--- /dev/null
+<?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&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(' ',' ',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('&', '&', $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&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 ?>&serendipity[tagview]=all"><?php echo PLUGIN_EVENT_FREETAG_MANAGE_ALL ?></a> </li>
+ <li> <a href="<?php echo FREETAG_MANAGE_URL ?>&serendipity[tagview]=leaf"><?php echo PLUGIN_EVENT_FREETAG_MANAGE_LEAF ?></a> </li>
+ <li> <a href="<?php echo FREETAG_MANAGE_URL ?>&serendipity[tagview]=entryuntagged"><?php echo PLUGIN_EVENT_FREETAG_MANAGE_UNTAGGED ?></a> </li>
+ <li> <a href="<?php echo FREETAG_MANAGE_URL ?>&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 . "&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?>&serendipity[tagaction]=rename&serendipity[tag]=<?php echo urlencode($tag)?>"><?php echo PLUGIN_EVENT_FREETAG_MANAGE_ACTION_RENAME ?></a>
+ <a href="<?php echo $url?>&serendipity[tagaction]=split&serendipity[tag]=<?php echo urlencode($tag)?>"><?php echo PLUGIN_EVENT_FREETAG_MANAGE_ACTION_SPLIT ?></a>
+ <a href="<?php echo $url?>&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 . "&serendipity[tagview]=".$this->eventData['GET']['tagview'];
+ $yes = FREETAG_MANAGE_URL . "&serendipity[tagview]=".$this->eventData['GET']['tagview'].
+ "&serendipity[tagaction]=delete".
+ "&serendipity[tag]=".urlencode($tag)."&serendipity[commit]=true";
+?>
+ <h2> <?php printf(PLUGIN_EVENT_FREETAG_MANAGE_CONFIRM_DELETE, $tag)?></h2>
+ <h3> <a href="<?php echo $yes; ?>"><?php echo YES; ?></a> <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 => foo,bar,baz</p>
+ <?php echo $tag ?> => <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 : */