<?php

# PLUGIN PREVIEW BY TEXTPATTERN.INFO

/**
 * smd_article_stats
 *
 * A Textpattern CMS plugin for counting words in article fields and optionally displaying them to visitors
 *  -> Choose which fields to count on the admin side
 *  -> Customize where you want the count to be displayed
 *  -> Shows ID of currently edited article.
 *
 * @author Stef Dawson
 * @link   http://stefdawson.com/
 */

// TODO:
//  * TinyMCE -- accessing fields inside iframes?

if (@txpinterface == 'admin') {
    
$all_privs array_keys(get_groups());
    unset(
$all_privs[array_search('0'$all_privs)]); // Remove 'none'
    
$all_joined join(','$all_privs);

    
add_privs('smd_artstat_prefs'$all_joined);
    
add_privs('prefs.smd_artstat'$all_joined);
    
register_callback('smd_artstat_prefs''prefs'''1);
    
register_callback('smd_article_info''article');
    
$smd_ai_prefs smd_article_info_prefs();
    foreach (
$smd_ai_prefs as $key => $prefobj) {
        
register_callback('smd_article_info_pophelp''admin_help'$key);
    }
}

// Public side info
function smd_article_stats($atts$thing=NULL) {
    global 
$thisarticle;

    
assert_article();

    
extract(lAtts(array(
        
'wraptag'  => '',
        
'class'    => __FUNCTION__,
        
'break'    => '',
        
'label'    => '',
        
'labeltag' => '',
        
'item'     => '',
    ), 
$atts));

    
$out = array();

    
// item not specified? Use the array 'keys' from the pref
    
if (empty($item)) {
        
$fldList do_list(get_pref('smd_artstat_fields'));
        
$cfs getCustomFields();

        foreach (
$fldList as $fld) {
            
$fldInfo do_list($fld'->');
            
$field $fldInfo[0];
            if (
strpos($field'custom_') !== false) {
                
$cfnum str_replace('custom_'''$field);
                if (
array_key_exists($cfnum$cfs)) {
                    
$field $cfs[$cfnum];
                } else {
                    
// Bogus CF: skip it
                    
continue;
                }
            }
            
$item[] = strtolower($field);
        }
    } else {
        
$item do_list($item);
    }

    
$out[] = smd_article_info_count($item$thisarticle);

    return 
doLabel($label$labeltag).doWrap($out$wraptag$break$class);
}

