if (@txpinterface == 'admin') { global $smd_featured_event, $smd_featured_textile_opts; $smd_featured_event = 'smd_featured'; $smd_featured_privs = get_pref('smd_featured_privs', '1,2'); $smd_featured_pref_privs = '1,2'; $smd_featured_textile_opts = array( 0 => 'title', 1 => 'desc', ); add_privs($smd_featured_event, $smd_featured_privs); register_tab("content", $smd_featured_event, smd_featured_gTxt('tab_name')); register_callback('smd_featured_manage', $smd_featured_event); register_callback('smd_featured_welcome', 'plugin_lifecycle.smd_featured'); } if (!defined('SMD_FEAT')) { define("SMD_FEAT", 'smd_featured'); } // ********** // ADMIN SIDE // ********** // ------------------------ function smd_featured_manage($evt, $stp) { if ($stp == 'save_pane_state') { smd_featured_save_pane_state(); } else { if(!$stp or !in_array($stp, array( 'smd_featured_table_install', 'smd_featured_table_remove', 'smd_featured_prefsave', 'smd_featured_save', 'smd_featured_tagit', 'smd_featured_change_pageby', ))) { smd_featured_list(''); } else $stp(); } } // ------------------------ function smd_featured_welcome($evt, $stp) { $msg = ''; switch ($stp) { case 'installed': smd_featured_table_install(0); $msg = 'Thanks for installing smd_featured. Please read the docs :-)'; break; case 'deleted': smd_featured_table_remove(0); break; } return $msg; } // ------------------------ function smd_featured_list($msg='') { global $smd_featured_event, $smd_featured_list_pageby, $smd_featured_textile_opts; pagetop(smd_featured_gTxt('tab_name'), $msg); extract(gpsa(array('smd_feat_id', 'smd_feat_label', 'smd_feat_searchkeep', 'smd_feat_filtkeep', 'page'))); if (smd_featured_table_exist(1)) { $featlist = safe_rows('*', SMD_FEAT, '1=1'); $featlist = empty($featlist) ? array() : $featlist; $editname = $feat_label = $feat_title = $feat_desc = ''; $etypes = $ftypes = $flist = array(); $etypes[''] = smd_featured_gTxt('unlabelled'); $ftypes['smd_unlabelled'] = smd_featured_gTxt('unlabelled'); foreach ($featlist as $item) { if (isset($item['label']) && !empty($item['label'])) { $ftypes[$item['label']] = $etypes[$item['label']] = $item['label']; } $flist[$item['feat_id']] = array('label' => $item['label'], 'title' => $item['feat_title'], 'title_html' => $item['feat_title_html'], 'description' => $item['description'], 'desc_html' => $item['desc_html']); } $featlist = $flist; // Get additional filtering from hidden prefs $where = array('1=1'); $seclist = get_pref('smd_featured_section_list', ''); if ($seclist) { $where[] = "Section IN ('".join("','", do_list($seclist))."')"; } $where[] = "Status IN (4,5)"; $orderby = get_pref('smd_featured_sort', 'Posted desc', 1); $orderqry = ($orderby) ? ' ORDER BY '.doSlash($orderby) : ''; $currOrder = explode(' ', $orderby); $currOrder[0] = (isset($currOrder[0])) ? $currOrder[0] : 'Posted'; $currOrder[1] = (isset($currOrder[1])) ? $currOrder[1] : 'desc'; $display = get_pref('smd_featured_display', 'all', 1); // Generate the extra criteria if in list view if ($display=='paginated') { if ($smd_feat_searchkeep) { $items = do_list($smd_feat_searchkeep, ' '); $itlist = array(); foreach ($items as $item) { if (trim($item) != '') { $itlist[] = "Title like '%$item%'"; } } $where[] = '('.join(' OR ', $itlist).')'; } if ($smd_feat_filtkeep) { $lbl = ($smd_feat_filtkeep == 'smd_unlabelled') ? '' : $smd_feat_filtkeep; $ids = safe_column('feat_id', SMD_FEAT, "BINARY label = '$lbl'"); $where[] = "ID IN ('".join("','", $ids)."')"; } } $where = join(' AND ', $where); $total = safe_count('textpattern', $where); $do_pag = !$smd_feat_filtkeep && !$smd_feat_searchkeep; $limit = ($display=='paginated' && $do_pag) ? max($smd_featured_list_pageby, 15) : 99999; list($page, $offset, $numPages) = pager($total, $limit, $page); $rs = safe_rows('*', 'textpattern', $where. $orderqry . " limit $offset, $limit"); $out = array(); foreach ($rs as $row) { $ftype = isset($featlist[$row['ID']]['label']) ? $featlist[$row['ID']]['label'] : ''; $out[] = array($row['ID'], $row['Title'], $ftype); if ($smd_feat_id && $row['ID'] == $smd_feat_id) { $editname = $row['Title']; $feat_label = $featlist[$smd_feat_id]['label']; $feat_title = $featlist[$smd_feat_id]['title']; $feat_desc = doStrip(str_replace('\r\n',' ', $featlist[$smd_feat_id]['description'])); } } $sortopts = array( 'Posted' => 'Posted', 'Expires' => 'Expiry', 'LastMod' => 'Modified', 'Title' => 'Title', 'Section' => 'Section', 'Category1' => 'Category1', 'Category2' => 'Category2', ); $sortdirs = array( 'asc' => 'Ascending', 'desc' => 'Descending', ); $displayopts = array( 'all' => 'All', 'paginated' => 'Paginated', ); $textileonoff = smd_featured_pref_explode($smd_featured_textile_opts, get_pref('smd_featured_textile', '11', 1)); $sizes = do_list(get_pref('smd_featured_box_size', '150x40', 1), 'x'); $sizes[0] = (isset($sizes[0]) && is_numeric($sizes[0])) ? $sizes[0] : '150'; $sizes[1] = (isset($sizes[1]) && is_numeric($sizes[1])) ? $sizes[1] : '40'; $display_js = ($display=='all') ? 1 : 0; echo '
Loading...
'; echo '' : '
'; } echo tag(join("",$tblout), 'div', $atts); echo '
'; if ($display=='paginated' && $do_pag) { echo n.''; } } $qs = array( "event" => $smd_featured_event, ); $qsVars = "index.php".join_qs($qs); $verifyTxt = smd_featured_gTxt('unfeature_confirm'); echo << // Concatenate checkbox options for storage function smd_feat_presub() { var smd_out = ""; jQuery(".smd_feat_textile :checkbox").each(function() { smd_out += (this.checked) ? 1 : 0; }); jQuery("#smd_feat_textile").val(smd_out); return true; } function smd_featured_select(obj, id) { obj = jQuery(obj).parent(); // N.B. Negative logic used here because we're checking the class _before_ it's been toggled var action = ((obj).hasClass("smd_featured")) ? 'remove' : 'add'; if (action == 'remove') { var ret = confirm('{$verifyTxt}'); if (ret == false) { return false; } } jQuery.post('{$qsVars}', { step: "smd_featured_tagit", smd_feat_id: id, smd_feat_action: action }, function(data) { obj.toggleClass('smd_featured'); if (action == 'add') { obj.prepend('{$edbtn} '); obj.append(''); } else { obj.find('a.edlink').remove(); obj.find('span.extra').remove(); if (jQuery("#smd_feat_search").val() != '') jQuery("#smd_feat_search").keyup(); if (jQuery("#smd_feat_filt").val() != '') jQuery("#smd_feat_filt").change(); } } ); return false; } function smd_featured_editkeep(id) { jQuery("#smd_feat_editform [name='smd_feat_searchkeep']").val(jQuery("#smd_feat_search").val()); jQuery("#smd_feat_editform [name='smd_feat_filtkeep']").val(jQuery("#smd_featured_bylabel #smd_feat_filt option:selected").val()); jQuery("#smd_feat_editform [name='smd_feat_id']").val(id); jQuery("#smd_feat_editform").submit(); } function smd_featured_savekeep() { jQuery("#smd_feat_saveform [name='smd_feat_searchkeep']").val(jQuery("#smd_feat_search").val()); jQuery("#smd_feat_saveform [name='smd_feat_filtkeep']").val(jQuery("#smd_featured_bylabel #smd_feat_filt option:selected").val()); } function smd_feat_filter(selector, query, nam, csense, exact) { if ({$display_js} == 1) { var query = jQuery.trim(query); csense = (csense) ? "" : "i"; query = query.replace(/ /gi, '|'); // add OR for regex query if (exact) { tmp = query.split('|'); for (var idx = 0; idx < tmp.length; idx++) { tmp[idx] = '^'+tmp[idx]+'$'; } query = tmp.join('|'); } var re = new RegExp(query, csense); jQuery(selector).each(function() { sel = (typeof nam=="undefined" || nam=='') ? jQuery(this) : jQuery(this).find("span[name='"+nam+"']"); if (query == '') { if (sel.length == 1 && sel.text() == '') { jQuery(this).show(); } else { jQuery(this).hide(); } } else { if (sel.text().search(re) < 0) { jQuery(this).hide(); } else { jQuery(this).show(); } } }); } } jQuery(function() { jQuery("#smd_feat_search").keyup(function(event) { jQuery("#smd_feat_filt").val('0'); // Clear the filter dropdown // if esc is pressed or nothing is entered if (event.keyCode == 27 || jQuery(this).val() == '') { jQuery(this).val(''); if ({$display_js} == 1) { jQuery(".smd_featured_table div:not(.tblhead)").show(); } } else { smd_feat_filter('.smd_featured_table div:not(.tblhead)', jQuery(this).val(), 'smd_feat_name', 0, 0); } }); if ('{$smd_feat_searchkeep}' != '') { jQuery("#smd_feat_search").keyup(); } jQuery("#smd_feat_filt").change(function(event) { jQuery("#smd_feat_search").val(''); // Empty the search box if (jQuery(this).val() == '') { if ({$display_js} == 1) { jQuery('.smd_featured_table div:not(.tblhead)').show(); } } else if (jQuery(this).val() == 'smd_unlabelled') { smd_feat_filter('.smd_featured_table div:not(.tblhead)', '', 'smd_feat_label', 0, 0); } else { smd_feat_filter('.smd_featured_table div:not(.tblhead)', jQuery(this).val(), 'smd_feat_label', 1, 1); } }); if ('{$smd_feat_filtkeep}' != '') { jQuery("#smd_feat_filt").change(); } if ('{$smd_feat_id}' != '') { jQuery("#smd_feat_label").focus(); jQuery("#smd_feat_labelchoose").change(function(event) { jQuery("#smd_feat_label").val(jQuery(this).val()); }); } jQuery("#smd_loading").hide(); jQuery("#smd_container").show(); }); EOS; echo ''; } else { // Table not installed $btnInstall = '
'.fInput('submit', 'submit', smd_featured_gTxt('tbl_install_lbl'), 'smallerbox').'
'; $btnStyle = ' style="border:0;height:25px"'; echo startTable('list'); echo tr(tda(strong(smd_featured_gTxt('prefs_some_tbl')).br.br .smd_featured_gTxt('prefs_some_explain').br.br .smd_featured_gTxt('prefs_some_opts'), ' colspan="2"') ); echo tr(tda($btnInstall, $btnStyle)); echo endTable(); } } // ------------------------------------------------------------- function smd_featured_change_pageby() { global $smd_featured_event; event_change_pageby($smd_featured_event); smd_featured_list(); } // ------------------------ // Update the passed record in the featured table function smd_featured_save() { global $smd_featured_event, $smd_featured_textile_opts; extract(gpsa(array('smd_feat_id', 'smd_feat_label', 'smd_feat_title', 'smd_feat_desc'))); assert_int($smd_feat_id); $smd_feat_titletile = $smd_feat_title; $smd_feat_desctile = $smd_feat_desc; $smd_feat_label = doSlash($smd_feat_label); if (smd_featured_table_exist()) { @include_once txpath.'/lib/classTextile.php'; @include_once txpath.'/publish.php'; $textileonoff = smd_featured_pref_explode($smd_featured_textile_opts, get_pref('smd_featured_textile', '11')); if (class_exists('Textile')) { $textile = new Textile(); if ($textileonoff['title'] == '1') { $smd_feat_titletile = doSlash($textile->TextileThis(parse($smd_feat_title))); } if ($textileonoff['desc'] == '1') { $smd_feat_desctile = doSlash($textile->TextileThis(parse($smd_feat_desc))); } } $smd_feat_title = doSlash($smd_feat_title); $smd_feat_desc = doSlash($smd_feat_desc); $ret = safe_upsert(SMD_FEAT, "label='$smd_feat_label', feat_title='$smd_feat_title', feat_title_html='$smd_feat_titletile', description='$smd_feat_desc', desc_html='$smd_feat_desctile'", "feat_id='$smd_feat_id'"); unset($_POST['smd_feat_id']); } smd_featured_list(smd_featured_gTxt('saved')); } // ------------------------ // Create an empty entry in the featured table or destroy it function smd_featured_tagit() { global $smd_featured_event; extract(doSlash(gpsa(array('smd_feat_id', 'smd_feat_action')))); assert_int($smd_feat_id); if ($smd_feat_action == 'add') { $ret = safe_upsert(SMD_FEAT, "label=''", "feat_id='$smd_feat_id'"); } else if ($smd_feat_action == 'remove') { $ret = safe_delete(SMD_FEAT, "feat_id='$smd_feat_id'"); } } // ------------------------------------------------------------- function smd_featured_prefsave() { extract(gpsa(array('smd_feat_display', 'smd_feat_sort', 'smd_feat_sortdir', 'smd_feat_box_x', 'smd_feat_box_y', 'smd_feat_textile'))); $msg = ''; if ($smd_feat_display) { set_pref("smd_featured_display", $smd_feat_display, 'smd_featured', PREF_HIDDEN, 'text_input', 0, PREF_PRIVATE); $msg = gTxt('preferences_saved'); } if ($smd_feat_sort && $smd_feat_sortdir) { $sort_crit = $smd_feat_sort.' '. $smd_feat_sortdir; set_pref("smd_featured_sort", $sort_crit, 'smd_featured', PREF_HIDDEN, 'text_input', 0, PREF_PRIVATE); $msg = gTxt('preferences_saved'); } if ($smd_feat_box_x && $smd_feat_box_y) { $dims = $smd_feat_box_x.'x'.$smd_feat_box_y; set_pref("smd_featured_box_size", $dims, 'smd_featured', PREF_HIDDEN, 'text_input', 0, PREF_PRIVATE); $msg = gTxt('preferences_saved'); } if ($smd_feat_textile) { set_pref("smd_featured_textile", $smd_feat_textile, 'smd_featured', PREF_HIDDEN, 'text_input', 0, PREF_PRIVATE); $msg = gTxt('preferences_saved'); } smd_featured_list($msg); } // ------------------------ // Split a multi-char preference value into an array of keys/values. // Note: value is passed in and not read directly from the prefs array in this function - intentionally function smd_featured_pref_explode($items, $optval) { $onoff = array_values(preg_split('//', $optval, -1, PREG_SPLIT_NO_EMPTY)); $out = array(); foreach($items as $key => $value) { $out[(string)$value] = $onoff[$key]; } return $out; } // ------------------------------------------------------------- function smd_featured_save_pane_state() { $panes = array('smd_featured_cpanel'); $pane = gps('pane'); if (in_array($pane, $panes)) { set_pref("pane_{$pane}_visible", (gps('visible') == 'true' ? '1' : '0'), 'smd_featured', PREF_HIDDEN, 'yesnoradio', 0, PREF_PRIVATE); send_xml_response(); } else { send_xml_response(array('http-status' => '400 Bad Request')); } } // ------------------------ // Add featured table if not already installed function smd_featured_table_install($showpane='1') { $GLOBALS['txp_err_count'] = 0; $ret = ''; $sql = array(); $sql[] = "CREATE TABLE IF NOT EXISTS `".PFX.SMD_FEAT."` ( `feat_id` int(8) NOT NULL default '0', `label` varchar(32) NULL default '', `feat_title` varchar(255) NULL default '', `feat_title_html` varchar(255) NULL default '', `description` text NULL default '', `desc_html` text NULL default '', PRIMARY KEY (`feat_id`) ) ENGINE=MyISAM"; if(gps('debug')) { dmp($sql); } foreach ($sql as $qry) { $ret = safe_query($qry); if ($ret===false) { $GLOBALS['txp_err_count']++; echo "".$GLOBALS['txp_err_count'].". ".mysql_error()."
\n"; echo "\n"; } } // Handle upgrades from previous versions $cols = getThings('describe `'.PFX.SMD_FEAT.'`'); if (!in_array('feat_id', $cols)) { safe_alter(SMD_FEAT, "CHANGE `id` `feat_id` int( 8 ) NOT NULL DEFAULT '0'"); } if (!in_array('feat_title', $cols)) { safe_alter(SMD_FEAT, "ADD `feat_title` varchar( 255 ) NULL DEFAULT '' AFTER `label`"); } if (!in_array('feat_title_html', $cols)) { safe_alter(SMD_FEAT, "ADD `feat_title_html` varchar( 255 ) NULL DEFAULT '' AFTER `feat_title`"); } // Spit out results if ($GLOBALS['txp_err_count'] == 0) { if ($showpane) { $message = smd_featured_gTxt('tbl_installed'); smd_featured_list($message); } } else { if ($showpane) { $message = smd_featured_gTxt('tbl_not_installed'); smd_featured_list($message); } } } // ------------------------ // Drop table if in database function smd_featured_table_remove() { $ret = ''; $sql = array(); $GLOBALS['txp_err_count'] = 0; if (smd_featured_table_exist()) { $sql[] = "DROP TABLE IF EXISTS " .PFX.SMD_FEAT. "; "; if(gps('debug')) { dmp($sql); } foreach ($sql as $qry) { $ret = safe_query($qry); if ($ret===false) { $GLOBALS['txp_err_count']++; echo "".$GLOBALS['txp_err_count'].". ".mysql_error()."
\n"; echo "\n"; } } } if ($GLOBALS['txp_err_count'] == 0) { $message = smd_featured_gTxt('tbl_removed'); } else { $message = smd_featured_gTxt('tbl_not_removed'); smd_featured_list($message); } } // ------------------------ function smd_featured_table_exist($all='') { if ($all) { $tbls = array(SMD_FEAT => 6); $out = count($tbls); foreach ($tbls as $tbl => $cols) { if (gps('debug')) { echo "++ TABLE ".$tbl." HAS ".count(@safe_show('columns', $tbl))." COLUMNS; REQUIRES ".$cols." ++".br; } if (count(@safe_show('columns', $tbl)) == $cols) { $out--; } } return ($out===0) ? 1 : 0; } else { if (gps('debug')) { echo "++ TABLE ".SMD_FEAT." HAS ".count(@safe_show('columns', SMD_FEAT))." COLUMNS;"; } return(@safe_show('columns', SMD_FEAT)); } } // **************** // PUBLIC SIDE TAGS // **************** // ------------------------ function smd_featured($atts, $thing) { global $smd_featured_info, $smd_prior_featured, $prefs; extract(lAtts(array( 'label' => '', 'unlabel' => 'Featured', 'labeltag' => '', 'time' => 'past', 'status' => '4,5', 'section' => '', 'limit' => '', 'sort' => '', 'form' => '', 'wraptag' => '', 'break' => '', 'class' => '', 'html_id' => '', ),$atts)); if (isset($atts['label'])) { if ($label) { $where = "BINARY label REGEXP '".$atts['label']."'"; } else { $where = "label=''"; } unset($atts['label']); } else { // If no label attribute has been given, treat this as 'all featured items' $ids = safe_column('feat_id', SMD_FEAT, '1=1'); $ids = join("','", doSlash($ids)); $where = "smdfeat.feat_id IN ('$ids')"; } // Exclude previously seen articles if (!empty($smd_prior_featured)) { $where .= ' AND smdfeat.feat_id NOT IN(' . join(',', $smd_prior_featured) . ')'; } if ($time) { switch ($time) { case 'any': break; case 'future': $where .= " AND Posted > now()"; break; default: $where .= " AND Posted <= now()"; } if (!$prefs['publish_expired_articles']) { $where .= " AND (now() <= Expires OR Expires = ".NULLDATETIME.")"; } unset($atts['time']); } if ($status) { $where .= ' AND Status in ('.join(',', do_list($status)).')'; unset($atts['status']); } if ($section) { $where .= " AND Section in ('".join("','", do_list($section))."')"; unset($atts['section']); } if ($sort) { $where .=' ORDER BY '.$sort; unset($atts['sort']); } if ($limit) { $where .=' LIMIT '.$limit; unset($atts['limit']); } // Don't pass the remaining attributes we've already handled onto the article tag unset( $atts['label'], $atts['unlabel'], $atts['labeltag'], $atts['wraptag'], $atts['break'], $atts['class'], $atts['html_id'] ); $rs = getRows('SELECT *, unix_timestamp(Posted) as uPosted, unix_timestamp(Expires) as uExpires, unix_timestamp(LastMod) as uLastMod FROM '.PFX.'textpattern AS txp LEFT JOIN '.PFX.SMD_FEAT.' AS smdfeat ON txp.ID=smdfeat.feat_id WHERE '.$where); $out = array(); if ($rs) { foreach ($rs as $row) { $smd_featured_info['label'] = $row['label']; $smd_featured_info['title'] = $row['feat_title_html']; $smd_featured_info['description'] = $row['desc_html']; $atts['id'] = $row['ID']; $artout = article($atts, $thing); if ($artout) { $smd_prior_featured[] = $row['ID']; $out[] = $artout; } } } if ($out) { return (($labeltag) ? doLabel( ( ($label == '') ? $unlabel : $label), $labeltag ) : '') .doWrap($out, $wraptag, $break, $class, '', '', '', $html_id); } return ''; } // ------------------------ function smd_unfeatured($atts, $thing) { global $smd_prior_featured; $where = "1=1"; // Exclude previously seen articles if (!empty($smd_prior_featured)) { $where .= ' AND id NOT IN(' . join(',', $smd_prior_featured) . ')'; } $rs = safe_column('ID', 'textpattern', $where); $atts['id'] = join(',', $rs); $out = article($atts, $thing); return $out; } // ------------------------ function smd_featured_info($atts) { global $smd_featured_info; extract(lAtts(array( 'item' => '', ),$atts)); return (isset($smd_featured_info[$item]) ? $smd_featured_info[$item] : ''); } // ------------------------ function smd_if_featured($atts, $thing) { global $smd_featured_info, $thisarticle; extract(lAtts(array( 'id' => '', 'label' => '', ),$atts)); if ($id) { $id = join("','", do_list(doSlash($id))); } if (!$id && $thisarticle) { $id = $thisarticle['thisid']; } $where[] = "feat_id IN ('".$id."')"; if (isset($atts['label'])) { $label = explode(',', doSlash($label)); $lblwhere = array(); foreach ($label as $lbl) { $lblwhere[] = "'".trim($lbl)."'"; } if ($lblwhere) { $where[] = '( BINARY label IN (' . join(',', $lblwhere) . ') )'; } } $ret = safe_row('feat_id', SMD_FEAT, join(' AND', $where)); return parse(EvalElse($thing, $ret)); } // ------------------------ // Plugin-specific replacement strings - localise as required // TODO: make these into a textpack when plugin composer supports them function smd_featured_gTxt($what, $atts = array()) { $lang = array( 'by_label' => 'By label: ', 'by_name' => 'By name: ', 'control_panel' => 'Control panel', 'manage_lbl' => 'Click to select featured articles, which will be shown highlighted.', 'prefs' => 'Preferences', 'pref_boxsize' => 'Box size: ', 'pref_boxsizeby' => 'x', 'pref_display' => 'Display: ', 'pref_sort' => 'Sort by: ', 'prefs_some_explain' => 'This is either a new installation or a different version'.br.'of the plugin to one you had before.', 'prefs_some_opts' => 'Click "Install table" to add or update the table'.br.'leaving all existing data untouched.', 'prefs_some_tbl' => 'Not all table info available.', 'saved' => 'Article info updated', 'search_live' => 'Article live search', 'search_standard' => 'Article search', 'tab_name' => 'Featured articles', 'tbl_install_lbl' => 'Install table', 'tbl_installed' => 'Table installed', 'tbl_not_installed' => 'Table not installed', 'tbl_removed' => 'Table removed', 'tbl_not_removed' => 'Table not removed', 'textile' => 'Textile: ', 'textile_desc' => 'Description', 'textile_title' => 'Title', 'unfeature_confirm' => 'Sure to unfeature this article?', 'unlabelled' => '[unlabelled]', ); return strtr($lang[$what], $atts); }