]> git.mjollnir.org Git - s9y.git/commitdiff
added freetag plugin asgn-1.0
authorPenny Leach <mjollnir@titania.local>
Fri, 4 Aug 2006 21:22:58 +0000 (09:22 +1200)
committerPenny Leach <mjollnir@titania.local>
Fri, 4 Aug 2006 21:22:58 +0000 (09:22 +1200)
plugins/serendipity_event_freetag/lang_en.inc.php [new file with mode: 0644]
plugins/serendipity_event_freetag/serendipity_event_freetag.php [new file with mode: 0644]
plugins/serendipity_event_freetag/serendipity_plugin_freetag.php [new file with mode: 0644]

diff --git a/plugins/serendipity_event_freetag/lang_en.inc.php b/plugins/serendipity_event_freetag/lang_en.inc.php
new file mode 100644 (file)
index 0000000..3b1ac2e
--- /dev/null
@@ -0,0 +1,59 @@
+<?php # $Id: lang_en.inc.php,v 1.8 2006/04/28 08:52:51 garvinhicking Exp $
+
+/**
+ *  @version $Revision: 1.8 $
+ *  @author Translator Name <yourmail@example.com>
+ *  EN-Revision: Revision of lang_en.inc.php
+ */
+
+//
+//  serendipity_event_freetag.php
+//
+@define('PLUGIN_EVENT_FREETAG_TITLE', 'Tagging of entries');
+@define('PLUGIN_EVENT_FREETAG_DESC', 'Allows freestyle tagging of entries');
+@define('PLUGIN_EVENT_FREETAG_ENTERDESC', 'Enter any tags that apply. Seperate multiple tags with a comma (,)');
+@define('PLUGIN_EVENT_FREETAG_LIST', 'Defined tags for this entry: %s');
+@define('PLUGIN_EVENT_FREETAG_USING', 'Entries tagged as %s');
+@define('PLUGIN_EVENT_FREETAG_SUBTAG', 'Tags related to tag %s');
+@define('PLUGIN_EVENT_FREETAG_NO_RELATED','No related tags.');
+@define('PLUGIN_EVENT_FREETAG_ALLTAGS', 'All defined Tags');
+@define('PLUGIN_EVENT_FREETAG_MANAGETAGS', 'Manage Tags');
+@define('PLUGIN_EVENT_FREETAG_MANAGE_ALL', 'Manage All Tags');
+@define('PLUGIN_EVENT_FREETAG_MANAGE_LEAF', 'Manage \'Leaf\' Tags');
+@define('PLUGIN_EVENT_FREETAG_MANAGE_UNTAGGED', 'List Untagged Entries');
+@define('PLUGIN_EVENT_FREETAG_MANAGE_LEAFTAGGED', 'List \'Leaf\' Tagged Entries');
+@define('PLUGIN_EVENT_FREETAG_MANAGE_UNTAGGED_NONE', 'No Untagged entries!');
+@define('PLUGIN_EVENT_FREETAG_MANAGE_LIST_TAG', 'Tag');
+@define('PLUGIN_EVENT_FREETAG_MANAGE_LIST_WEIGHT', 'Weight');
+@define('PLUGIN_EVENT_FREETAG_MANAGE_LIST_ACTIONS', 'Action');
+@define('PLUGIN_EVENT_FREETAG_MANAGE_ACTION_RENAME', 'Rename');
+@define('PLUGIN_EVENT_FREETAG_MANAGE_ACTION_SPLIT', 'Split');
+@define('PLUGIN_EVENT_FREETAG_MANAGE_ACTION_DELETE', 'Delete');
+@define('PLUGIN_EVENT_FREETAG_MANAGE_CONFIRM_DELETE', 'Do you really want to delete the %s tag?');
+@define('PLUGIN_EVENT_FREETAG_MANAGE_INFO_SPLIT', 'use a comma to seperate tags:');
+@define('PLUGIN_EVENT_FREETAG_SHOW_TAGCLOUD', 'Show tag cloud to related tags?');
+
+//
+//  serendipity_plugin_freetag.php
+//
+@define('PLUGIN_FREETAG_NAME', 'Show tagged entries');
+@define('PLUGIN_FREETAG_BLAHBLAH', 'Shows a list of existing tags for entries');
+@define('PLUGIN_FREETAG_NEWLINE', 'Linefeed after each Tag?');
+@define('PLUGIN_FREETAG_XML', 'Show XML-icons?');
+@define('PLUGIN_FREETAG_SCALE','Scale tag font size depending on popularity (like Technorati, flickr)?');
+@define('PLUGIN_FREETAG_UPGRADE1_2','Upgrading %d tags for entry number: %d');
+@define('PLUGIN_FREETAG_MAX_TAGS', 'How many tags should be shown?');
+@define('PLUGIN_FREETAG_TRESHOLD_TAG_COUNT', 'How many occurences must a tag have in order to be shown?');
+
+@define('PLUGIN_EVENT_FREETAG_TAGCLOUD_MIN', 'Minimum font size % of tag in tag cloud');
+@define('PLUGIN_EVENT_FREETAG_TAGCLOUD_MAX', 'Maximum font size % of tag in tag cloud');
+
+@define('PLUGIN_FREETAG_META_KEYWORDS', 'Number of meta keywords to embed in HTML source (0: disabled)');
+
+@define('PLUGIN_EVENT_FREETAG_RELATED_ENTRIES', 'Related entries by tags:');
+@define('PLUGIN_EVENT_FREETAG_SHOW_RELATED','Display related entries by tags?');
+@define('PLUGIN_EVENT_FREETAG_SHOW_RELATED_COUNT','How many related entries should be dislayed?');
+@define('PLUGIN_EVENT_FREETAG_EMBED_FOOTER', 'Show tags in footer?');
+@define('PLUGIN_EVENT_FREETAG_EMBED_FOOTER_DESC', 'If enabled, the tags will be shown in the footer of an entry. If disabled, the tags will be put inside the body/extended part of your entries.');
+@define('PLUGIN_EVENT_FREETAG_LOWERCASE_TAGS', 'Lowercase tags');
+
diff --git a/plugins/serendipity_event_freetag/serendipity_event_freetag.php b/plugins/serendipity_event_freetag/serendipity_event_freetag.php
new file mode 100644 (file)
index 0000000..7fe088e
--- /dev/null
@@ -0,0 +1,1422 @@
+<?php #$Id: serendipity_event_freetag.php,v 1.59 2006/04/27 08:48:54 garvinhicking Exp $
+/*
+ * ULTRA HIGH PRIORITY
+ * - get some kind of data-sharing protocol in action.  It is very difficult
+ *   tracing out what the hell is going on with this thing.
+ * - Refactor out the entryproperties depenancy, and use our own space
+ * - Refactor the external plugin event hook.  Its kind of cruddy.
+ *
+ * TODO:
+ * - Add tag intersections with + on the URI
+ * - Integrate into the del.icio.us plugin
+ * - Integrate into the flickr plugin
+ * - Refactor code out of the main event dispatch and into its own methods
+ * - Remove comma-delimiting and use the 'standard' space delimiting instead
+ * - - convert tags with spaces to no-space tags
+ * - - convert database structure to a truely 3rd normal form
+ * - Tag administration
+ * - - Describe Tag
+ * - - Super-Tag (tags 'php', 'java' and 'scheme' are super-tagged to tag code)
+ * - - Add Tag
+ *
+ * DONE:
+ * - Added more microformat support
+ * - Better RSS/Technorati integration
+ * - Better styling on tag display (more classes, less inline styles)
+ * - Tag Intersections
+ *   - Note: Tag intersections do work, but it is a little hackey.  You need
+ *           to apply a patch to your main serendiptiy file.  The patch is
+ *           available here:
+ *              http://blog.jonnay.net/uploads/Code/freetag2.1.s9y.patch.txt
+ *           If you are using PostgreSQL then this patch wont work for you.
+ *           sorry, but thems the breaks.  Maybe you can help fix the query?
+ * - Tag Administration
+ */
+
+// Probe for a language include with constants. Still include defines later on, if some constants were missing
+$probelang = dirname(__FILE__) . '/' . $serendipity['charset'] . 'lang_' . $serendipity['lang'] . '.inc.php';
+if (file_exists($probelang)) {
+    include $probelang;
+}
+
+include_once dirname(__FILE__) . '/lang_en.inc.php';
+
+// Because I am using get methods, if you change this, you also have to change the getManageUrlAsHidden
+define('FREETAG_MANAGE_URL','?serendipity[adminModule]=event_display&amp;serendipity[adminAction]=managetags');
+define('FREETAG_EDITENTRY_URL','?serendipity[action]=admin&serendipity[adminModule]=entries&serendipity[adminAction]=edit&serendipity[id]=');
+
+class serendipity_event_freetag extends serendipity_event
+{
+    var $tags  = array();
+    var $title = PLUGIN_EVENT_FREETAG_TITLE;
+    var $displayTag = false;
+    var $TaggedEntries = null;
+    var $eventData;            // We use this as an eventdata store, so that we don't have to keep passing it
+                            // back and forth.
+
+    function introspect(&$propbag)
+    {
+        global $serendipity;
+
+        $propbag->add('name',          PLUGIN_EVENT_FREETAG_TITLE);
+        $propbag->add('description',   PLUGIN_EVENT_FREETAG_DESC);
+        $propbag->add('stackable',     false);
+        $propbag->add('author',        'Garvin Hicking, Jonathan Arkell');
+        $propbag->add('requirements',  array(
+            'serendipity' => '0.8',
+            'smarty'      => '2.6.7',
+            'php'         => '4.1.0'
+        ));
+        $propbag->add('version',       '2.48');
+        $propbag->add('event_hooks',    array(
+            'frontend_fetchentries'                             => true,
+            'frontend_fetchentry'                               => true,
+            'frontend_display:rss-2.0:per_entry'                => true,
+            'frontend_header'                                   => true,
+//            'frontend_display:rss-0.92:per_entry'             => true,
+            'frontend_display:rss-1.0:per_entry'                => true,
+//            'frontend_display:rss-0.91:per_entry'             => true,
+            'frontend_display:atom-0.3:per_entry'               => true,
+            'frontend_display:atom-1.0:per_entry'               => true,
+            'frontend_entryproperties'                          => true,
+            'frontend_rss'                                      => true,
+            'entry_display'                                     => true,
+            'entries_header'                                    => true,
+            'backend_publish'                                   => true,
+            'backend_save'                                      => true,
+            'backend_display'                                   => true,
+            'backend_sidebar_entries'                           => true,
+            'backend_sidebar_entries_event_display_managetags'  => true,
+            'backend_delete_entry'                              => true,
+            'external_plugin'                                   => true,
+            'xmlrpc_updertEntry'                                => true,
+            'xmlrpc_fetchEntry'                                 => true,
+            'xmlrpc_deleteEntry'                                => true,
+            'css'                                               => true
+        ));
+        $propbag->add('groups', array('BACKEND_EDITOR'));
+        $this->supported_properties = array('freetag_name', 'freetag_tagList');
+        $this->dependencies = array('serendipity_plugin_freetag' => 'keep');
+        $propbag->add('configuration', array('embed_footer', 'show_tagcloud', 'min_percent', 'max_percent', 'meta_keywords', 'show_related', 'show_related_count', 'lowercase_tags'));
+    }
+
+    function introspect_config_item($name, &$propbag)
+    {
+        switch($name) {
+            case 'show_tagcloud':
+                 $propbag->add('type',        'boolean');
+                 $propbag->add('name',        PLUGIN_EVENT_FREETAG_SHOW_TAGCLOUD);
+                 $propbag->add('description', '');
+                 $propbag->add('default',     true);
+                 break;
+
+            case 'embed_footer':
+                 $propbag->add('type',        'boolean');
+                 $propbag->add('name',        PLUGIN_EVENT_FREETAG_EMBED_FOOTER);
+                 $propbag->add('description', PLUGIN_EVENT_FREETAG_EMBED_FOOTER_DESC);
+                 $propbag->add('default',     true);
+                 break;
+
+            case 'min_percent':
+                 $propbag->add('type',        'string');
+                 $propbag->add('name',        PLUGIN_EVENT_FREETAG_TAGCLOUD_MIN);
+                 $propbag->add('description', '');
+                 $propbag->add('default',     '100');
+                 break;
+
+            case 'max_percent':
+                 $propbag->add('type',        'string');
+                 $propbag->add('name',        PLUGIN_EVENT_FREETAG_TAGCLOUD_MAX);
+                 $propbag->add('description', '');
+                 $propbag->add('default',     '300');
+                 break;
+
+            case 'meta_keywords':
+                 $propbag->add('type',        'string');
+                 $propbag->add('name',        PLUGIN_FREETAG_META_KEYWORDS);
+                 $propbag->add('description', '');
+                 $propbag->add('default',     '0');
+                 break;
+
+            case 'show_related':
+                $propbag->add('type',            'boolean');
+                $propbag->add('name',            PLUGIN_EVENT_FREETAG_SHOW_RELATED);
+                $propbag->add('description',     '');
+                $propbag->add('default',         true);
+                break;
+
+            case 'show_related_count':
+                $propbag->add('type',            'string');
+                $propbag->add('name',            PLUGIN_EVENT_FREETAG_SHOW_RELATED_COUNT);
+                $propbag->add('description',     '');
+                $propbag->add('default',         '5');
+                break;
+
+            case 'lowercase_tags':
+                 $propbag->add('type',        'boolean');
+                 $propbag->add('name',        PLUGIN_EVENT_FREETAG_LOWERCASE_TAGS);
+                 $propbag->add('description', '');
+                 $propbag->add('default',     true);
+        }
+        return true;
+    }
+
+    function generate_content(&$title) {
+        $title = $this->title;
+    }
+
+    function tableCreated()  {
+        global $serendipity;
+
+        $q = "select count(tag) from {$serendipity['dbPrefix']}entrytags";
+        $row = serendipity_db_query($q, true, 'num');
+
+        if (!is_numeric($row[0])) {        // if the response we got back was an SQL error.. :P
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    function upgradeFromVersion1() {
+        global $serendipity;
+
+        $q = "select count(*) from {$serendipity['dbPrefix']}entryproperties where property = 'ep_freetag_name'";
+        $result = serendipity_db_query($q);
+
+        if ((int)$result[0] > 0) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    function convertEntryPropertiesTags() {
+        global $serendipity;
+
+        $q = "select entryid, value from {$serendipity['dbPrefix']}entryproperties where property = 'ep_freetag_name'";
+        $result = serendipity_db_query($q);
+
+        if (!is_array($result)) {
+            return false;
+        }
+
+        foreach($result as $entry) {
+            $tags = serendipity_event_freetag::makeTagsFromTaglist($entry['value']);
+            serendipity_event_freetag::addTagsToEntry($entry['entryid'], $tags);
+
+            printf(PLUGIN_FREETAG_UPGRADE1_2, count($tags), $entry['entryid']);
+            echo '<BR/>';
+        }
+
+        $q = "delete from {$serendipity['dbPrefix']}entryproperties where property = 'ep_freetag_name'";
+        $result = serendipity_db_query($q);
+    }
+
+    function cleanup() {
+        global $serendipity;
+
+        serendipity_event_freetag::install();
+    }
+
+    function install() {
+        global $serendipity;
+
+        if (!serendipity_event_freetag::tableCreated()) {
+            $q = "create table {$serendipity['dbPrefix']}entrytags (" .
+                    "entryid int(10) not null, " .
+                    "tag varchar(50) not null, " .
+                    "primary key (entryid, tag)" .
+                ")";
+
+            $result = serendipity_db_schema_import($q);
+
+            if ($result !== true) {
+                return;
+            }
+
+            serendipity_db_schema_import("CREATE INDEX tagsentryindex ON {$serendipity['dbPrefix']}entrytags (entryid)");
+            serendipity_db_schema_import("CREATE INDEX tagsTagIndex ON {$serendipity['dbPrefix']}entrytags (tag)");
+        }
+
+        if (serendipity_event_freetag::upgradeFromVersion1()) {
+            serendipity_event_freetag::convertEntryPropertiesTags();
+        } else {
+            echo "NOT UPGRADING!";
+        }
+    }
+
+    function getTagHtmlFromCSV($tagString) {
+        global $serendipity;
+
+        $links   = array();
+        if (empty($tagString)) {
+            return array();
+        }
+        $tags    = explode(',', $tagString);
+        $taglink = $serendipity['baseURL'] . ($serendipity['rewrite'] == 'none' ? $serendipity['indexFile'] . '?/' : '') . 'plugin/tag/';
+        foreach($tags as $tag) {
+            $tag = trim($tag);
+            if (empty($tag)) {
+                continue;
+            }
+            $links[] = '<a href="' . $taglink . urlencode($tag) . '"' .
+                       ' title="' . htmlspecialchars($tag) . '"' .
+                       ' rel="tag">' . htmlspecialchars($tag) . '</a>';
+        }
+
+        return implode(', ', $links);
+    }
+
+    function getTagHtml($tags) {
+        global $serendipity;
+
+        $links   = array();
+        $taglink = $serendipity['baseURL'] . ($serendipity['rewrite'] == 'none' ? $serendipity['indexFile'] . '?/' : '') . 'plugin/tag/';
+        if (!is_array($tags)) {
+            return '';
+        }
+
+        foreach($tags as $tag) {
+            $tag = trim($tag);
+            if (empty($tag)) {
+                continue;
+            }
+            $links[] = '<a href="' . $taglink . urlencode($tag) . '"' .
+                       ' title="' . htmlspecialchars($tag) . '"' .
+                       ' rel="tag">' . htmlspecialchars($tag) . '</a>';
+        }
+
+        return implode(', ', $links);
+    }
+
+    function getRelatedEntries($tags, $postID) {
+        global $serendipity;
+
+        if (!is_array($tags)) {
+            return false;
+        }
+
+        $q = "SELECT DISTINCT e1.entryid,
+                     e2.title
+                FROM {$serendipity['dbPrefix']}entrytags AS e1
+           LEFT JOIN {$serendipity['dbPrefix']}entries   AS e2
+                  ON e1.entryid = e2.id
+               WHERE e1.tag IN ('" . implode("', '", $tags) . "')
+                 AND e1.entryid != " . (int)$postID . "
+                 AND e2.isdraft = 'false'
+                     " . (!serendipity_db_bool($serendipity['showFutureEntries']) ? " AND e2.timestamp <= " . time() : '') . "
+               LIMIT " . $this->get_config('show_related_count', 10);
+
+        $result = serendipity_db_query($q, false, 'assoc', false, 'entryid', 'title');
+
+        if (!is_array($result)) {
+            return false;
+        }
+
+        return $result;
+    }
+
+    function getRelatedEntriesHtml(&$entries) {
+        global $serendipity;
+
+        if (!is_array($entries)) {
+            return false;
+        }
+
+        $entrylink = $serendipity['baseURL'] . ($serendipity['rewrite'] == 'none' ? $serendipity['indexFile'] . '?/' : '/');
+
+        $return = '<div class="serendipity_freeTag_related">' . PLUGIN_EVENT_FREETAG_RELATED_ENTRIES . '<br />';
+        foreach($entries AS $entryid => $title) {
+            $return .= ' <a href="' . serendipity_archiveURL($entryid, $title) . '" title="' . htmlspecialchars($title) . '">' . htmlspecialchars($title) . '</a><br />';
+        }
+        $return .= '</div>';
+        return $return;
+    }
+
+    /*  This method can be called statically.
+        Tags should be an array with the key being the tag name, and val being
+        the number of occurances. */
+    function displayTags($tags, $xml, $nl, $scaling, $maxSize = 200, $minSize = 100)
+    {
+        global $serendipity;
+
+        if (!is_array($tags)) {
+            return false;
+        }
+
+        $taglink = $serendipity['baseURL'] . ($serendipity['rewrite'] == 'none' ? $serendipity['indexFile'] . '?/' : '') . 'plugin/tag/';
+        $rsslink = $serendipity['serendipityHTTPPath'] . 'rss.php?serendipity[tag]=';
+        $xmlImg  = serendipity_getTemplateFile('img/xml.gif');
+
+        $first   = true;
+        $biggest = max($tags);
+        $smallest= min($tags) - 1;
+        $scale   = $biggest - $smallest;
+
+        if ($scale < 0) {
+            $scale = 1;
+        }
+
+        foreach($tags AS $name => $quantity) {
+            if (empty($name)) {
+                continue;
+            }
+
+            if (!$first && !$nl && !$scaling) {
+                echo ', ';
+            }
+
+            if ($scaling) {
+                $fontSize = round((($maxSize - $minSize) * $quantity) / $scale) + $minSize;
+                echo '<span class="tag_weight_' . $fontSize . '" style="font-size: '. $fontSize .'%">';
+            }
+
+            echo '<a rel="tag" href="' . $taglink . urlencode($name) . '" title="' . htmlspecialchars($name) . ($quantity > 0 ? ' (' . $quantity . ') ' : '') . '">' . str_replace(' ','&nbsp;',htmlspecialchars($name)) . '</a>';
+
+            if ($scaling) {
+                echo '</span>';
+            }
+
+            if ($xml) {
+                echo '<a rel="tag" href="' . $rsslink . urlencode($name) . '" title="' . htmlspecialchars($name) . '">'.
+                     '<img alt="xml" src="' . $xmlImg . '" class="serendipity_freeTag_xmlButton" /></a>';
+            }
+
+            if ($nl) {
+                echo '<br />' . "\n";
+            } else {
+                echo ' ';
+            }
+
+            $first = false;
+        }
+    }
+
+    function event_hook($event, &$bag, &$eventData, $addData = null) {
+        global $serendipity;
+
+        $hooks = &$bag->get('event_hooks');
+        if (isset($hooks[$event])) {
+            switch($event) {
+                case 'backend_delete_entry':
+                    $this->deleteTagsForEntry((int)$eventData);
+                    return true;
+
+                case 'frontend_header':
+                    $this->displayMetaKeywords($serendipity['GET']['id'] );
+                    return true;
+
+                case 'frontend_display:rss-2.0:per_entry':
+                case 'frontend_display:rss-0.91:per_entry':
+                    $eventData['display_dat'] .= $this->getFeedXmlForTags('category', $eventData['properties']['freetag_tags']);
+                    return true;
+
+                case 'frontend_display:rss-1.0:per_entry':
+                case 'frontend_display:rss-0.91:per_entry':
+                case 'frontend_display:atom-0.3:per_entry':
+                case 'frontend_display:atom-1.0:per_entry':
+                    $eventData['display_dat'] .= $this->getFeedXmlForTags('dc:subject', $eventData['properties']['freetag_tags']);
+                    return true;
+
+                case 'external_plugin':
+                    $uri_parts  = explode('?', str_replace('&amp;', '&', $eventData));
+                    $param      = explode('/', $uri_parts[0]);
+                    $plugincode = array_shift($param);
+
+                    if (($plugincode == "tag") || ($plugincode == "tags") || ($plugincode == "freetag")) {
+                        /* Attempt to locate hidden variables within the URI */
+                        foreach ($serendipity['uriArguments'] as $k => $v) {
+                            if ($v{0} == 'P') { /* Page */
+                                $page = substr($v, 1);
+                                if (is_numeric($page)) {
+                                    $serendipity['GET']['page'] = $page;
+                                    unset($serendipity['uriArguments'][$k]);
+                                    if ($param[count($param)-1] == "P{$page}.html") {
+                                        array_pop($param);  // knock it off of the param array as well
+                                    }
+                                }
+                            }
+                        }
+
+                        if (count($param) == 0 || empty($param[0])) {
+                            $serendipity['head_subtitle'] = PLUGIN_EVENT_FREETAG_ALLTAGS;
+                            $this->displayTag = true;
+                            $param = null;
+                        } else if (count($param) == 1) {
+                            $param      = urldecode($param[0]);
+                            $serendipity['head_subtitle'] = sprintf(PLUGIN_EVENT_FREETAG_USING, htmlspecialchars($param));
+                            $emit_404 = true;
+                        } else {
+                            $serendipity['head_subtitle'] = sprintf(PLUGIN_EVENT_FREETAG_USING, implode(' + ', array_map('htmlspecialchars', $param)));
+                            $param = array_map('urldecode', $param);
+                            $emit_404 = true;
+                        }
+                        $this->tags['show'] = $param;
+
+                        include_once(S9Y_INCLUDE_PATH . 'include/genpage.inc.php');
+                        if ($emit_404 && $this->TaggedEntries !== null && $this->TaggedEntries < 1) {
+                            @header('HTTP/1.0 404 Not found');
+                            @header('X-FreeTag: not found');
+                        } else {
+                            @header('X-FreeTag: ' . $this->TaggedEntries);
+                        }
+                        $raw_data = ob_get_contents();
+                        ob_end_clean();
+                        $serendipity['smarty']->assign('raw_data', $raw_data);
+                        serendipity_gzCompression();
+                        $serendipity['smarty']->display(serendipity_getTemplateFile($serendipity['smarty_file'], 'serendipityPath'));
+                        @define('NO_EXIT', true);
+                    }
+                    break;
+
+                case 'backend_sidebar_entries':
+?>
+                        <li>
+                            <a href="?serendipity[adminModule]=event_display&amp;serendipity[adminAction]=managetags">
+                                <?php echo PLUGIN_EVENT_FREETAG_MANAGETAGS; ?>
+                            </a>
+                        </li>
+<?php
+                    return true;
+                    break;
+
+
+                case 'backend_sidebar_entries_event_display_managetags':
+                    $this->eventData = $eventData;
+                    $this->displayManageTags($event, $bag, $eventData, $addData);
+
+                    return true;
+                    break;
+
+                case 'backend_publish':
+                case 'backend_save':
+                    if (!isset($serendipity['POST']['properties']) || !is_array($serendipity['POST']['properties']) || !isset($eventData['id'])) {
+                        return true;
+                    }
+
+                    $tags = $this->makeTagsFromTagList($serendipity['POST']['properties']['freetag_tagList']);
+                    if (!empty($tags)) {
+                        $serendipity['POST']['properties']['freetag_tagList'] = implode(',', $tags);
+
+                        $this->deleteTagsForEntry($eventData['id']);
+                        $this->addTagsToEntry($eventData['id'], $tags);
+                    }
+
+                    return true;
+                    break;
+
+                case 'backend_display':
+                    if (isset($serendipity['POST']['properties']['freetag_tagList'])) {
+                        $tagList = $serendipity['POST']['properties']['freetag_tagList'];
+                    } else if (isset($eventData['id'])) {
+                        $tagList = implode(',', $this->getTagsForEntry($eventData['id']));
+                    } else {
+                        $tagList = '';
+                    }
+
+                    if (serendipity_db_bool($this->get_config('lowercase_tags', true))) {
+                        if (function_exists("mb_strtolower")) {
+                            $tagList = mb_strtolower($tagList);
+                        } else {
+                            $tagList = strtolower($tagList);
+                        }
+                    }
+
+                    $freetags = $this->makeTagsFromTagList($tagList);
+                    if (!empty($freetags)) {
+                        $tagList = implode(',', $freetags);
+                    }
+
+                    $taglist = (array)$this->getAllTags();
+?>
+                    <script language="Javascript">
+                    function addTag(addTag)
+                    {
+                        var tags = document.getElementById("properties_freetag_tagList").value.split(',');
+
+                        inList = false;
+                        for (tag in tags) {
+                            if (trim(tags[tag].toLowerCase()) == addTag.toLowerCase())
+                                inList = true;
+                        }
+
+                        if (!inList)
+                            document.getElementById("properties_freetag_tagList").value = document.getElementById("properties_freetag_tagList").value + "," + addTag
+                    }
+
+                    function trim(str)
+                    {
+                        return str.replace(/^\s*|\s*$/g,"");
+
+                    }
+                    </script>
+                    <fieldset style="margin: 5px">
+                        <a name="tagListAnchor"></a>
+                        <div style="margin: 5px; border: 1px dotted #000; padding: 5px; font-size: 9px;">
+<?php
+                            $lastletter = '';
+                            foreach ($taglist as $tag => $count) {
+                                if (substr($tag, 0, 1) != $lastletter)
+                                    echo " <b>|".strtoupper(substr($tag, 0, 1)).':</b> ';
+                                echo "<A href=\"#tagListAnchor\" style=\"text-decoration: none\" onClick=\"addTag('$tag')\">$tag</a>, ";
+                                $lastletter = substr($tag, 0, 1);
+                            }
+?>
+                        </div>
+                        <legend><?php echo PLUGIN_EVENT_FREETAG_TITLE; ?></legend>
+                        <label for="serendipity[properties][freetag_tagList]" title="<?php echo PLUGIN_EVENT_FREETAG_TITLE; ?>">
+                            <?php echo PLUGIN_EVENT_FREETAG_ENTERDESC; ?>:</label><br/>
+                        <input type="text" name="serendipity[properties][freetag_tagList]" id="properties_freetag_tagList" value="<?php echo htmlspecialchars($tagList); ?>" style="width: 100%" />
+                    </fieldset>
+<?php
+                    return true;
+                    break;
+
+
+                case 'frontend_entryproperties':
+                    $this->importEntryTagsIntoProperties($eventData, $addData);
+
+                    return true;
+                    break;
+
+                case 'frontend_fetchentries':
+                case 'frontend_fetchentry':
+                    if (!empty($this->tags['show'])) {
+                        if (is_array($this->tags['show'])) {
+                            $showtag = array_map('serendipity_db_escape_string', $this->tags['show']);
+                        } else {
+                            $showtag = serendipity_db_escape_string($this->tags['show']);
+                        }
+                    } else if (!empty($serendipity['GET']['tag'])) {
+                        $showtag = serendipity_db_escape_string(urldecode($serendipity['GET']['tag']));
+                    }
+
+                    if (is_string($show_tag) && serendipity_db_bool($this->get_config('lowercase_tags', true))) {
+                        if (function_exists("mb_strtolower")) {
+                            $showtag = mb_strtolower($showtag);
+                        } else {
+                            $showtag = strtolower($showtag);
+                        }
+                    }
+
+                    if (!empty($showtag)) {
+                        if (is_string($showtag)) {
+                            $join = "INNER JOIN {$serendipity['dbPrefix']}entrytags AS entrytags ON (e.id = entrytags.entryid) ";
+                            $cond = "entrytags.tag = '$showtag' ";
+                        } else if (is_array($showtag)) {
+                            $taglist = implode('\',\'', $showtag);  // outputs tag','tag2','tag3
+                            $total = count($showtag);
+                            $join = "INNER JOIN {$serendipity['dbPrefix']}entrytags AS entrytags ".
+                                    "ON e.id = entrytags.entryid ";
+                            $cond = "(entrytags.tag IN ('$taglist'))";
+                            $eventData['having'] = " HAVING count(entrytags.tag) = $total";
+                        }
+
+                        if (empty($eventData['and'])) {
+                            $eventData['and'] = " WHERE $cond ";
+                        } else {
+                            $eventData['and'] .= " AND $cond ";
+                        }
+
+
+                        if (empty($eventData['joins'])) {
+                            $eventData['joins'] = $join;
+                        } else {
+                            $eventData['joins'] .= $join;
+                        }
+
+                        $this->displayTag = $showtag;
+                    }
+
+                    return true;
+                    break;
+
+                case 'frontend_rss':
+                    if (!empty($this->displayTag)) {
+                        $eventData['title'] .= serendipity_utf8_encode(htmlspecialchars(' (' . sprintf(PLUGIN_EVENT_FREETAG_USING, $this->displayTag) . ')'));
+                    }
+
+                    return true;
+                    break;
+
+                case 'entries_header':
+                    if ($this->displayTag !== false && serendipity_db_bool($this->get_config('show_tagcloud'))) {
+                         $this->displayTagCloud();
+                    }
+
+                    return true;
+                    break;
+
+                case 'css':
+                    if (strpos($eventData, '.serendipity_freeTag')) {
+                        // class exists in CSS, so a user has customized it and we don't need default
+                        return true;
+                    }
+
+                    $this->addToCSS($eventData);
+
+                    return true;
+                    break;
+
+                case 'entry_display':
+                    // Don't display entries if we are getting a full tag list
+                    if (is_array($eventData)) {
+                        $this->TaggedEntries = count($eventData);
+                        @header('X-FreeTag-Count: Array');
+                    } else {
+                        @header('X-FreeTag-Count: Empty');
+                        $this->TaggedEntries = 0;
+                    }
+                    if ($this->displayTag === true) {
+                        $eventData['clean_page'] = true;
+                        return true;
+                    }
+
+                    // This falls into the default case, which returns false...  Is this supposed to happen?
+                    // Is it a bug?
+                    // Is it a feature?
+                    $this->displayEntry($eventData, $addData);
+                    return true;
+
+                case 'xmlrpc_updertEntry':
+                    if (isset($eventData['id']) && isset($eventData['mt_keywords'])) {
+                        //XMLRPC call
+                        $tags = $this->makeTagsFromTagList($eventData['mt_keywords']);
+                        if (!empty($tags)) {
+                            $this->deleteTagsForEntry($eventData['id']);
+                            $this->addTagsToEntry($eventData['id'], $tags);
+                        }
+                    }
+                    return true;
+                    break;
+
+                case 'xmlrpc_fetchEntry':
+                    $eventData['mt_keywords']=implode(',', $this->getTagsForEntry($eventData['id']));
+                    return true;
+                    break;
+
+                case 'xmlrpc_deleteEntry':
+                    if (isset($eventData["id"])) {
+                        $this->deleteTagsForEntry($eventData["id"]);
+                    }
+
+                    return true;
+                    break;
+
+                default:
+                    return false;
+                    break;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    function displayEntry(&$eventData, $addData)
+    {
+        global $serendipity;
+        $msg = '<div class="serendipity_freeTag">' . PLUGIN_EVENT_FREETAG_LIST . '</div>';
+
+        if (serendipity_db_bool($this->get_config('embed_footer'))) {
+            $field = 'add_footer';
+        } else {
+            if (strlen($eventData[0]['extended']) > 0) {
+                $field = 'extended';
+            } else {
+                $field = 'body';
+            }
+
+        }
+
+        if ($addData['extended']) {
+            $key =& $this->getFieldReference($field, $eventData[0]);
+
+            $tags = $this->getTagsForEntries(array($eventData[0]['id']));
+            $key .= sprintf($msg, $this->getTagHtml($tags[$eventData[0]['id']]));
+            if (serendipity_db_bool($this->get_config('show_related', true))) {
+                   $eventData[0]['add_footer'] .= $this->getRelatedEntriesHtml($this->getRelatedEntries($tags[$eventData[0]['id']], $eventData[0]['id']));
+            }
+        } else if ($addData['preview']) {
+            $eventData[0]['exflag']    = 1;
+            $eventData[0][$field] .= sprintf($msg, $this->getTagHtmlFromCSV($serendipity['POST']['properties']['freetag_tagList']));
+            if (serendipity_db_bool($this->get_config('show_related', true))) {
+                $ctags = explode(',', $serendipity['POST']['properties']['freetag_tagList']);
+                $eventData[0]['add_footer'] .= $this->getRelatedEntriesHtml($this->getRelatedEntries($ctags, $eventData[0]['id']));
+            }
+        } else {
+            $elements = count($eventData);
+            $skeys = array();
+            for ($i = 0; $i < $elements; $i++) {
+                if (empty($eventData[$i]['properties']['freetag_tags'])) {
+                    continue;
+                }
+
+                if (!isset($eventData[$i]['add_footer'])) {
+                    $eventData[$i]['add_footer'] = '';
+                }
+
+                $cont = sprintf($msg, $this->getTagHtml($eventData[$i]['properties']['freetag_tags']));
+                if ($field == 'add_footer') {
+                    $skeys[$i] =& $eventData[$i]['add_footer'];
+                } elseif (strlen($eventData[$i]['extended']) > 0) {
+                    $skeys[$i] =& $this->getFieldReference('extended', $eventData[$i]);
+                } else {
+                    $skeys[$i] =& $this->getFieldReference('body', $eventData[$i]);
+                }
+                $skeys[$i] .= $cont;
+            }
+        }
+    }
+
+    /**
+     * Returns a list of all tags
+     * This performs a memoization operation, so that if we happen to be
+     * getting all tags more then one time per request, we only perform
+     * the SQL query once
+     */
+    // static
+    function makeTagsFromTaglist($tagList)
+    {
+        $freetags = explode(',', $tagList);
+        foreach($freetags AS $idx => $tag) {
+            $tag = trim($tag);
+            if (!empty($tag)) {
+                $tags[] = $tag;
+            }
+        }
+        return $tags;
+    }
+
+    function getAllTags()
+    {
+        global $serendipity;
+
+        static $memo = false;
+
+        if (is_array($memo)) {
+            return $memo;
+        }
+
+        $q = "SELECT tag, count(tag) as total
+                FROM {$serendipity['dbPrefix']}entrytags
+                GROUP BY tag
+                ORDER BY tag";
+
+        $rows = serendipity_db_query($q);
+
+        if (!is_array($rows)) {
+            echo $rows;
+            return false;
+        }
+
+        $memo = array();
+        foreach((array)$rows as $r) {
+            $memo[$r['tag']] = $r['total'];
+        }
+
+        return $memo;
+    }
+
+    function displayTagCloud()
+    {
+        $tags = $this->getTagCloudTags();
+
+        echo '<div class="serendipity_Entry_Date freetag_cloud">';
+
+        echo '<h2 class="serendipity_date">';
+        $tagTitle = is_array($this->displayTag) ? implode(' + ',$this->displayTag) : $this->displayTag;
+        printf ($title, $tagTitle);
+        echo '</h2>';
+        echo '<div class="serendipity_freetag_taglist">';
+        if (!empty($tags)) {
+            $min = $this->get_config('min_percent', 100);
+            $max = $this->get_config('max_percent', 300);
+            serendipity_event_freetag::displayTags($tags, false, false, true, $max, $min);
+        } else {
+            echo PLUGIN_EVENT_FREETAG_NO_RELATED;
+        }
+        echo '</div>';
+        echo '</div>';
+    }
+
+    function getTagCloudTags() {
+        $rows = serendipity_db_query($this->getTagCloudQuery());
+
+        foreach((array)$rows as $r) {
+            $tags[$r['tag']] = $r['total'];
+        }
+        return $tags;
+    }
+
+    /* Todo:
+        - turn use of instance var to parameter */
+    function getTagCloudQuery()
+    {
+        global $serendipity;
+        if ($this->displayTag === true) {
+            $title = PLUGIN_EVENT_FREETAG_ALLTAGS;
+            $q = "SELECT tag, count(tag) as total FROM {$serendipity['dbPrefix']}entrytags GROUP BY tag ORDER BY tag";
+        } else {
+            $title = PLUGIN_EVENT_FREETAG_SUBTAG;
+
+            if (is_string($this->displayTag)) {
+                $cond = "main.tag = '$this->displayTag'";
+                $ncond = "neg.tag != '$this->displayTag'";
+                $join = "LEFT JOIN {$serendipity['dbPrefix']}entrytags AS neg ".
+                      "ON main.entryid = neg.entryid ";
+                $totalModifier = '';
+            } else if (is_array($this->displayTag)) {
+                 $join = "LEFT JOIN {$serendipity['dbPrefix']}entrytags AS neg ".
+                    "ON main.entryid = neg.entryid ";
+                $ccond = '';
+                $ncond = '';
+
+                 $first = true;
+                $total = count($this->displayTag);
+
+                $totalModifier = " - $total";
+
+                for ($i = 0; $i < $total; $i++) {
+                    if (!$first) {
+                        $ncond .= " AND ";
+                        $cond .= " AND ";
+                    } else {
+                        $first = false;
+                    }
+
+                    $join .= "LEFT JOIN {$serendipity['dbPrefix']}entrytags AS sub{$i} ".
+                                "ON main.entryid = sub{$i}.entryid ";
+                    $cond .= "sub{$i}.tag = '{$this->displayTag[$i]}' ";
+                    $ncond .= "neg.tag != '{$this->displayTag[$i]}' ";
+                }
+            } else {
+                echo "FATAL ERROR! Unrecognized type for serendipity_event_freetag::$displayTag !";
+            }
+            $q = "SELECT neg.tag AS tag, count(neg.tag) {$totalModifier} AS total
+                    FROM {$serendipity['dbPrefix']}entrytags AS main
+               {$join}
+                   WHERE ($cond)
+                      AND ($ncond)
+                 GROUP BY neg.tag";
+        }
+        return $q;
+    }
+
+    /* Todo:
+        - turn use of instance var to parameter */
+    function displayMetaKeywords($id = null)
+    {
+        global $serendipity;
+        $max_keywords = (int)$this->get_config('meta_keywords', 0);
+        if ($max_keywords < 1) {
+            return;
+        }
+        if ($this->displayTag !== false && $this->displayTag !== true) { //show related tags
+          $query = $this->getTagCloudQuery();
+          $query = $query . " ORDER BY total DESC LIMIT " . $max_keywords;
+        } else if ($id == null) { // show all tags
+            // select most used tags in descending order
+            $query = "SELECT tag,
+                             count(tag) AS total
+                        FROM {$serendipity['dbPrefix']}entrytags
+                    GROUP BY tag
+                    ORDER BY total DESC
+                       LIMIT " . $max_keywords;
+        } else { // show tags for entry
+            // select tags from entry $id ordered by most usage descending
+            $query = "SELECT one.tag,
+                             two.entryid,
+                             count(two.tag) AS total
+                        FROM {$serendipity['dbPrefix']}entrytags
+                          AS one
+                        JOIN {$serendipity['dbPrefix']}entrytags AS two
+                          ON two.entryid = " . $id . "
+                         AND one.tag = two.tag
+                    GROUP BY one.tag
+                    ORDER BY total DESC
+                       LIMIT " . $max_keywords;
+        }
+        $rows = serendipity_db_query($query);
+        if (!is_array($rows)) {
+            return;
+        }
+        echo "<meta name=\"keywords\" content=\"";
+        if (isset($this->tags['show'])) {
+            if (is_array($this->tags['show'])) {
+                foreach($this->tags['show'] AS $r) {
+                    $not_first ? print(', ') : $not_first = true;
+                    echo $r;
+                }
+            } else {
+                echo $this->tags['show'];
+                $not_first = true;
+            }
+        }
+        foreach($rows AS $r) {
+            if (empty($r['tag'])) {
+                continue;
+            }
+            $not_first ? print(', ') : $not_first = true;
+            echo htmlspecialchars($r['tag']);
+        }
+        echo "\">";
+    }
+
+    function getRelatedTags($tag) {
+        global $serendipity;
+
+        $q = "SELECT sub.tag AS tag, count(sub.tag) AS total
+                     FROM {$serendipity['dbPrefix']}entrytags AS main
+                LEFT JOIN {$serendipity['dbPrefix']}entrytags AS sub
+                       ON main.entryid = sub.entryid
+                    WHERE main.tag = '$tag'
+                      AND sub.tag != '$tag'
+                 GROUP BY sub.tag
+                 ORDER BY sub.tag";
+
+        $rows = serendipity_db_query($q);
+
+        if (!is_array($rows)) {
+             if ($rows !== true && $rows !== 1 && $rows !== 'true') {
+                 echo $rows;
+             }
+             return array();
+        }
+
+        foreach($rows as $r) {
+            $tags[$r['tag']] = $r['total'];
+        }
+
+        return $tags;
+    }
+
+    function getLeafTags($leafWeight=1) {
+        global $serendipity;
+
+    $q = "SELECT tag, count(tag) as total
+               FROM {$serendipity['dbPrefix']}entrytags
+               GROUP BY tag
+               HAVING total <= $leafWeight
+               ORDER BY tag";
+
+    $rows = serendipity_db_query($q);
+
+        if (!is_array($rows)) {
+             echo $rows;
+        }
+
+        $tags = array();
+        foreach((array)$rows as $r) {
+            $tags[$r['tag']] = $r['total'];
+        }
+
+        return $tags;
+    }
+
+    function getTagsForEntries($entries) {
+        global $serendipity;
+
+        $q = "SELECT entryid, tag from {$serendipity['dbPrefix']}entrytags WHERE entryid IN (".implode(',', $entries).") order by entryid, tag";
+        $result = serendipity_db_query($q);
+
+        if (!is_array($result)) {
+            return false;
+        }
+
+        $return = array();
+        foreach($result as $idx => $row) {
+            $return[$row['entryid']][] = $row['tag'];
+        }
+
+        return $return;
+    }
+
+    function getTagsForEntry($entryId) {
+        $array = $this->getTagsForEntries(array($entryId));
+        return (is_array($array) ? array_pop($array) : array());
+    }
+
+    function deleteTagsForEntry($entryId) {
+        global $serendipity;
+
+        $q = "DELETE FROM {$serendipity['dbPrefix']}entrytags WHERE entryid = ".(int)$entryId;
+        serendipity_db_query($q);
+    }
+
+    // Static
+    function addTagsToEntry($entryId, $tags) {
+        global $serendipity;
+
+        if (!is_array($tags)) {
+            return false;
+        }
+
+        foreach($tags as $tag) {
+            $q = "INSERT INTO {$serendipity['dbPrefix']}entrytags (entryId, tag) VALUES (".(int)$entryId.", '".serendipity_db_escape_string($tag)."')";
+            serendipity_db_query($q);
+        }
+    }
+
+    // This may not be the right way to do this...
+    function importEntryTagsIntoProperties(&$eventData, $addData) {
+        // we do a dual loop here, which is probably the worst thing to do.
+        // A better thing might be some kind of array merge action, but I am not
+        // entirely sure how do do that with the arrays we are given.
+        //
+        // RefactorMe Later.
+
+        // Loop one in getTagsForEntries
+        $tagGroups = $this->getTagsForEntries(array_keys($addData));
+
+        // Loop 2
+        if (is_array($tagGroups))  {
+            foreach($tagGroups as $entryId => $tagList) {
+                $eventData[$addData[$entryId]]['properties']['freetag_tags'] = $tagList;
+                $eventData[$addData[$entryId]]['properties']['freetag_tagList'] = implode(",", $tagList);
+            }
+        }
+    }
+
+    function getFeedXmlForTags($element, $tagList) {
+        $out = '';
+        if (!is_array($tagList)) {
+            return $out;
+        }
+
+        foreach($tagList as $tag) {
+            $out .= serendipity_utf8_encode("<$element>".htmlspecialchars($tag)."</$element>\n");
+        }
+        return $out;
+    }
+
+    function displayManageTags($event, &$bag, &$eventData, $addData) {
+        ?>
+        <div style="border: 1px solid #000; padding: 5px;">
+        <ul>
+            <li> <a href="<?php echo FREETAG_MANAGE_URL ?>&amp;serendipity[tagview]=all"><?php echo PLUGIN_EVENT_FREETAG_MANAGE_ALL ?></a> </li>
+            <li> <a href="<?php echo FREETAG_MANAGE_URL ?>&amp;serendipity[tagview]=leaf"><?php echo PLUGIN_EVENT_FREETAG_MANAGE_LEAF ?></a> </li>
+            <li> <a href="<?php echo FREETAG_MANAGE_URL ?>&amp;serendipity[tagview]=entryuntagged"><?php echo PLUGIN_EVENT_FREETAG_MANAGE_UNTAGGED ?></a> </li>
+            <li> <a href="<?php echo FREETAG_MANAGE_URL ?>&amp;serendipity[tagview]=entryleaf"><?php echo PLUGIN_EVENT_FREETAG_MANAGE_LEAFTAGGED ?></a> </li>
+        </ul>
+        </div>
+        <?php
+        if (!empty($this->eventData['GET']['tagaction'])) {
+            $this->displayTagAction($this->eventData);
+        }
+
+        switch(@$this->eventData['GET']['tagview']) {
+            case "entryuntagged":
+                $this->displayUntaggedEntries();
+                break;
+
+            case "entryleaf":
+                $this->displayLeafTaggedEntries();
+                break;
+
+            case "all":
+                $tags = (array)$this->getAllTags();
+                $this->displayEditTags($this->eventData, $tags);
+                break;
+
+            case "leaf":
+                $tags = $this->getLeafTags();
+                $this->displayEditTags($this->eventData, $tags);
+                break;
+
+            default:
+                echo "Tag Administration";
+                if (!empty($this->eventData['GET']['tagview'])) {
+                    echo "Can't execute {$this->eventData['GET']['tagview']}";
+                }
+                break;
+        }
+        return true;
+    }
+
+    function displayUntaggedEntries() {
+        global $serendipity;
+
+        $q = "SELECT e.id as id, e.title as title
+                FROM ${serendipity['dbPrefix']}entries AS e
+                LEFT OUTER JOIN ${serendipity['dbPrefix']}entrytags AS t
+                    ON e.id = t.entryid
+                WHERE isnull(entryid)
+                GROUP BY e.id";
+
+        $this->displayEditEntries($q);
+    }
+
+    function displayLeafTaggedEntries() {
+        global $serendipity;
+
+        $q = "SELECT e.id as id, e.title as title, count(*) as total
+                FROM ${serendipity['dbPrefix']}entries AS e
+                LEFT JOIN ${serendipity['dbPrefix']}entrytags AS t
+                    ON e.id = t.entryid
+                GROUP BY e.id
+                HAVING total = 1";
+
+        $this->displayEditEntries($q);
+    }
+
+    function displayEditEntries($q) {
+        global $serendipity;
+
+        $r = serendipity_db_query($q);
+
+        if ($r === true) {
+            echo PLUGIN_EVENT_FREETAG_MANAGE_UNTAGGED_NONE;
+        } else if (!is_array($r)) {
+            echo $r;
+        } else {
+            foreach ($r as $row) {
+            echo '<p style="margin: 5px; border: 1px dotted #000; padding: 3px;">
+                    <a href="' . FREETAG_EDITENTRY_URL . $row['id'] . '"><img style="border: 0px;" src="' . serendipity_getTemplateFile('admin/img/edit.png') . '"></a>
+                    ' . $row['title'] . '
+                </p>';
+            }
+        }
+    }
+
+    function displayEditTags(&$eventData, $taglist) {
+        $url = FREETAG_MANAGE_URL . "&amp;serendipity[tagview]=".$this->eventData['GET']['tagview'];
+?>
+        <table>
+            <tr>
+                <th> <?php echo PLUGIN_EVENT_FREETAG_MANAGE_LIST_TAG ?> </th>
+                <th> <?php echo PLUGIN_EVENT_FREETAG_MANAGE_LIST_WEIGHT ?> </th>
+                <th> <?php echo PLUGIN_EVENT_FREETAG_MANAGE_LIST_ACTIONS ?> </th>
+            </tr>
+<?php
+        foreach($taglist as $tag => $weight) {
+?>
+            <tr>
+                <td> <?php echo $tag; ?> </td>
+                <td> <?php echo $weight; ?> </td>
+                <td>
+                    <a href="<?php echo $url?>&amp;serendipity[tagaction]=rename&serendipity[tag]=<?php echo urlencode($tag)?>"><?php echo PLUGIN_EVENT_FREETAG_MANAGE_ACTION_RENAME ?></a>
+                    <a href="<?php echo $url?>&amp;serendipity[tagaction]=split&serendipity[tag]=<?php echo urlencode($tag)?>"><?php echo  PLUGIN_EVENT_FREETAG_MANAGE_ACTION_SPLIT ?></a>
+                    <a href="<?php echo $url?>&amp;serendipity[tagaction]=delete&serendipity[tag]=<?php echo urlencode($tag)?>"><?php echo PLUGIN_EVENT_FREETAG_MANAGE_ACTION_DELETE ?></a>
+                </td>
+            </tr>
+<?php
+        }
+?>
+        </table>
+<?php
+    }
+
+    /**
+     * Here we are going to do a dispatch based on the action.
+     * There are 2 dispatches that happen here: The first is the display/query, where
+     * we ask the user for any extra information, and/or a confirmation.
+     * The next is the actual action itself, where we do a db update/delete of some sort.
+     */
+    function displayTagAction(&$eventData) {
+        global $serendipity;
+
+        $validActions = array('rename','split','delete');
+
+        // Sanitize user input
+        $tag = urldecode($this->eventData['GET']['tag']);
+        $action = urldecode($this->eventData['GET']['tagaction']);
+        if (!in_array($this->eventData['GET']['tagaction'], $validActions))
+            exit ("DON'T HACK!");
+
+        if ($this->eventData['GET']['commit'] == 'true') {
+            $method = 'get'.$this->eventData['GET']['tagaction'].'TagQuery';
+            $q = $this->$method($tag, $this->eventData);
+            echo $this->eventData['GET']['tagaction'] . " Completed";
+        } else {
+            $method = 'display'.$this->eventData['GET']['tagaction']."Tag";
+            $this->$method($tag, $this->eventData);
+        }
+    }
+
+    function getManageUrlAsHidden(&$eventData) {
+        return '<input type="hidden" name="serendipity[adminModule]" value="event_display" />
+                <input type="hidden" name="serendipity[adminAction]" value="managetags" />';
+    }
+
+    function displayRenameTag($tag, &$eventData) {
+?>
+        <form action="" method="GET">
+            <?php echo $this->getManageUrlAsHidden($this->eventData) ?>
+            <input type="hidden" name="serendipity[tagview]" value="<?php echo $this->eventData['GET']['tagview'] ?>">
+            <input type="hidden" name="serendipity[tagaction]" value="rename" />
+            <input type="hidden" name="serendipity[commit]" value="true" />
+            <input type="hidden" name="serendipity[tag]" value="<?php echo $tag?>" />
+            <?php echo $tag?> => <input type="text" name="serendipity[newtag]" /> <input type="submit" name="submit" value="rename" />
+        </form>
+<?php
+    }
+
+    /**
+     * Execute A rename of a tag
+     * We select all the entreis with the old tag name, delete all entry tags
+     * with the old tag name, and finally re insert.  The reason we do this is
+     * that we might be renaming a tag, to an already exising tag that is
+     * already associated to an entry, duplicating the primary key.
+     * If we do it via an update, the update fails, and our rename doesn't
+     * happen.  This way our update does happen, and we can siltenly fail
+     * when we hit a duplicate key condition.
+     * Postgres doesnt have an UPDATE IGNORE syntax, so we can't use that
+     * method.  Sux0rz.
+     */
+    function getRenameTagQuery($tag, &$eventData) {
+        global $serendipity;
+
+        $tag = serendipity_db_escape_string($tag);
+        $newtag = serendipity_db_escape_string(urldecode($serendipity['GET']['newtag']));
+
+        $q = "select entryid from ${serendipity['dbPrefix']}entrytags where tag = '$tag'";
+
+        $r = serendipity_db_query($q);
+        if (!is_array($r)) {
+            echo $r;
+            return false;
+        }
+
+        $q = "delete from ${serendipity['dbPrefix']}entrytags where tag = '$tag'";
+        serendipity_db_query($q);
+
+        foreach ($r as $row) {
+            $q = "insert into ${serendipity['dbPrefix']}entrytags values ('{$row['entryid']}','$newtag')";
+            serendipity_db_query($q);
+        }
+
+        return true;
+    }
+
+    function displayDeleteTag($tag, &$eventData) {
+        $no  = FREETAG_MANAGE_URL . "&amp;serendipity[tagview]=".$this->eventData['GET']['tagview'];
+        $yes = FREETAG_MANAGE_URL . "&amp;serendipity[tagview]=".$this->eventData['GET']['tagview'].
+                    "&amp;serendipity[tagaction]=delete".
+                    "&amp;serendipity[tag]=".urlencode($tag)."&amp;serendipity[commit]=true";
+?>
+        <h2> <?php printf(PLUGIN_EVENT_FREETAG_MANAGE_CONFIRM_DELETE, $tag)?></h2>
+        <h3> <a href="<?php echo $yes; ?>"><?php echo YES; ?></a> &nbsp; &nbsp; <a href="<?php echo $no; ?>"><?php echo NO; ?></a> </h3>
+<?php
+    }
+
+    function getDeleteTagQuery($tag, &$eventData) {
+        global $serendipity;
+
+           $tag = serendipity_db_escape_string($tag);
+
+        $q = "DELETE from ${serendipity['dbPrefix']}entrytags
+                WHERE tag='$tag'";
+
+        $r = serendipity_db_query($q);
+        if ($r !== true) {
+            echo $r;
+        }
+    }
+
+    function displaySplitTag($tag, &$eventData) {
+        if (strstr($tag, ' ')) {
+            $newtag = str_replace(' ',',',$tag);
+        } else {
+            $newtag = '';
+        }
+?>
+        <form action="" method="GET">
+            <?php echo $this->getManageUrlAsHidden($this->eventData) ?>
+            <input type="hidden" name="serendipity[tagview]" value="<?php echo $this->eventData['GET']['tagview'] ?>">
+            <input type="hidden" name="serendipity[tagaction]" value="split" />
+            <input type="hidden" name="serendipity[commit]" value="true" />
+            <input type="hidden" name="serendipity[tag]" value="<?php echo $tag?>" />
+            <p> <?php echo PLUGIN_EVENT_FREETAG_MANAGE_INFO_SPLIT ?> <br/>
+                foobarbaz =&gt; foo,bar,baz</p>
+            <?php echo $tag ?> =&gt; <input type="text" name="serendipity[newtags]" value="<?php echo $newtag; ?>" />
+            <input type="submit" name="submit" value="split" />
+        </form>
+<?php
+    }
+
+    function getSplitTagQuery($tag, &$eventData) {
+        global $serendipity;
+
+        $newtags = $this->makeTagsFromTaglist(urldecode($this->eventData['GET']['newtags']));
+        $tag = serendipity_db_escape_string($tag);
+
+        $q = "SELECT entryid from ${serendipity['dbPrefix']}entrytags where tag = '$tag'";
+        $entries = serendipity_db_query($q);
+
+        if (!is_array($entries)) {
+            echo $entries;
+            return false;
+        }
+
+        $q = "DELETE FROM ${serendipity['dbPrefix']}entrytags where tag = '$tag'";
+        $r = serendipity_db_query($q);
+        if ($r !== true) {
+            echo $r;
+            return false;
+        }
+
+        foreach ($entries as $entryid) {
+            foreach ($newtags as $tag) {
+                $q = "INSERT INTO ${serendipity['dbPrefix']}entrytags (entryid, tag)
+                        VALUES ('${entryid['entryid']}', '$tag')";
+                $r = serendipity_db_query($q);
+            }
+        }
+    }
+
+    function addToCSS(&$eventData) {
+        $eventData .= '
+.serendipity_freeTag
+{
+    margin-left: auto;
+    margin-right: 0px;
+    text-align: right;
+    font-size: 7pt;
+    display: block;
+    margin-top: 5px;
+    margin-bottom: 0px;
+}
+
+.serendipity_freeTag_related
+{
+    margin-left: 50px;
+    margin-right: 0px;
+    text-align: left;
+    font-size: small;
+    display: block;
+    margin-top: 20px;
+    margin-bottom: 0px;
+}
+
+.serendipity_freetag_taglist
+{
+    margin: 10px;
+    border: 1px solid #6265F0;
+    padding: 5px;
+    background-color: #B5B8FF;
+    text-align: justify;
+}
+
+.serendipity_freeTag a
+{
+    font-size: 7pt;
+    text-decoration: none;
+}
+
+.serendipity_freeTag a:hover
+{
+    color: green;
+    text-decoration: underline;
+}
+img.serendipity_freeTag_xmlButton
+{
+    vertical-align: bottom;
+    display: inline;
+    border: 0px
+}
+';
+    }
+}
+
+/* vim: set sts=4 ts=4 expandtab : */
diff --git a/plugins/serendipity_event_freetag/serendipity_plugin_freetag.php b/plugins/serendipity_event_freetag/serendipity_plugin_freetag.php
new file mode 100644 (file)
index 0000000..c554189
--- /dev/null
@@ -0,0 +1,134 @@
+<?php # $Id: serendipity_plugin_freetag.php,v 1.21 2006/04/05 08:44:16 garvinhicking Exp $
+
+// Probe for a language include with constants. Still include defines later on, if some constants were missing
+$probelang = dirname(__FILE__) . '/' . $serendipity['charset'] . 'lang_' . $serendipity['lang'] . '.inc.php';
+if (file_exists($probelang)) {
+    include $probelang;
+}
+
+include_once dirname(__FILE__) . '/lang_en.inc.php';
+
+class serendipity_plugin_freetag extends serendipity_plugin
+{
+    var $title = PLUGIN_FREETAG_NAME;
+
+    function introspect(&$propbag)
+    {
+        global $serendipity;
+
+        $this->title = $this->get_config('title', $this->title);
+
+        $propbag->add('name',          PLUGIN_FREETAG_NAME);
+        $propbag->add('description',   PLUGIN_FREETAG_BLAHBLAH);
+        $propbag->add('stackable',     false);
+        $propbag->add('author',        'Garvin Hicking, Jonathan Arkell');
+        $propbag->add('requirements',  array(
+            'serendipity' => '0.8',
+            'smarty'      => '2.6.7',
+            'php'         => '4.1.0'
+        ));
+        $propbag->add('version',       '2.37');
+        $propbag->add('groups',        array('FRONTEND_ENTRY_RELATED'));
+        $propbag->add('configuration', array('title', 'show_xml', 'show_newline', 'scale_tag', 'max_tags', 'treshold_tag_count'));
+        $this->dependencies = array('serendipity_event_freetag' => 'keep');
+    }
+
+
+    function introspect_config_item($name, &$propbag)
+    {
+        switch($name) {
+            case 'title':
+                 $propbag->add('type',        'string');
+                 $propbag->add('name',        TITLE);
+                 $propbag->add('description', TITLE_FOR_NUGGET);
+                 $propbag->add('default',     PLUGIN_FREETAG_NAME);
+                 break;
+
+            case 'scale_tag':
+                 $propbag->add('type',        'boolean');
+                 $propbag->add('name',        PLUGIN_FREETAG_SCALE);
+                 $propbag->add('description', '');
+                 $propbag->add('default',     false);
+                 break;
+
+            case 'show_xml':
+                $propbag->add('type',        'boolean');
+                $propbag->add('name',        PLUGIN_FREETAG_XML);
+                $propbag->add('description', '');
+                $propbag->add('default',     true);
+                break;
+
+            case 'show_newline':
+                $propbag->add('type',        'boolean');
+                $propbag->add('name',        PLUGIN_FREETAG_NEWLINE);
+                $propbag->add('description', '');
+                $propbag->add('default',     true);
+                break;
+
+            case 'max_tags':
+                $propbag->add('type',        'string');
+                $propbag->add('name',        PLUGIN_FREETAG_MAX_TAGS);
+                $propbag->add('description', '');
+                $propbag->add('default',     '100');
+                break;
+
+            case 'treshold_tag_count':
+                $propbag->add('type',        'string');
+                $propbag->add('name',        PLUGIN_FREETAG_TRESHOLD_TAG_COUNT);
+                $propbag->add('description', '');
+                $propbag->add('default',     '2');
+                break;
+            }
+
+        return true;
+    }
+
+    function generate_content(&$title)
+    {
+        global $serendipity;
+
+        $title = $this->get_config('title', $this->title);
+
+        if ($this->get_config('max_tags', 0) != 0) {
+            $limit = "LIMIT " . $this->get_config('max_tags', 0);
+        } else {
+            $limit = '';
+        }
+
+        $query = "SELECT et.tag, count(et.tag) AS total 
+                    FROM {$serendipity['dbPrefix']}entrytags AS et
+         LEFT OUTER JOIN {$serendipity['dbPrefix']}entries AS e
+                      ON et.entryid = e.id
+                   WHERE e.isdraft = 'false' "
+                         . (!serendipity_db_bool($serendipity['showFutureEntries']) ? " AND e.timestamp <= " . time() : '') . "
+                GROUP BY et.tag 
+                  HAVING count(et.tag) >= " . $this->get_config('treshold_tag_count') . " 
+                ORDER BY et.tag " . $limit;
+
+        $rows = serendipity_db_query($query);
+
+        if (!is_array($rows)) {
+            return;
+        }
+
+        // not sure if we can optimize this loop... :/
+        // Probably through some SQL magick.
+        foreach($rows as $r) {
+            $tags[$r['tag']] = $r['total'];
+        }
+
+        $xml     = serendipity_db_bool($this->get_config('show_xml'));
+        $nl      = serendipity_db_bool($this->get_config('show_newline'));
+        $scaling = serendipity_db_bool($this->get_config('scale_tag'));
+
+        serendipity_event_freetag::displayTags($tags, $xml, $nl, $scaling);
+    }
+
+    function cleanup() {
+        global $serendipity;
+
+        serendipity_event_freetag::install();
+    }
+}
+
+/* vim: set sts=4 ts=4 expandtab : */