// Admin-side info -- auto-updated via jQuery
function smd_article_info($event$step) {
    global 
$app_mode;

    
extract(gpsa(array('view')));

    include_once 
txpath.'/publish/taghandlers.php';
    if(!
$view || gps('save') || gps('publish')) {
        
$view 'text';
    }

    if (
$view == 'text') {
        
$screen_locs = array(
            
'none'                  => '',
            
'excerpt_below'         => 'jq|.excerpt|after',
            
'author_below'          => 'jq|.author|after',
            
'status_above'          => 'jq|#write-status|before',
            
'title_above'           => 'jq|#article-main|prepend',
            
'textfilter_help_above' => 'jq|#textfilter_group|before',
            
'textfilter_help_below' => 'jq|#textfilter_group|after'// For 4.6.x+
            
'textile_help_above'    => 'jq|#article-col-1|prepend',
            
'textile_help_below'    => 'jq|#textile_help|after'// For 4.5.x
        
);

        
// Check hidden pref and sanitize
        
$posn get_pref('smd_artstat_pos''status_above');
        
$posn = (array_key_exists($posn$screen_locs)) ? $posn 'status_above';

        
$placer explode('|'$screen_locs[$posn]);
        
doArray($placer'escape_js');

        
// Split and recombine to get rid of spaces
        // TODO: error detection if missing entries
        
$fldList do_list(get_pref('smd_artstat_fields''Body -> #body, Excerpt -> #excerpt'));
        
$fldAnchors = array('0'); // Placeholder since Status isn't a countable field, but we need it later
        
$db_fields = array('Status');

        foreach (
$fldList as $fld) {
            
$fldInfo do_list($fld'->');
            
$db_fields[] = $fldInfo[0];
            if (isset(
$fldInfo[1])) {
                
$fldAnchors[] = $fldInfo[1];
            }
        }

        
array_shift($fldAnchors); // Goodbye Status anchor
        
$js_fields escape_js(implode(','$fldAnchors));
        
$js_array_fields implode(','doArray(doArray($fldAnchors'escape_js'), 'doQuote'));

        
$id = (empty($GLOBALS['ID']) ? gps('ID') : $GLOBALS['ID']);

        if (empty(
$id)) {
            
$rs $db_fields;
        } else {
            
$rs safe_row(join(','doArray($db_fields'doSlash')), 'textpattern''ID='.doSlash($id));
        }

        
$idlink = (get_pref('smd_artstat_id') === '1') ? (($id && in_array($rs['Status'], array(STATUS_LIVESTATUS_STICKY))) ? href($idpermlinkurl_id($id)) : $id) : '';
        
$indiv = array();
        
$words 0;

        
array_shift($db_fields); // Goodbye Status field
        
foreach ($db_fields as $idx => $fld) {
            
$wc smd_article_info_count($fld$rs);
            
$words += $wc;
            
$indiv[] = '<span class="smd_article_stats_' $idx '">'.$wc.'</span>';
        }
        
gTxtScript(array('smd_artstat_word_singular''smd_artstat_word_plural'));
        
$singstring get_pref('smd_artstat_singular''1');
        
$singles do_list($singstring);
        
$out1 escape_js(
            
defined('PREF_PLUGIN')
                ? 
wrapGroup('smd_artstat''<span class="smd_article_stats_wc">'.$words.'</span> <span class="smd_article_stats_wd">'.(in_array($words$singles) ? gTxt('smd_artstat_word_singular') : gTxt('smd_artstat_word_plural')).'</span>: ( ' join(' / '$indiv) .' )'.(($idlink) ? ' | ' gTxt('id') .n$idlink ''), 'smd_artstat')
                : 
'<fieldset><legend>'.gTxt('smd_artstat_legend').'</legend><p><span class="smd_article_stats_wc">'.$words.'</span> <span class="smd_article_stats_wd">'.(in_array($words$singles) ? gTxt('smd_artstat_word_singular') : gTxt('smd_artstat_word_plural')).'</span>: ( ' join(' / '$indiv) .' )'.(($idlink) ? ' | ' gTxt('id') .n$idlink '').'</p></fieldset>'
        
);
        
$out2 script_js(<<<EOJS
jQuery(function() {
    var singlist = [
{$singstring}];

    jQuery("
{$js_fields}").keyup(function() {
        var flds = [
{$js_array_fields}];
        var wds = 0;
        var content = '';
        for (idx = 0; idx < flds.length; idx++) {
            if (jQuery(flds[idx]).length > 0) {
                content = jQuery(flds[idx]).val();
                content += (content.length > 0) ? " " : "";
                word_count = content.replace(/(<([^>]+)>)/ig,"").split(/\s+/).length-1
                jQuery(".smd_article_stats_"+idx).text(word_count);
                wds += word_count;
            }
        }

        jQuery(".smd_article_stats_wc").text(wds);
        jQuery(".smd_article_stats_wd").text(((jQuery.inArray(wds, singlist) > -1) ? textpattern.gTxt('smd_artstat_word_singular') : textpattern.gTxt('smd_artstat_word_plural')));
    }).keyup();
});
EOJS
        );

        if (
$placer[0] == 'jq' && $app_mode != 'async') {
            echo 
'<script type="text/javascript">jQuery(function() { jQuery("'.$placer[1].'").'.$placer[2].'(\''.$out1.'\'); });</script>'.$out2;
        }
    }
}

// Get pophelp content from stefdawson.com
function smd_article_info_pophelp($evt$stp$ui$vars) {
    return 
str_replace(HELP_URL'http://stefdawson.com/downloads/support/'$ui);
}

// Install prefs if they don't already exist
function smd_artstat_prefs($evt$stp) {
    
$smd_ai_prefs smd_article_info_prefs();
    foreach (
$smd_ai_prefs as $key => $prefobj) {
        if (
get_pref($key) === '') {
            
set_pref($keydoSlash($prefobj['default']), 'smd_artstat'$prefobj['type'], $prefobj['html'], $prefobj['position'], $prefobj['visibility']);
        }
    }
}

