// TODO: // Use an array like $types = array( 'int' => array( sql_type='INTEGER', widget="TEXT", widget_constraint="is_integer" ), ); // --> Populate the select box from this array // Add 'index' checkbox to allow an Index to be added to a meta column // Ability to specify wildcards/matches for items/authors in the client tag // Specify tooltip extended bio information in prefs if (@txpinterface == 'admin') { add_privs('smd_bio', '1'); register_tab('extensions', 'smd_bio', smd_bio_gTxt('admin_tab')); register_callback('smd_bio', 'smd_bio'); register_callback('smd_bio_fields', 'author_ui', 'extend_detail_form'); register_callback('smd_bio_admin_js', 'admin_side', 'head_end'); // Note these are all pre TXP's involvement register_callback('smd_bio_save', 'admin', 'author_save', 1); register_callback('smd_bio_save', 'admin', 'author_save_new', 1); register_callback('smd_bio_delete', 'admin', 'admin_multi_edit', 1); } $step = gps('step'); if ($step == 'smd_bio_get_image') { smd_bio_get_image(); } if ($step == 'smd_bio_get_ebio') { smd_bio_get_ebio(); } global $smd_bio_types; $smd_bio_types = array( 'text_input' => 'Text box', 'list' => 'Select list', 'radio' => 'Radio set', 'yesnoradio' => 'Yes/no radio', 'checkbox' => 'Checkbox(es)', 'textarea' => 'Text area', 'image' => 'Image', 'datetime' => 'Date/Time' ); if (!defined('SMD_BIO')) { define("SMD_BIO", 'smd_bio'); } if (!defined('SMD_BIO_META')) { define("SMD_BIO_META", 'smd_bio_meta'); } // ************************ // ADMIN -> USERS TAB // ------------------------ function smd_bio_fields($evt, $stp, $mt, $data) { $out = $vals = array(); $rstep = gps('step'); if(smd_bio_table_exist()) { if ($rstep == 'author_edit') { extract(gpsa(array('user_id'))); // Shame we have to double de-clutch here but we can't index on user_id unfortunately ('cos when // inserting new users, the bio functions run _BEFORE_ an auto_increment ID has been generated by TXP) $uname = safe_field('name','txp_users',"user_id = '$user_id'"); $vals = safe_row('*', SMD_BIO, "user_ref='$uname'"); } $widgets = safe_rows('*', SMD_BIO_META, '1=1 ORDER BY position'); $tdac = ' class="noline"'; $tdac_image = ' class="noline smd_bio_image_cell"'; foreach ($widgets as $widget) { $val = ($vals && isset($vals[$widget['name']])) ? $vals[$widget['name']] : $widget['val']; $title = ($widget['title']) ? $widget['title'] : $widget['name']; $sizeopts = do_list($widget['size']); $size1 = ($sizeopts[0] > 0) ? $sizeopts[0] : ''; $size2 = (isset($sizeopts[1]) && $sizeopts[1] > 0) ? $sizeopts[1] : ''; $name = 'smd_bio_'.$widget['name']; switch($widget['type']) { case 'list': $selv = smd_bio_splitval($widget['val']); list($selv, $dflt) = smd_bio_get_default($selv, $val); $out[] = tr(fLabelCell($title).tda(selectInput($name, $selv, $dflt, false, '', $name), $tdac), ' class="smd_bio_select '.$name.'"'); break; case 'radio': $selv = smd_bio_splitval($widget['val']); list($selv, $dflt) = smd_bio_get_default($selv, $val); $out[] = tr(fLabelCell($title).tda(radioSet($selv, $name, $dflt), $tdac), ' class="smd_bio_radio '.$name.'"'); break; case 'yesnoradio': $out[] = tr(fLabelCell($title).tda(yesnoRadio($name, $val), $tdac), ' class="smd_bio_radio '.$name.'"'); break; case 'checkbox': $selv = smd_bio_splitval($widget['val']); $val = ($vals && isset($vals[$widget['name']])) ? $vals[$widget['name']] : ''; $checkedVals = do_list($val); $items = array(); foreach ($selv as $idx => $lbl) { // Not using checkbox() because it doesn't support onclick $items[] = ''.$lbl; } $out[] = tr(fLabelCell($title).tda(join('', $items), $tdac), ' class="smd_bio_checkbox '.$name.'"').fInput('hidden',$name,$val,'','','','','',$name); break; case 'textarea': // Not using text_area() because it forces inline styled width/height which should be in CSS $size1 = ($size1 == '' || $size1 == 0) ? 40 : $size1; $size2 = ($size2 == '' || $size2 == 0) ? 5 : $size2; $out[] = tr(fLabelCell($title).tda('', $tdac), ' class="smd_bio_textarea '.$name.'"'); break; case 'image': $parent = $widget['val']; $val = ($vals && isset($vals[$widget['name']])) ? $vals[$widget['name']] : ''; $where = ($parent) ? "category='$parent'" : '1=1'; $tree = safe_rows('*', 'txp_image', $where); $selv = array(); foreach ($tree as $row) { $selv[$row['id']] = $row['name']; } $out[] = tr(fLabelCell($title).tda(''.selectInput($name.'_list', $selv, $val, true, '').'
', $tdac_image. ' id="'.$name.'"'), ' class="smd_bio_image_row '.$name.'"'); break; case 'datetime': case 'text_input': // Not using fInput() because it has no MAXLENGTH property $size1 = ($size1 == '' || $size1 == 0) ? 25 : $size1; $size2 = ($size2 == '' || $size2 == 0) ? $size1 : $size2; $out[] = tr(fLabelCell($title).tda('', $tdac), ' class="smd_bio_text_input '.$name.'"'); break; } } } return join('', $out); } // ------------------------ // Read a name/val array and remove any [*] marker which indicates a default item function smd_bio_get_default($list, $curr) { $out = array(); $dflt = $new_dflt = ''; foreach ($list as $item => $value) { if (($pos = strpos($value, '[*]')) !== false) { $out[$item] = substr($value, 0, $pos); $new_dflt = $item; } else { $out[$item] = $value; } if ($item == $curr) { $dflt = $item; } } $dflt = ($dflt) ? $dflt : $new_dflt; return array($out, $dflt); } // ------------------------ // AJAX calls function smd_bio_get_image() { global $img_dir; $id = gps('id'); if ($id) { $rs = safe_row('*', 'txp_image', "id = '$id'"); extract($rs); $out = array(); $out['thumb'] = ($thumbnail) ? hu.$img_dir.'/'.$id.'t'.$ext : ''; $out['image'] = hu.$img_dir.'/'.$id.$ext; $out['w'] = $w; $out['h'] = $h; $out['thw'] = ($thumb_w) ? $thumb_w : ''; $out['thh'] = ($thumb_h) ? $thumb_h : ''; send_xml_response($out); } else { send_xml_response(); } } // ------------------------ // IMPORTANT: constants NOT used for table names function smd_bio_get_ebio() { include_once txpath.'/publish/taghandlers.php'; $id = gps('id'); $core = array('user_ref'); $rs = safe_row('*', 'smd_bio', "user_ref = '$id'"); $meta = safe_rows('*', 'smd_bio_meta', "1=1"); // $include = array_merge($core, array('mug', 'cell', 'department')); // TODO: get these from prefs/meta table $allowed_types = array('text_input', 'textarea', 'datetime'); $out = array(); foreach ($rs as $idx => $val) { // if (in_array($idx, $include)) { if (in_array($idx, $core)) { $out[$idx] = doSlash($val); } else { foreach($meta as $row) { if ($row['name'] == $idx) { if ($row['type'] == "image") { $out[$idx] = 'smd_image::'.thumbnail(array('id'=> $val)); } else if (in_array($row['type'], $allowed_types)) { $out[$idx] = $row['title'].'::'.htmlspecialchars(strip_tags($val), ENT_QUOTES); } break; } } } // } } send_xml_response($out); } // ------------------------ function smd_bio_admin_js($evt, $stp) { global $event; if ($event != 'admin' && $event != 'smd_bio') { return false; } $css = safe_field('css', 'txp_css', "name='smd_bio'"); if ($css) { $css = ''; } $css .= <<"+ tt +"
"); jQuery("#tooltip") .css("top",(e.pageY - xOffset) + "px") .css("left",(e.pageX + yOffset) + "px") .fadeIn("fast"); } }, function() { jQuery(this).parent().attr("title", tt); jQuery("#tooltip").remove(); }); hovItem.mousemove(function(e) { jQuery("#tooltip") .css("top",(e.pageY - xOffset) + "px") .css("left",(e.pageX + yOffset) + "px"); }); }); // Grey out the Size box for those items that don't use it jQuery("#page-smd_bio .list[name='type']").change(function() { var theType = jQuery("#page-smd_bio .list[name='type'] option:selected").val(); var dest = "#page-smd_bio input[name='size']"; if (theType == 'list' || theType == 'radio' || theType == 'yesnoradio' || theType == 'checkbox') { jQuery(dest).attr("disabled", true); jQuery(dest).parent().prev().css("color", '#999'); } else { jQuery(dest).attr("disabled", false); jQuery(dest).parent().prev().css("color", ''); } }).change(); // Pop up the help tooltips based on the current Type jQuery(".pophelp.smd_bio_size").hover( function(e) { var theType = jQuery("#page-smd_bio .list[name='type'] option:selected").val(); spanid = 'span#smd_bio_size_help_'+theType; this.title = jQuery(spanid).attr("title"); }, function(e) { this.title = ''; } ); jQuery(".pophelp.smd_bio_val").hover( function(e) { var theType = jQuery("#page-smd_bio .list[name='type'] option:selected").val(); spanid = 'span#smd_bio_val_help_'+theType; this.title = jQuery(spanid).attr("title"); }, function(e) { this.title = ''; } ); }); //]]> {$css} EOJS; } // ------------------------ // Make the name/val pairs for selectInput / radio / checkbox sets function smd_bio_splitval($val) { $selv = array(); $wvals = explode(',', $val); foreach ($wvals as $wval) { $prts = explode('=>', $wval); if (count($prts) == 1) { $prts[1] = $prts[0]; $prts[0] = smd_bio_sanitize($prts[0]); } $selv[trim($prts[0])] = trim($prts[1]); } return $selv; } // ------------------------ // Super-sanitize the passed value so we can make variable names from the returned string function smd_bio_sanitize($val) { return strtolower(str_replace("-", "_", sanitizeForUrl($val))); } // ------------------------ function smd_bio_save($evt, $stp) { global $prefs; if (smd_bio_table_exist()) { $targetvars = array(); extract(doSlash(psa(array('privs', 'name', 'email', 'RealName', 'user_id')))); if (get_pref('smd_bio_sanitize_name', 0) > 0) { // Sanitize and pass the new name forward to the actual txp_user save routine $name = strtolower(sanitizeForUrl($name)); $_POST['name'] = $name; } $length = function_exists('mb_strlen') ? mb_strlen($name, '8bit') : strlen($name); if (($user_id || $name) and $length <= 64 and is_valid_email($email)) { foreach ($_POST as $idx => $item) { if (strpos($idx, 'smd_bio_') === 0) { $targetvars[] = $idx; } } // Double de-clutch again... dammit :-( $user_id = gps('user_id'); if ($user_id) { $user_ref = safe_field('name','txp_users',"user_id = '$user_id'"); } else { $user_ref = $name; } extract(gpsa($targetvars)); $bcols = getThings('describe `'.PFX.SMD_BIO.'`'); $sqlSet = array(); foreach ($targetvars as $var) { $colname = str_replace('smd_bio_', '', $var); if (in_array($colname, $bcols)) { $sqlSet[] = "`$colname` = '".doSlash($$var)."'"; } } if ($sqlSet) { $rs = safe_upsert(SMD_BIO, join(',', $sqlSet), "`user_ref` = '$user_ref'"); } } } } // ------------------------ function smd_bio_delete($evt, $stp) { global $txp_user; if (smd_bio_table_exist()) { // Since we are executing 'pre' delete we need to unfortunately duplicate some of the checks // from txp_admin.php so we minimise the opportunity to delete someone by mistake $selected = ps('selected'); $method = ps('edit_method'); if (!$selected or !is_array($selected)) { return; } if ($method != 'delete') { return; } $names = safe_column('name', 'txp_users', "name IN ('".join("','", doSlash($selected))."') AND name != '".doSlash($txp_user)."'"); if (!$names) return; $assign_assets = ps('assign_assets'); if ($assign_assets === '') { return; } elseif (in_array($assign_assets, $names)) { return; } else { // All the checks passed -- do it safe_delete(SMD_BIO, "user_ref IN ('".join("','", doSlash($names))."')"); } } } // ************************ // BIO CONFIGURATION // ------------------------ // Tab handler function smd_bio($event, $step) { if(!$step or !in_array($step, array( 'smd_bio_meta_add', 'smd_bio_meta_del', 'smd_bio_meta_save', ))) { smd_bio_config(''); } else $step(); } // ------------------------ function smd_bio_config($message) { if (!smd_bio_table_exist()) { smd_bio_install(''); exit; } pagetop(smd_bio_gTxt('admin_tab'), $message); echo smd_bio_meta_edit(); echo smd_bio_meta_list(); } // ------------------------ function smd_bio_meta_edit() { global $smd_bio_types; $vars = array('step', 'id', 'title', 'name', 'type', 'size', 'val', 'position'); $rs = array(); extract(gpsa($vars)); if ($id && $step == 'meta_edit') { $id = assert_int($id); $rs = safe_row('*', SMD_BIO_META, "id = $id"); extract($rs); } if ($step == 'smd_bio_meta_save' || $step == 'smd_bio_meta_add' || $step == 'smd_bio_meta_del') { foreach ($vars as $var) { $$var = ''; } } $caption = smd_bio_gTxt(($step == 'meta_edit') ? 'meta_edit' : 'meta_add'); // Make the name/val pairs for selectInput $selv = array(); foreach ($smd_bio_types as $widx => $wval) { $selv[$widx] = $wval; } return form( hed($caption, 3,' style="text-align: center;"'). startTable('edit', '', 'edit-pane'). tr( fLabelCell('name'). ($id && $step == 'meta_edit' ? td(strong($name)) : fInputCell('name', $name)) ). tr( fLabelCell('title'). fInputCell('title', $title) ). tr( fLabelCell('type'). td(selectInput('type', $selv, $type, false)) ). tr( fLabelCell(smd_bio_gTxt('size')). fInputCell('size', $size).td(tag(smd_bio_gTxt('help'), 'a', ' class="pophelp smd_bio_size"')) ). tr( fLabelCell('value'). td(text_area('val', '50', '128', $val)).td(tag(smd_bio_gTxt('help'), 'a', ' class="pophelp smd_bio_val"')) ). tr( fLabelCell(smd_bio_gTxt('position')). fInputCell('position', $position) ). tr( td(). td( fInput('submit', '', gTxt('save'), 'publish') ) ). endTable(). eInput('smd_bio'). ($id ? hInput('id', $id).hInput('name', $name).sInput('smd_bio_meta_save') : sInput('smd_bio_meta_add')). tag(' ', 'span', ' id="smd_bio_size_help_text_input" title="'.smd_bio_gTxt('sizehelp_text_input').'"'). tag(' ', 'span', ' id="smd_bio_size_help_list" title="'.smd_bio_gTxt('help_unused').'"'). tag(' ', 'span', ' id="smd_bio_size_help_radio" title="'.smd_bio_gTxt('help_unused').'"'). tag(' ', 'span', ' id="smd_bio_size_help_yesnoradio" title="'.smd_bio_gTxt('help_unused').'"'). tag(' ', 'span', ' id="smd_bio_size_help_checkbox" title="'.smd_bio_gTxt('help_unused').'"'). tag(' ', 'span', ' id="smd_bio_size_help_textarea" title="'.smd_bio_gTxt('sizehelp_textarea').'"'). tag(' ', 'span', ' id="smd_bio_size_help_image" title="'.smd_bio_gTxt('sizehelp_image').'"'). tag(' ', 'span', ' id="smd_bio_size_help_datetime" title="'.smd_bio_gTxt('sizehelp_text_input').'"'). tag(' ', 'span', ' id="smd_bio_val_help_text_input" title="'.smd_bio_gTxt('valhelp_text_input').'"'). tag(' ', 'span', ' id="smd_bio_val_help_list" title="'.smd_bio_gTxt('valhelp_lrc').'"'). tag(' ', 'span', ' id="smd_bio_val_help_radio" title="'.smd_bio_gTxt('valhelp_lrc').'"'). tag(' ', 'span', ' id="smd_bio_val_help_yesnoradio" title="'.smd_bio_gTxt('valhelp_ynr').'"'). tag(' ', 'span', ' id="smd_bio_val_help_checkbox" title="'.smd_bio_gTxt('valhelp_lrc').'"'). tag(' ', 'span', ' id="smd_bio_val_help_textarea" title="'.smd_bio_gTxt('valhelp_text_input').'"'). tag(' ', 'span', ' id="smd_bio_val_help_image" title="'.smd_bio_gTxt('valhelp_image').'"'). tag(' ', 'span', ' id="smd_bio_val_help_datetime" title="'.smd_bio_gTxt('valhelp_text_input').'"') ); } // ------------------------ function smd_bio_meta_list() { global $smd_bio_types; extract(gpsa(array('sort', 'dir', 'crit', 'search_method'))); if ($sort === '') $sort = get_pref('smd_bio_meta_sort_column', 'name'); if ($dir === '') $dir = get_pref('smd_bio_meta_sort_dir', 'asc'); $dir = ($dir == 'desc') ? 'desc' : 'asc'; if (!in_array($sort, array('name', 'title', 'type', 'size', 'val', 'position'))) $sort = 'position'; $sort_sql = $sort.' '.$dir; set_pref('smd_bio_meta_sort_column', $sort, 'smd_bio', 2, '', 0, PREF_PRIVATE); set_pref('smd_bio_meta_sort_dir', $dir, 'smd_bio', 2, '', 0, PREF_PRIVATE); $switch_dir = ($dir == 'desc') ? 'asc' : 'desc'; $rs = safe_rows_start('*', SMD_BIO_META, '1 = 1 ORDER BY '.$sort_sql); if ($rs) { echo ''; } } // ------------------------ function smd_bio_meta_make_list($val) { $wvals = do_list($val, '\r\n'); if (count($wvals) == 1) { $wvals = do_list($val); } return join(', ', doArray($wvals, 'trim')); } // ------------------------ function smd_bio_meta_save() { extract(doSlash(psa(array('id', 'name', 'title', 'type', 'size', 'val', 'position')))); $id = assert_int($id); $val = smd_bio_meta_make_list($val); $rs = safe_update(SMD_BIO_META, " title = '$title', type = '$type', size = '$size', val = '$val', position = '$position'", "id = $id" ); if ($rs) { smd_bio_config( smd_bio_gTxt('meta_updated', array('{name}' => $name)) ); } } // ------------------------ function smd_bio_meta_add() { extract(doSlash(psa(array('name', 'title', 'type', 'size', 'val', 'position')))); $name = smd_bio_sanitize($name); if (!empty($name) && smd_bio_meta_check($name)) { $size = (empty($size)) ? 25 : $size; //TODO: make the selection of column more intelligent based on the given type if ($type == 'textarea') { $asize = '4096'; //TODO: Find a way to user specify this $coltype = 'text'; } else { $asize = '64'; //TODO: Find a way to user specify this $coltype = 'varchar'; } $ret = safe_alter(SMD_BIO, "ADD `$name` $coltype($asize) NULL"); $val = smd_bio_meta_make_list($val); if ($ret) { $rs = safe_insert(SMD_BIO_META, " name = '$name', title = '$title', type = '$type', size = '$size', val = '$val', position = '$position' "); if ($rs) { smd_bio_config(smd_bio_gTxt('meta_added')); return; } } } smd_bio_config(array(smd_bio_gTxt('meta_not_added'), E_ERROR)); } // ------------------------ function smd_bio_meta_del() { extract(gpsa(array('id','name'))); $id = assert_int($id); $message = smd_bio_gTxt('meta_not_deleted'); $exists = smd_bio_meta_check($name); $ret = @safe_alter(SMD_BIO, "DROP COLUMN `$name`"); if ($ret || $exists) { $ret = safe_delete(SMD_BIO_META, "id='$id'"); $message = smd_bio_gTxt('meta_deleted'); } smd_bio_config($message); } // ------------------------ function smd_bio_meta_check($col) { $ucols = getThings('describe `'.PFX.'txp_users`'); $bcols = getThings('describe `'.PFX.SMD_BIO.'`'); $cols = array_merge($ucols, $bcols); return (!in_array($col, $cols)); } // ************************ // TABLE GENERATION // ------------------------ function smd_bio_table_exist() { if (gps('debug')) { echo "++ TABLE ".SMD_BIO_META." HAS ".count(@safe_show('columns', SMD_BIO_META))." COLUMNS;"; } return(@safe_show('columns', SMD_BIO_META)); } // ------------------------ function smd_bio_install($message) { global $smd_bio_types; $version = mysql_get_server_info(); $GLOBALS['txp_err_count'] = 0; if ($version < "4.1.2") { $GLOBALS['txp_err_count']++; trigger_error("smd_bio requires MySQL v4.1.2 or greater."); } else { $ret = ''; $sql = array(); $sql[] = "CREATE TABLE IF NOT EXISTS `".PFX.SMD_BIO."` ( `user_ref` varchar(64) NOT NULL default '', UNIQUE KEY `user_ref` (`user_ref`) ) ENGINE=MyISAM PACK_KEYS=1 "; $sql[] = "CREATE TABLE IF NOT EXISTS `".PFX.SMD_BIO_META."` ( `id` int(4) NOT NULL auto_increment, `title` varchar(64) NULL default '', `name` varchar(64) NOT NULL default '', `type` set(".doQuote(join("','", array_keys($smd_bio_types))).") NOT NULL default 'text_input', `size` varchar(10) NULL default 0, `val` text NULL default '', `position` tinyint(3) NULL default 0, PRIMARY KEY (`id`), UNIQUE KEY (`name`) ) ENGINE=MyISAM AUTO_INCREMENT=1"; 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()."