Revision [14685]
This is an old revision of BookmarkManager made by BrianKoontz on 2006-06-24 02:48:00.
Bookmark Manager
An integrated bookmark manager in the spirit of de.lirio.us. Note: de.lirio.us will be shutting down within the month (end of July 2006), so if you plan on exporting your de.lirio.us bookmarks, better do it soon!Try it out! Beta version with latest code here.
Design ideas
- Allow both user-specific and site-wide bookmark access (other than those tagged as "private")
- Allow tagging of objects other than URIs (such as pages)
- Implement as both a handler and an action
Progress reports
- Beta test announcement: Well, after hacking around with Scuttle, I decided it was much too complex for what I had in mind. Nils suggested another project, Freetag, that seems to provide the basic functionality needed without all of the formatting/presentation overhead. I have a beta up and running here, and would appreciate your comments and suggestions! Keep in mind this is still quite rough around the edges, but I was aiming more towards proof-of-concept. I think something like this would be a cool addition (as a 100% modular plugin) to Wikka...
- Progress is going well. Add/edit/delete capabilities have been added. Two Perl scripts (see below) have been provided that allow you to export your bookmarks from de.lirio.us and import them into BookmarkManager. Beta currently running under Wikka 1.1.6.2-alpha. A page of 25 links (out of 200+) and about 100 tags renders in approximately 1.1 seconds.
- More enhancements and modifications: Numeric tags, link pagination, tag pagination, tag/link editing and deletion.
- More cool stuff: Support for bookmarklets (small Javascript bookmark that immediately saves the page you are viewing and returns to the page), tag links within link descriptors.
TODO
Indicates issues that have been addressed- This code is most likely not yet safe for a production environment! I've worked to secure all data passed in from GET/POST requests, as well as from Wikka itself in some cases. I'm hoping a few more folks have time to look over the code for any obvious security weaknesses.
- User tags should be displayed as raw tags.
- As a general consideration it would be nice to provide this functionality as a handler.
- it would be nice to have a link for the add-form near list yours.
- how about something like my tags / all tags? List all/list yours now provides this functionality
- what would be usefull: If I tag a link with the name of an existing wiki-page, this link could show up at the end of the page.
- Need to fix logic so "your" tags only display "your" links (also, identify tag cloud as "all" or "yours")
- Optional logic to display tags in a right-justified vertical list instead of a cloud
- Paging, user prefs
- Tag pages as well as links
- Please put the wikka_freetag class in a file like Wikka.freetag.class.php in the new \libs directory.
- $freetag_options -> why not use the params provided by wikka ($this->mysql_host, etc.)?
- Create bookmarklets such as these (borrowed from de.lirio.us): Implemented...see below for details
- Provide edit/delete functionality
- Search functionality
- Restricting spam. Some ideas: Option to allow only registered users to set bookmarks Implemented; using "captcha" images to preclude automated scripts
- It would be nice if tags in each bookmarks were links pointing to the list of bookmarks with the same tag.
Installation
- Install a copy of Freetag in 3rdparty/plugins Check for freetag library
include_once('Wikka.freetag.class.php');
$freetag_options = array(
'db_user' => 'root',
'db_pass' => ,
'db_host' => 'localhost',
'db_name' => 'freetag',
'PCONNECT' => true,
);
$freetag = new wikka_freetag($freetag_options);
function wikka_id_to_tagger_id ($wikka_id, $obj, $freetag_options) {
if(!isset($wikka_id)) {
return NULL;
}
$wikka_id = mysql_real_escape_string($wikka_id);
$res = $obj->LoadSingle("select tagger_id from ".$freetag_options['db_name'].".freetag_wikka_id_map where wikka_id = '".$wikka_id."';");
$tagger_id = $res['tagger_id'];
if(!$tagger_id) {
$obj->Query("insert ".$freetag_options['db_name'].".freetag_wikka_id_map set "."wikka_id = '".$wikka_id."';");
$res = $obj->LoadSingle("select last_insert_id();");
$tagger_id = $res['last_insert_id()'];
}
return $tagger_id;
}
function output_tag_cloud($freetag,$tag_page_url,$tagger_id=NULL,$header=NULL,$tag_offset=0,$tag_limit=100) {
Output tag cloud
$tag_count = $freetag->count_unique_tags($tagger_id);
print "<div class='floatr'>";
if($header) {
print $header." (".$tag_count."):<br/>";
}
print $freetag->get_tag_cloud_html_with_limits($tag_offset,$tag_limit,10,20,'px','cloud_tag',$tag_page_url."&tag_offset=".$tag_offset."&tag_limit=".$tag_limit."&tag=",$tagger_id);
Display pagination links
$tag_url = ;
$prev_offset = $tag_offset - $tag_limit;
$prev_url = ;
if($prev_offset < 0) {
$prev_offset = 0;
}
if($tag_offset > 0) {
$prev_url = "<a href=\.$tag_page_url."&tag_offset=".$prev_offset."&tag_limit=".$tag_limit."\"><<";
}
$next_offset = $tag_offset + $tag_limit;
$next_url = ;
if($next_offset < $tag_count - 1) {
$next_url = "<a href=\.$tag_page_url."&tag_offset=".$next_offset."&tag_limit=".$tag_limit.$tag_url."\">>>";
}
print " ";
}
/********************************************************************/
/* count_objects
*
* Returns a count of objects (bookmarks, links, etc.)
*
* NOTE: Set $wikka_id to NULL for all objects (except those marked
* private)
*/
function count_objects($wikka_id, $obj, $freetag_options) {
if(isset($wikka_id)) {
$wikka_sql = "AND wikka_id = '".mysql_real_escape_string($wikka_id)."'";
} else {
$wikka_sql = "AND private = 0";
}
$res = $obj->LoadSingle("select COUNT(*) as count from ".$freetag_options['db_name'].".freetag_bookmarks where 1 ".$wikka_sql.";");
$count = $res['count'];
return $count;
}
/********************************************************************/
/* count_tagged_objects
*
* Returns a count of tagged objects (bookmarks, links, etc.)
*
* NOTE: Set $wikka_id to NULL for all taggedobjects regardless of
* owner (except those marked private)
*/
function count_tagged_objects($wikka_id, $tag, $obj, $freetag_options, $freetag) {
$num_objs = count_objects($wikka_id, $obj, $freetag_options);
$tagger_id = wikka_id_to_tagger_id($wikka_id, $obj, $freetag_options);
$ids = $freetag->get_most_recent_objects($tagger_id, $tag, 0, $num_objs);
return count($ids);
}
/********************************************************************/
/* save_to_current_session
*
* Save various fields to the current session
*
* Input: Associative array of session tags->values
*
* Return: Name of session
*
*/
function save_to_current_session($values) {
foreach($values as $tag=>$value) {
$_SESSION[$tag] = $value;
}
return $_SESSION['name'];
}
/********************************************************************/
$wikka_id = $this->GetUserName();
$tagger_id = wikka_id_to_tagger_id($wikka_id, $this, $freetag_options);
$all_obj_count = count_objects(NULL, $this, $freetag_options);
$your_obj_count = count_objects($wikka_id, $this, $freetag_options);
echo "
"; print "
";
print $prev_url." ".$next_url;
print "
";
print "";
print "BookmarkTest
"; echo ".$this->href()."&action=list_all"."\">List all</a> (".$all_obj_count.") | ".
if(!isset($_REQUEST['action'])) {
Display all tags at start of session
$this->Redirect($this->href()."&action=list_all");
}
Add new entry to DB
if(isset($_REQUEST['action']) && ($_REQUEST['action']"add")) {
"add")) {
echo $_SESSION['when_done'];
$values = array();
Check for request from a bookmarklet...check to see if user
is logged in...if not, redirect to login page and come back
here when done
if(isset($_REQUEST['wikka_bookmarklet'])) {
$values['uri'] = $_REQUEST['uri'];
if(isset($_REQUEST['title'])) {
$values['title'] = $_REQUEST['title'];
}
$values['referrer'] = $_SERVER['HTTP_REFERER'];
$values['when_done'] = "add_link";
save_to_current_session($values);
session_write_close();
$_SESSION['go_back'] = $this->Href(null, $this->MiniHref()."&action=add");
session_write_close();
$this->Redirect($this->config['base_url']."UserSettings");
}
}
The next clause checks to see if we're returning from a
login request while trying to execute a bookmarklet
if(isset($_SESSION['when_done']) && ($_SESSION['when_done']
"add_link")) {
$values['uri'] = $_SESSION['uri'];
$values['title'] = $_SESSION['title'];
$_SESSION['when_done'] = "return";
session_write_close();
}
if(trim($_REQUEST['tags']) != ) {
// Private bookmark?
$private = 0;
if(strpos(trim($_REQUEST['tags']), "@private") !== false)
$private = 1;
// Converts numeric tag "123" to "123_" to facilitate
// alphanumeric sorting (otherwise, PHP converts string to
// true integer).
$tags = preg_split('/\s+/', $_REQUEST['tags'], -1, PREG_SPLIT_NO_EMPTY);
$tags = preg_replace('/^([0-9]+)$/', "$1_", $tags);
$tags = implode(" ", $tags);
$this->Query("insert ".$freetag_options['db_name'].".freetag_bookmarks set ".
"title = '".mysql_real_escape_string($_REQUEST['title'])."', ".
"uri = '".mysql_real_escape_string($this->cleanUrl($_REQUEST['uri']))."', ".
"wikka_id = '".mysql_real_escape_string($wikka_id)."', ".
"private = '".$private."', ".
"description = '".mysql_real_escape_string($_REQUEST['desc'])."';");
$last_id = $this->LoadSingle("select last_insert_id();");
$freetag->tag_object($tagger_id, $last_id['last_insert_id()'], $tags);
// Check to see if it's time to return to the page from which
// the bookmarklet was called
if(isset($_SESSION['when_done']) && ($_SESSION['when_done']=="return")) {
if(isset($_SESSION['referrer'])) {
$referrer = $_SESSION['referrer'];
unset($_SESSION['go_back']);
unset($_SESSION['uri']);
unset($_SESSION['title']);
unset($_SESSION['referrer']);
unset($_SESSION['when_done']);
$this->Redirect($referrer);
}
}
// Otherwise, go back to tag/link list view
$this->Redirect($this->href()."&action=list_yours");
} else {
// Display add form
print($this->FormOpen());
?>
FormClose());
}
}
// Edit entry
if(isset($_REQUEST['action']) && ($_REQUEST['action']=="edit") && (isset($_REQUEST['object_id']))) {
$object_id = $_REQUEST['object_id'];
$obj = $this->LoadSingle("select bookmark_id,title,uri,description,wikka_id from ".$freetag_options['db_name'].".freetag_bookmarks where bookmark_id = ".$object_id.";");
// Is the logged-in user the owner?
if($wikka_id != $obj['wikka_id']) {
$this->Redirect($this->href()."&action=list_all");
}
if(isset($_REQUEST['modify']) && trim($_REQUEST['tags']) != ) {
Title: | |
URI: | |
Description: | |
Format("Use blank space between tags, include \"@private\" for private bookmark"); ?> | |
Tags: | |
Delete all tags, then re-tag
$freetag->delete_all_object_tags_for_user($tagger_id,$object_id);
Private bookmark?
$private = 0;
if(strpos(trim($_REQUEST['tags']), "@private") ! false)
false)
$private = 1;
$this->Query("update ".$freetag_options['db_name'].".freetag_bookmarks set ".
"title = '".mysql_real_escape_string($_REQUEST['title'])."', ".
"uri = '".mysql_real_escape_string($this->cleanUrl($_REQUEST['uri']))."', ".
"wikka_id = '".mysql_real_escape_string($wikka_id)."', ".
"private = '".$private."', ".
"description = '".mysql_real_escape_string($_REQUEST['desc'])."' ".
"where bookmark_id = ".mysql_real_escape_string($object_id)." ".
"limit 1;");
$freetag->tag_object($tagger_id, $obj['bookmark_id'], $_REQUEST['tags']);
$this->Redirect($this->href()."&action=list_yours");
}
Display add form
?>
<input type="hidden" name="action" value="edit" />
<input type="hidden" name="modify" value="yes" />
<input type="hidden" name="object_id" value="<?php print $object_id ?>" />
<table>
<tr>
<td align="right">Title:</td>
<td><input name="title" size="40" value="<?php print $obj['title']; ?>"/></td>
</tr>
<tr>
<td align="right">URI:
<td><input name="uri" size="40" value="<?php print $obj['uri']; ?>"/></td>
</tr>
<tr>
<td align="right">Description:</td>
<td><input name="desc" size="40" value="<?php print $obj['description']; ?>"/></td>
</tr>
<tr>
<td align="right"></td>
<td><?php echo $this->Format("Use blank space between tags, include \"@private\" for private bookmark"); ?></td>
</tr>
<tr>
<td align="right">Tags:</td>
<?php
$tags = $freetag->get_tags_on_object($object_id);
$taglist = ;
foreach($tags as $idx=>$res) {
$taglist .= trim($res['raw_tag'])." ";
}
?>
FormClose());
}
// Delete entry
if(isset($_REQUEST['action']) && $_REQUEST['action']=="delete") {
$object_id = $_REQUEST['object_id'];
$obj = $this->LoadSingle("select bookmark_id,wikka_id from ".$freetag_options['db_name'].".freetag_bookmarks where bookmark_id = ".mysql_real_escape_string($object_id).";");
// Is the logged-in user the owner?
if($wikka_id != $obj['wikka_id']) {
$this->Redirect($this->href()."&action=list_all");
}
// Delete all tags first...
$freetag->delete_all_object_tags_for_user($tagger_id,$object_id);
// ...then delete object
$this->Query("delete from ".$freetag_options['db_name'].".freetag_bookmarks where bookmark_id = ".mysql_real_escape_string($object_id)." limit 1;");
$this->Redirect($this->href()."&action=list_yours");
}
// List all bookmarks (ordered by most recent)
if(isset($_REQUEST['action']) && ($_REQUEST['action']=="list_all")) {
$offset = 0;
if(isset($_REQUEST['offset'])) {
$offset = $_REQUEST['offset'];
}
$limit = 25;
if(isset($_REQUEST['limit'])) {
$limit = $_REQUEST['limit'];
}
$tag_offset = 0;
if(isset($_REQUEST['tag_offset'])) {
$tag_offset = $_REQUEST['tag_offset'];
}
$tag_limit = 100;
if(isset($_REQUEST['tag_limit'])) {
$tag_limit = $_REQUEST['tag_limit'];
}
// Output tag cloud
$url_opts = $this->href()."&action=list_all";
output_tag_cloud($freetag,$url_opts,NULL,"All tags",$tag_offset,$tag_limit);
$ids = ;
$tag = ;
if(isset($_REQUEST['tag']) && $_REQUEST['tag'] != ) {
$ids = $freetag->get_most_recent_objects(NULL,$_REQUEST['tag'],$offset,$limit);
$tag = $_REQUEST['tag'];
} else {
$ids = $freetag->get_most_recent_objects(NULL,NULL,$offset,$limit);
}
foreach($ids as $key=>$val) {
$tags = $freetag->get_tags_on_object($val['object_id']);
if(!isset($obj)) {
continue;
}
print "<h3><a href=\.$obj['uri']."\">".$obj['title']."
"; print "
"; print "
$link = $url_opts."&tag_offset=".$tag_offset."&tag_limit=".$tag_limit;
foreach($tags as $idx=>$res) {
$tag = trim($res['tag']);
$taglist .= "<a href=\.$link."&tag=".$tag."\">".$tag." ";
}
print $taglist."by ".$obj['wikka_id']." (created: ".$val['tagged_on'].")";
print "
"; } // Display pagination links $obj_count = 0; $tag_url = ;
"; } // Display pagination links $obj_count = 0; $tag_url = ;
if($tag != ) {
$obj_count = count_tagged_objects(NULL, $tag, $this, $freetag_options, $freetag);
$tag_url = "&tag=".$tag;
} else {
$obj_count = count_objects(NULL, $this, $freetag_options);
}
$prev_offset = $offset - $limit;
$prev_url = ;
if($prev_offset < 0) {
$prev_offset = 0;
}
if($offset > 0) {
$prev_url = "<a href=\.$this->href()."&action=list_all&offset=".$prev_offset."&limit=".$limit.$tag_url."\"><<";
}
$next_offset = $offset + $limit;
$next_url = ;
if($next_offset < $obj_count - 1) {
$next_url = "<a href=\.$this->href()."&action=list_all&offset=".$next_offset."&limit=".$limit.$tag_url."\">>>";
}
print "
"; print "
";
print $prev_url." ".$next_url;
print "
";
}
// List user bookmarks (ordered by most recent)
if(isset($_REQUEST['action']) && ($_REQUEST['action']=="list_yours")) {
$offset = 0;
if(isset($_REQUEST['offset'])) {
$offset = $_REQUEST['offset'];
}
$limit = 25;
if(isset($_REQUEST['limit'])) {
$limit = $_REQUEST['limit'];
}
$tag_offset = 0;
if(isset($_REQUEST['tag_offset'])) {
$tag_offset = $_REQUEST['tag_offset'];
}
$tag_limit = 100;
if(isset($_REQUEST['tag_limit'])) {
$tag_limit = $_REQUEST['tag_limit'];
}
// Output tag cloud
$url_opts = $this->href()."&action=list_yours";
output_tag_cloud($freetag,$url_opts,$tagger_id,"Your tags",$tag_offset,$tag_limit);
$ids = ;
$tag = ;
if(isset($_REQUEST['tag']) && $_REQUEST['tag'] != ) {
$ids = $freetag->get_most_recent_objects($tagger_id, $_REQUEST['tag'], $offset, $limit);
$tag = $_REQUEST['tag'];
} else {
$ids = $freetag->get_most_recent_objects($tagger_id, NULL, $offset, $limit);
}
foreach($ids as $key=>$val) {
$tags = $freetag->get_tags_on_object($val['object_id']);
print "|";
print "<a href=\.$this->href()."&action=delete&object_id=".$val['object_id']."\">delete";
print "
"; $taglist = ;
"; $taglist = ;
$link = $url_opts."&tag_offset=".$tag_offset."&tag_limit=".$tag_limit;
foreach($tags as $idx=>$res) {
$tag = trim($res['tag']);
$rawtag = trim($res['raw_tag']);
$taglist .= "<a href=\.$link."&tag=".$tag."\">".$rawtag." ";
}
print $taglist."by ".$obj['wikka_id']." (created: ".$val['tagged_on'].")";
print "
"; } // Display pagination links $obj_count = 0; $tag_url = ;
"; } // Display pagination links $obj_count = 0; $tag_url = ;
if($tag != ) {
$obj_count = count_tagged_objects($wikka_id, $tag, $this, $freetag_options, $freetag);
$tag_url = "&tag=".$tag;
} else {
$obj_count = count_objects($wikka_id, $this, $freetag_options);
}
$prev_offset = $offset - $limit;
$prev_url = ;
if($prev_offset < 0) {
$prev_offset = 0;
}
if($offset > 0) {
$prev_url = "<a href=\.$this->href()."&action=list_yours&offset=".$prev_offset."&limit=".$limit.$tag_url."\"><<";
}
$next_offset = $offset + $limit;
$next_url = ;
if($next_offset < $obj_count - 1) {
$next_url = "<a href=\.$this->href()."&action=list_yours&offset=".$next_offset."&limit=".$limit.$tag_url."\">>>";
}
print "
"; print "
";
print $prev_url." ".$next_url;
print "
";
}
?>
%%
- Save the following file as ##actions/Wikka.freetag.class.php## (needs to be moved to libs/ eventually):
**Wikka.freetag.class.php**
%%(php)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public Licence for more details:
*
* http://www.gnu.org/copyleft/gpl.html
*
*********************************************************************/
// Check for freetag library
$freetag_lib = '3rdparty/plugins/freetag/freetag.class.php';
if(!is_file($freetag_lib)) {
print("".$this->Format("Can't find $freetag_lib!")."
\n"); die(); } include_once($freetag_lib); /********************************************************************/ /* Freetag subclass (defines additional support methods) */ /********************************************************************/ class wikka_freetag extends freetag { function wikka_freetag($freetag_options) { parent::freetag($freetag_options); $this->_normalized_valid_chars = '@_a-zA-Z0-9'; } /******************************************************************* * get_tag_cloud_html_with_limits * * Extension to get_tag_cloud_html() that permits specifying * an offset and limit (useful for presenting more tags than * can be displayed at one time). * * See get_tag_cloud_html() comments for description of this * function. * * @param int Specify starting record (default: 0) * @param int The maximum number of tags to return. (default: 100) * @param int The minimum font size in the cloud. (default: 10) * @param int The maximum number of tags to return. (default: 20) * @param string The "units" for the font size (i.e. 'px', 'pt', * 'em') (default: px) * @param string The class to use for all spans in the cloud. * (default: cloud_tag) * @param string The tag page URL (default: /tag/) * * @return string Returns an HTML snippet that can be used * directly as a tag cloud. */ function get_tag_cloud_html_with_limits($offset = 0, $limit = 100, $min_font_size = 10, $max_font_size = 20, $font_units = 'px', $span_class = 'cloud_tag', $tag_page_url = '/tag/', $tagger_id = NULL) { $tag_list = $this->get_tag_cloud_tags_with_limits($offset, $limit, $tagger_id); // Get the maximum qty of tagged objects in the set $max_qty = max(array_values($tag_list)); // Get the min qty of tagged objects in the set $min_qty = min(array_values($tag_list)); // For ever additional tagged object from min to max, we add // $step to the font size. $spread = $max_qty - $min_qty; if (0 == $spread) { // Divide by zero $spread = 1; } $step = ($max_font_size - $min_font_size)/($spread); // Since the original tag_list is alphabetically ordered, // we can now create the tag cloud by just putting a span // on each element, multiplying the diff between min and qty // by $step. $cloud_html = ''; $cloud_spans = array(); foreach ($tag_list as $tag => $qty) { //if(strpos($tag, "private") !== false) continue; $size = $min_font_size + ($qty - $min_qty) * $step; $cloud_span[] = '' . htmlspecialchars(stripslashes($tag)) . ''; } $cloud_html = join("\n ", $cloud_span); return $cloud_html; } /* * get_tag_cloud_tags_with_limits * * Extension to get_tag_cloud_tags() that permits specifying * an offset and limit (useful for presenting more tags than * can be displayed at one time). Also, tags are returned * in true alphanumeric sequence across the entire record set, * rather than across the most popular tags. * * See get_tag_cloud_tags() comments for description of this * function. * @param int Specify starting record (default: 0) * @param int The maximum number of tags to return (default: 100) * @param int Tag owner (default: NULL) * * @return array Returns an array where the keys are normalized * tags, and the * values are numeric quantity of objects tagged with that tag. */ function get_tag_cloud_tags_with_limits($offset = 0, $limit = 100, $tagger_id = NULL) { $db = $this->db; if(isset($tagger_id) && ($tagger_id > 0)) { $tagger_sql = "AND tagger_id = $tagger_id"; } else { $tagger_sql =
;\n"); die(); } include_once($freetag_lib); /********************************************************************/ /* Freetag subclass (defines additional support methods) */ /********************************************************************/ class wikka_freetag extends freetag { function wikka_freetag($freetag_options) { parent::freetag($freetag_options); $this->_normalized_valid_chars = '@_a-zA-Z0-9'; } /******************************************************************* * get_tag_cloud_html_with_limits * * Extension to get_tag_cloud_html() that permits specifying * an offset and limit (useful for presenting more tags than * can be displayed at one time). * * See get_tag_cloud_html() comments for description of this * function. * * @param int Specify starting record (default: 0) * @param int The maximum number of tags to return. (default: 100) * @param int The minimum font size in the cloud. (default: 10) * @param int The maximum number of tags to return. (default: 20) * @param string The "units" for the font size (i.e. 'px', 'pt', * 'em') (default: px) * @param string The class to use for all spans in the cloud. * (default: cloud_tag) * @param string The tag page URL (default: /tag/) * * @return string Returns an HTML snippet that can be used * directly as a tag cloud. */ function get_tag_cloud_html_with_limits($offset = 0, $limit = 100, $min_font_size = 10, $max_font_size = 20, $font_units = 'px', $span_class = 'cloud_tag', $tag_page_url = '/tag/', $tagger_id = NULL) { $tag_list = $this->get_tag_cloud_tags_with_limits($offset, $limit, $tagger_id); // Get the maximum qty of tagged objects in the set $max_qty = max(array_values($tag_list)); // Get the min qty of tagged objects in the set $min_qty = min(array_values($tag_list)); // For ever additional tagged object from min to max, we add // $step to the font size. $spread = $max_qty - $min_qty; if (0 == $spread) { // Divide by zero $spread = 1; } $step = ($max_font_size - $min_font_size)/($spread); // Since the original tag_list is alphabetically ordered, // we can now create the tag cloud by just putting a span // on each element, multiplying the diff between min and qty // by $step. $cloud_html = ''; $cloud_spans = array(); foreach ($tag_list as $tag => $qty) { //if(strpos($tag, "private") !== false) continue; $size = $min_font_size + ($qty - $min_qty) * $step; $cloud_span[] = '' . htmlspecialchars(stripslashes($tag)) . ''; } $cloud_html = join("\n ", $cloud_span); return $cloud_html; } /* * get_tag_cloud_tags_with_limits * * Extension to get_tag_cloud_tags() that permits specifying * an offset and limit (useful for presenting more tags than * can be displayed at one time). Also, tags are returned * in true alphanumeric sequence across the entire record set, * rather than across the most popular tags. * * See get_tag_cloud_tags() comments for description of this * function. * @param int Specify starting record (default: 0) * @param int The maximum number of tags to return (default: 100) * @param int Tag owner (default: NULL) * * @return array Returns an array where the keys are normalized * tags, and the * values are numeric quantity of objects tagged with that tag. */ function get_tag_cloud_tags_with_limits($offset = 0, $limit = 100, $tagger_id = NULL) { $db = $this->db; if(isset($tagger_id) && ($tagger_id > 0)) { $tagger_sql = "AND tagger_id = $tagger_id"; } else { $tagger_sql =
}
$prefix = $this->_table_prefix;
$sql = "SELECT tag, COUNT(object_id) AS quantity
FROM ${prefix}freetags INNER JOIN
${prefix}freetagged_objects
ON (${prefix}freetags.id = tag_id)
WHERE 1
$tagger_sql
GROUP BY tag
ORDER BY tag ASC
LIMIT $offset, $limit
";
$rs = $db->Execute($sql) or die("Syntax Error: $sql");
while(!$rs->EOF) {
$retarr[$rs->fields['tag']] = $rs->fields['quantity'];
}
ksort($retarr);
return $retarr;
}
function count_unique_tags($tagger_id = NULL) {
$db = $this->db;
if(isset($tagger_id) && ($tagger_id > 0)) {
$tagger_sql = "AND tagger_id = $tagger_id";
} else {
$tagger_sql = ;
}
$prefix = $this->_table_prefix;
$sql = "SELECT DISTINCT tag_id, COUNT(*) as count
FROM ${prefix}freetags INNER JOIN ${prefix}freetagged_objects ON (id = tag_id)
$tagger_sql
GROUP BY NULL
";
$rs = $db->Execute($sql) or die("Syntax Error: $sql");
if(!$rs->EOF) {
return $rs->fields['count'];
}
return false;
}
}
/********************************************************************/
%%
- Adjust the DB connection parameters for your own installation
- Add the Unknown action ""bookmarks"""" action code to a new page
BookmarkManager now supports "bookmarklets," which is a small snippet of Javascript saved as a browser bookmark that allows you to bookmark a webpage "on the fly." The following patch must be applied to actions/usersettings.php if you want to restrict bookmarklets to registered users (recommended):
===================================================================
RCS file: RCS/usersettings.php,v
retrieving revision 1.1
diff -u -r1.1 usersettings.php
--- usersettings.php 2006/06/18 06:03:03 1.1
+++ usersettings.php 2006/06/24 06:40:13
@@ -1,5 +1,7 @@
<?php
/**
+ * $Id: usersettings.php,v 1.5 2006/06/24 06:40:07 brian Exp brian $
+ *
* Display a form to register, login and change user settings.
*
* @package Actions
@@ -334,6 +336,13 @@
// is user trying to log in or register?
if (isset($_POST['action']) && ($_POST['action'] == 'login'))
{
+ // Login request was redirected from elsewhere...let's make
+ // sure to go back if requested by setting $referrer
+ $referrer = null;
+ if(isset($_SESSION['go_back'])) {
+ $referrer = $_SESSION['go_back'];
+ }
+
// if user name already exists, check password
if (isset($_POST['name']) && $existingUser = $this->LoadUser($_POST['name']))
{
@@ -349,7 +358,11 @@
break;
default:
$this->SetUser($existingUser);
- $this->Redirect($this->href());
+ if($referrer == null)
+ $this->Redirect($this->href());
+ else {
+ $this->Redirect($referrer);
+ }
}
}
else // otherwise, proceed to registration
@@ -417,7 +430,11 @@
// log in
$this->SetUser($this->LoadUser($name));
- $this->Redirect($this->href('', '', 'registered=true'));
+ if($referrer == null)
+ $this->Redirect($this->href('', '', 'registered=true'));
+ else {
+ $this->Redirect($referrer);
+ }
}
}
}
@@ -542,4 +559,4 @@
<?php
print($this->FormClose());
}
Save the following as a bookmark in your browser:
javascript:location.href='http://your.site.com/wiki/wikka.php?wakka=BookmarkPage&action=add&uri='+escape(location.href)+'&title='+encodeURIComponent(document.title)+'&wikka_bookmarklet=1'
(Don't forget to change "your.site.com" as appropriate for your installation!)
TODO: Implement as a popup:
post bookmarklet (with popup): javascript:void(open('http://de.lirio.us/rubric/post?uri='+escape(location.href)+'&title='+encodeURIComponent(document.title)+'&when_done=close','Rubric','toolbar=no,width=700,height=325,scrollbars'));
Other stuff=================================================================== RCS file: RCS/usersettings.php,v retrieving revision 1.1 diff -u -r1.1 usersettings.php --- usersettings.php 2006/06/18 06:03:03 1.1 +++ usersettings.php 2006/06/24 06:40:13 @@ -1,5 +1,7 @@ <?php /** + * $Id: usersettings.php,v 1.5 2006/06/24 06:40:07 brian Exp brian $ + * * Display a form to register, login and change user settings. * * @package Actions @@ -334,6 +336,13 @@ // is user trying to log in or register? if (isset($_POST['action']) && ($_POST['action'] == 'login')) { + // Login request was redirected from elsewhere...let's make + // sure to go back if requested by setting $referrer + $referrer = null; + if(isset($_SESSION['go_back'])) { + $referrer = $_SESSION['go_back']; + } + // if user name already exists, check password if (isset($_POST['name']) && $existingUser = $this->LoadUser($_POST['name'])) { @@ -349,7 +358,11 @@ break; default: $this->SetUser($existingUser); - $this->Redirect($this->href()); + if($referrer == null) + $this->Redirect($this->href()); + else { + $this->Redirect($referrer); + } } } else // otherwise, proceed to registration @@ -417,7 +430,11 @@ // log in $this->SetUser($this->LoadUser($name)); - $this->Redirect($this->href('', '', 'registered=true')); + if($referrer == null) + $this->Redirect($this->href('', '', 'registered=true')); + else { + $this->Redirect($referrer); + } } } } @@ -542,4 +559,4 @@ <?php print($this->FormClose()); }
javascript:location.href='http://your.site.com/wiki/wikka.php?wakka=BookmarkPage&action=add&uri='+escape(location.href)+'&title='+encodeURIComponent(document.title)+'&wikka_bookmarklet=1' (Don't forget to change "your.site.com" as appropriate for your installation!)
post bookmarklet (with popup): javascript:void(open('http://de.lirio.us/rubric/post?uri='+escape(location.href)+'&title='+encodeURIComponent(document.title)+'&when_done=close','Rubric','toolbar=no,width=700,height=325,scrollbars'));
- The two Perl scripts that follow can be used to import bookmarks from de.lirio.us. Use your browser to save a page of bookmarks as an HTML file (you might have to save multiple pages; that's OK, the script can handle it). Export the HTML data into text format:
parseDelirious.pl file1.html file2.html file3.html > myLinks.txt
Change the $base_url, $wikiname, and $password global vars in importDelirious.pl, then run against the file created in the previous step:
importDelirious.pl myLinks.txt
parseDelirious.pl
#! /usr/bin/perl
#
# $Id: parseDelirious.pl,v 1.2 2006/05/30 03:27:21 brian Exp brian $
#
# parseDelirious.pl - Parses a de.lirio.us screen dump (as saved by
# Firefox)
#
#####################################################################
require HTML::TreeBuilder;
foreach my $filename(@ARGV) {
my $tree = HTML::TreeBuilder->new;
$tree->parse_file($filename);
$tree->elementify();
@nodes = $tree->look_down("class","xfolkentry");
foreach $node(@nodes) {
$_ = $node->look_down("class","uri");
$link = $_->extract_links();
$title = $link->[0]->[1]->as_text();
print "Title: $title\n";
print "URI: $link->[0]->[0]\n";
# Get description, if any
$_=$node->look_down("class","extended");
print "Desc: ";
if($_) {
$desc = $_->as_text();
print "$desc";
}
print "\n";
# A de.lirio.us export quirk prevents some tags from
# displaying; default these to "@private" for later review
@_ = $node->look_down("class","tag");
print "Tags: ";
if($#_ < 0) {
print "\@private";
}
foreach $tagnode(@_) {
$link = $tagnode->extract_links();
$tag = $link->[0]->[1]->as_text();
print "$tag ";
}
print "\n\n\n";
}
$tree = $tree->delete;
}
importDelirious.pl
#! /usr/bin/perl
#
# $Id: importDelirious.pl,v 1.3 2006/05/31 04:43:19 brian Exp brian $
#
# importDelirious.pl -- Imports file created by parseDelirious.pl
#
# Usage: importDelirious.pl exportFile
#
#####################################################################
require LWP::UserAgent;
require HTTP::Cookies;
###Global###
$base_url = "http://some.url.com/wiki/";
$bookmark_page = "Bookmarks";
$wikiname = "YourName";
$password = "yourpassword";
$ua = LWP::UserAgent->new;
$cookie_jar = HTTP::Cookies->new(file => "lwpcookies.txt",
autosave => 1);
$ua->cookie_jar($cookie_jar);
# Login
$login_url = $base_url."wikka.php?wakka=UserSettings";
my $req = HTTP::Request->new(POST=>"$login_url");
$req->content_type('application/x-www-form-urlencoded');
$req->content("name=$wikiname&password=$password&action=login&wakka=UserSettings");
my $res = $ua->request($req);
$cookie_jar->extract_cookies($res);
# Import
open(IN, "<$ARGV[0]") || die "Can't open $ARGV[0] for reading!";
# Set autoflush so progress is displayed
my $oldfh = select(STDOUT); $| = 1; select($oldfh);
print "Importing...";
while(<IN>) {
print ".";
next until /Title: /;
chomp;
$title = (split(": ",$_))[1];
$_ = <IN>;
chomp;
$uri = (split(": ",$_))[1];
$_ = <IN>;
chomp;
$desc = (split(": ",$_))[1];
$_ = <IN>;
chomp;
$tags = (split(": ",$_))[1];
$add_url = $base_url."wikka.php?wakka=".$bookmark_page."&action=add";
$req = HTTP::Request->new(POST=>"$add_url");
$req->content_type('application/x-www-form-urlencoded');
$req->content("title=$title&uri=$uri&desc=$desc&tags=$tags");
$ua->request($req);
}
print "done!\n";
CategoryparseDelirious.pl file1.html file2.html file3.html > myLinks.txt
importDelirious.pl myLinks.txt
#
# $Id: parseDelirious.pl,v 1.2 2006/05/30 03:27:21 brian Exp brian $
#
# parseDelirious.pl - Parses a de.lirio.us screen dump (as saved by
# Firefox)
#
#####################################################################
require HTML::TreeBuilder;
foreach my $filename(@ARGV) {
my $tree = HTML::TreeBuilder->new;
$tree->parse_file($filename);
$tree->elementify();
@nodes = $tree->look_down("class","xfolkentry");
foreach $node(@nodes) {
$_ = $node->look_down("class","uri");
$link = $_->extract_links();
$title = $link->[0]->[1]->as_text();
print "Title: $title\n";
print "URI: $link->[0]->[0]\n";
# Get description, if any
$_=$node->look_down("class","extended");
print "Desc: ";
if($_) {
$desc = $_->as_text();
print "$desc";
}
print "\n";
# A de.lirio.us export quirk prevents some tags from
# displaying; default these to "@private" for later review
@_ = $node->look_down("class","tag");
print "Tags: ";
if($#_ < 0) {
print "\@private";
}
foreach $tagnode(@_) {
$link = $tagnode->extract_links();
$tag = $link->[0]->[1]->as_text();
print "$tag ";
}
print "\n\n\n";
}
$tree = $tree->delete;
}
#
# $Id: importDelirious.pl,v 1.3 2006/05/31 04:43:19 brian Exp brian $
#
# importDelirious.pl -- Imports file created by parseDelirious.pl
#
# Usage: importDelirious.pl exportFile
#
#####################################################################
require LWP::UserAgent;
require HTTP::Cookies;
###Global###
$base_url = "http://some.url.com/wiki/";
$bookmark_page = "Bookmarks";
$wikiname = "YourName";
$password = "yourpassword";
$ua = LWP::UserAgent->new;
$cookie_jar = HTTP::Cookies->new(file => "lwpcookies.txt",
autosave => 1);
$ua->cookie_jar($cookie_jar);
# Login
$login_url = $base_url."wikka.php?wakka=UserSettings";
my $req = HTTP::Request->new(POST=>"$login_url");
$req->content_type('application/x-www-form-urlencoded');
$req->content("name=$wikiname&password=$password&action=login&wakka=UserSettings");
my $res = $ua->request($req);
$cookie_jar->extract_cookies($res);
# Import
open(IN, "<$ARGV[0]") || die "Can't open $ARGV[0] for reading!";
# Set autoflush so progress is displayed
my $oldfh = select(STDOUT); $| = 1; select($oldfh);
print "Importing...";
while(<IN>) {
print ".";
next until /Title: /;
chomp;
$title = (split(": ",$_))[1];
$_ = <IN>;
chomp;
$uri = (split(": ",$_))[1];
$_ = <IN>;
chomp;
$desc = (split(": ",$_))[1];
$_ = <IN>;
chomp;
$tags = (split(": ",$_))[1];
$add_url = $base_url."wikka.php?wakka=".$bookmark_page."&action=add";
$req = HTTP::Request->new(POST=>"$add_url");
$req->content_type('application/x-www-form-urlencoded');
$req->content("title=$title&uri=$uri&desc=$desc&tags=$tags");
$ua->request($req);
}
print "done!\n";
"; $taglist =