// Only render the pref if enough privs exist
function smd_artstat_restricted($key$val) {
    global 
$txp_user;
    static 
$smd_artstat_privs = array();

    if (
array_key_exists($txp_user$smd_artstat_privs)) {
        
$privs $smd_artstat_privs[$txp_user];
    } else {
        
$safe_user doSlash($txp_user);
        
$privs safe_field('privs''txp_users'"name='$safe_user'");
        
$smd_artstat_privs[$txp_user] = $privs;
    }
   if (
$privs === '1') {
        return 
fInput('text'$key$val''''''INPUT_REGULAR);
    } else {
        return 
gTxt('smd_artstat_set_by_admin');
    }
}
// Render the position pref
function smd_artstat_pos($key$val) {
    
$smd_ai_prefs smd_article_info_prefs();
    
$obj $smd_ai_prefs[$key];
    return 
selectInput($key$obj['content'], $val);
}
// Settings for the plugin
// TODO: Use PREF_PLUGIN constant after 4.6.0 released
function smd_article_info_prefs() {
    
$smd_ai_prefs = array(
        
'smd_artstat_fields' => array(
            
'html'       => 'smd_artstat_restricted',
            
'type'       => PREF_ADVANCED,
            
'position'   => 10,
            
'default'    => 'Body -> #body, Excerpt -> #excerpt',
            
'group'      => 'smd_artstat_settings',
            
'visibility' => PREF_GLOBAL,
        ),
        
'smd_artstat_pos' => array(
            
'html'       => 'smd_artstat_pos',
            
'type'       => PREF_ADVANCED,
            
'position'   => 20,
            
'content'    => array(
                
'none'                  => gTxt('none'),
                
'excerpt_below'         => gTxt('smd_artstat_pos_below_excerpt'),
                
'author_below'          => gTxt('smd_artstat_pos_below_author'),
                
'status_above'          => gTxt('smd_artstat_pos_above_status'),
                
'title_above'           => gTxt('smd_artstat_pos_above_title'),
                
'textile_help_above'    => gTxt('smd_artstat_pos_above_textile'),
//                'textfilter_help_above' => gTxt('smd_artstat_pos_above_textfilter'), // Uncomment after 4.6.0 release and remove textile_help_above. Upgrade anyone using this setting to the new one automatically
                
'textile_help_below'    => gTxt('smd_artstat_pos_below_textile'),
//                'textfilter_help_below' => gTxt('smd_artstat_pos_below_textfilter'), // Uncomment after 4.6.0 release and remove textile_help_below. Upgrade anyone using this setting to the new one automatically
                
),
            
'default'    => 'status_above',
            
'group'      => 'smd_artstat_settings',
            
'visibility' => PREF_PRIVATE,
        ),
        
'smd_artstat_id' => array(
            
'html'       => 'yesnoradio',
            
'type'       => PREF_ADVANCED,
            
'position'   => 30,
            
'default'    => '0',
            
'group'      => 'smd_artstat_settings',
            
'visibility' => PREF_PRIVATE,
        ),
        
'smd_artstat_singular' => array(
            
'html'       => 'smd_artstat_restricted',
            
'type'       => PREF_ADVANCED,
            
'position'   => 40,
            
'default'    => '1',
            
'group'      => 'smd_artstat_settings',
            
'visibility' => PREF_GLOBAL,
        ),
    );

    return 
$smd_ai_prefs;
}

// Library function to count words in the given field items
function smd_article_info_count($item$from) {
    
$words 0;
    
$notags '/(<([^>]+?)>)/';

    
$item is_array($item) ? $item : array($item);
    foreach (
$item as $whatnot) {
        
$content = (isset($from[$whatnot])) ? preg_replace($notags''trim($from[$whatnot])) . ((strlen($from[$whatnot])==0) ? '' ' ') : '';
        if (
$content) {
            
$words += preg_match_all('@\s+@'$content$m);
        }
    }
    return 
$words;
}