# PLUGIN PREVIEW BY TEXTPATTERN.INFO
/*
adi_form_links - Admin-side form links
Written by Adi Gilbert
Released under the GNU General Public License
Version history:
0.4 - refixes for TXP 4.6
0.3.1 - fix: cope with default page not being called "default" in 4.6 (thanks jpdupont)
0.3 - fixes: to back up the wild claim made about TXP 4.6 in version 0.2
- code tidy up
0.2 - ignore invalid form names
- blacklist
- tested on TXP 4.6
0.1 - initial release (from an idea by Edoardo @wornout & thoroughly tested by Uli)
*/
global $event,$step,$adi_form_links_debug;
if (@txpinterface == 'admin') {
$adi_form_links_debug = 0;
adi_form_links_init($event,$step);
}
function adi_form_links_init($event,$step) {
global $prefs,$textarray,$adi_form_links_debug,$adi_form_links_url,$adi_form_links_prefs,$adi_form_links_blacklist,$adi_form_links_newname,$adi_form_links_txp460;
$adi_form_links_txp460 = (version_compare(txp_version,'4.6-dev','>='));
$adi_form_links_blacklist[] = 'smd_wrap,transform';
// $adi_form_links_blacklist[] = 'another_plugin,another_attribute';
if (!version_compare(txp_version,'4.5.0','>=')) return;
// plugin lifecycle
register_callback('adi_form_links_lifecycle','plugin_lifecycle.adi_form_links');
// plugin options
$adi_form_links_plugin_status = fetch('status','txp_plugin','name','adi_form_links',$adi_form_links_debug);
if ($adi_form_links_plugin_status) { // proper install - options under Plugins tab
add_privs('plugin_prefs.adi_form_links','1,2,6');
register_callback('adi_form_links_options','plugin_prefs.adi_form_links');
}
else { // txpdev - options under Extensions tab
add_privs('adi_form_links_options','1,2,6');
register_tab('extensions','adi_form_links_options','adi_form_links options');
register_callback('adi_form_links_options','adi_form_links_options');
}
// Textpack
$adi_form_links_url = array(
'textpack' => 'http://www.greatoceanmedia.com.au/files/adi_textpack.txt',
'textpack_download' => 'http://www.greatoceanmedia.com.au/textpack/download',
'textpack_feedback' => 'http://www.greatoceanmedia.com.au/textpack/?plugin=adi_form_links',
);
if (strpos($prefs['plugin_cache_dir'],'adi') !== FALSE) // use Adi's local version
$adi_form_links_url['textpack'] = $prefs['plugin_cache_dir'].'/adi_textpack.txt';
# --- BEGIN PLUGIN TEXTPACK ---
$adi_form_links_gtxt = array(
'adi_edit_form' => 'Edit form',
'adi_forms_referenced' => 'Forms referenced',
'adi_forms_used' => 'Forms used',
'adi_link_list' => 'Link list',
'adi_list_format' => 'List format',
'adi_none_found' => 'None found',
'adi_pref_update_fail' => 'Preference update failed',
'adi_textpack_fail' => 'Textpack installation failed',
'adi_textpack_feedback' => 'Textpack feedback',
'adi_textpack_online' => 'Textpack also available online',
'adi_update_prefs' => 'Update preferences',
);
# --- END PLUGIN TEXTPACK ---
// update $textarray
$textarray += $adi_form_links_gtxt;
// preferences & defaults
$adi_form_links_prefs = array(
'adi_form_links_type' => array('value' => 'list', 'input' => 'radio'), // 'list' or 'popup'
);
foreach ($adi_form_links_prefs as $adi_form_links_pref => $this_pref) {
$get_value = get_pref($adi_form_links_pref,'?'); // returns '?' if not set (but beware of cacheing)
if ($get_value != '?')
$adi_form_links_prefs[$adi_form_links_pref]['value'] = $get_value;
}
// some action
if (($event == "page") || ($event == 'form')) { // 'ere we go
// inject markup
if ($adi_form_links_txp460)
register_callback('adi_form_links_markup_46','admin_side','footer'); // markup in the footer, shifted by jQuery
else {
// callbacks - inject markup into Pages/Forms tab
register_callback('adi_form_links_list','page','',1);
register_callback('adi_form_links_list','form','',1);
}
// script
register_callback('adi_form_links_script','admin_side','head_end');
// new form link clicked in TXP 4.6?
$adi_form_links_newname = gps('adi_form_links_newname');
if ($adi_form_links_newname)
register_callback('adi_form_links_script2','admin_side','head_end');
if ($adi_form_links_debug) {
echo 'Event='.$event.',Step='.$step.br.br;
echo '$_GET=';
dmp($_GET);
echo '$_POST=';
dmp($_POST);
}
// style
register_callback('adi_form_links_style','admin_side','head_end');
}
}
function adi_form_links_style() {
// practical & stylish
echo
'<style type="text/css">
#adi_form_links { margin-top:1em }
#adi_form_links label { width:auto; float:left; margin:0 }
#adi_form_links select { float:left; margin:0 }
#adi_form_links input.smallerbox { margin:0 0 0 0.5em }
#adi_form_links .adi_form_links_disabled { color:#777 } /* explicitly grey out disabled options (for IE6/7) - still no good for iOS Safari NOW REDUNDANT? */
#adi_form_links p { margin:0 }
#adi_form_links ul { list-style:none; margin:0.5em 0 0; padding:0 0 1em }
#adi_form_links li { margin:0; padding:0 }
#adi_form_links li.adi_form_links_new a,
#adi_form_links option.adi_form_links_new { color:#777 }
/* TXP 4.6 */
@media (max-width: 47em) {
#adi_form_links label { float:none; display:block }
#adi_form_links select { float:none; margin:0.5em 0 1em }
#adi_form_links input.smallerbox { display:block; margin:0 }
}
</style>';
}
function adi_form_links_options($event,$step) {
// plugin options page
global $adi_form_links_debug,$adi_form_links_url,$textarray,$adi_form_links_prefs;
$message = '';
// step-tastic
if ($step == 'textpack') {
if (function_exists('install_textpack')) {
$adi_textpack = file_get_contents($adi_form_links_url['textpack']);
if ($adi_textpack) {
$result = install_textpack($adi_textpack);
$message = gTxt('textpack_strings_installed', array('{count}' => $result));
$textarray = load_lang(LANG); // load in new strings
}
else
$message = gTxt('adi_textpack_fail');
}
}
if ($step == 'update_prefs') {
$result = adi_form_links_update_prefs();
$result ? $message = gTxt('preferences_saved') : $message = gTxt('adi_pref_update_fail');
}
// generate page
if (!empty($message))
$message = '<strong>'.$message.'</strong>';
pagetop('adi_form_links '.gTxt('plugin_prefs'),$message);
// options
echo tag(
tag('adi_form_links '.gTxt('plugin_prefs'),'h2')
// preferences
.form(
tag(gTxt('edit_preferences'),'h3')
.graf(
tag(gTxt('adi_list_format'),'label',' for="adi_form_links_type"')
.sp.sp
.tag(
radio('adi_form_links_type','list',($adi_form_links_prefs['adi_form_links_type']['value'] == 'list'))
.sp
.gTxt('adi_link_list')
,'label'
)
.sp.sp
.tag(
radio('adi_form_links_type','popup',($adi_form_links_prefs['adi_form_links_type']['value'] == 'popup'))
.sp
.gTxt('tag_popup')
,'label'
)
)
.graf(fInput("submit","do_something",gTxt('adi_update_prefs'),"smallerbox"))
.eInput($event)
.sInput("update_prefs")
)
// textpack links
.graf(href(gTxt('install_textpack'),'?event='.$event.'&step=textpack'),' style="margin-top:3em"')
.graf(href(gTxt('adi_textpack_online'),$adi_form_links_url['textpack_download']))
.graf(href(gTxt('adi_textpack_feedback'),$adi_form_links_url['textpack_feedback']))
,'div'
,' style="text-align:center; margin-bottom:3em"'
);
if ($adi_form_links_debug) {
echo '<b>$adi_textpack ('.$adi_form_links_url['textpack'].'):</b>';
$adi_textpack = file_get_contents($adi_form_links_url['textpack']);
dmp($adi_textpack);
}
}
function adi_form_links_lifecycle($event,$step) {
// from cradle to grave
// $event: "plugin_lifecycle.adi_form_links"
// $step: "installed", "enabled", disabled", "deleted"
global $adi_form_links_debug,$adi_form_links_prefs;
$result = '?';
if ($step == 'deleted') {
// delete preferences
$res = TRUE;
foreach ($adi_form_links_prefs as $this_pref => $value)
$res = $res && safe_delete('txp_prefs',"name = '$this_pref'",$adi_form_links_debug);
$result = $res;
}
if ($adi_form_links_debug)
echo "Event=$event Step=$step Result=$result";
}
function adi_form_links_update_prefs() {
// trawl $_POST & update adi_form_links preferences
global $adi_form_links_prefs;
$per_user_prefs = TRUE;
$res = TRUE;
foreach ($adi_form_links_prefs as $adi_form_links_pref => $this_pref) {
if (array_key_exists($adi_form_links_pref,$_POST))
$new_value = $_POST[$adi_form_links_pref];
else
$new_value = '';
$res = $res && set_pref($adi_form_links_pref,$new_value,'adi_form_links',2,$adi_form_links_prefs[$adi_form_links_pref]['input'],0,$per_user_prefs);
$adi_form_links_prefs[$adi_form_links_pref]['value'] = $new_value;
}
return $res;
}
function adi_form_links_forms($name) {
// find the forms & generate the markup
global $event,$step,$adi_form_links_debug,$adi_form_links_prefs,$adi_form_links_blacklist,$adi_form_links_txp460;
$debug = '';
if ($adi_form_links_debug) $debug.= "FORM NAME:".br."supplied=$name";
if ($event == 'page') {
/* $step $name $newname
Initial page tab visit: - - - (the "default" page is the one linked to section 'default' - which may not be called 'default' in 4.6)
Edit page: - abc -
Save page: page_save abc -
Create page: page_new - -
Save new page: page_save - abc
Delete page: page_delete abc -
Copy/Duplicate page*: page_save abc xyz (4.6: $newname contains old name if user doesn't enter new one, even though name field contains "abc_copy")
*with/without modifications on the way
Rename page: (there is no rename page functionality)
*/
if (empty($step) && empty($name)) // initial page tab visit
$name = safe_field('page','txp_section',"name='default'"); // get $name from page assigned to section "default"
if ($step == 'page_new')
return ''; // otherwise it'll list default's form
$newname = gps('newname');
if ($step == 'page_save') { // save, add, copy or duplicate page
if (empty($name)) // add new page
$name = gps('newname');
if ($newname) // 4.6: duplicate page, need to retrieve new oage (user may have modified it before hitting duplicate)
$name = gps('newname');
}
if ($step == 'page_delete') // page delete, so default to default
$name = safe_field('page','txp_section',"name='default'"); // get $name from page assigned to section "default"
// retrieve page contents from DB
$row = safe_row('user_html','txp_page'," name='".$name."'");
$data = $row['user_html'];
}
else if ($event == 'form') {
/* $step $name $oldname (4.5) $newname (4.6)
Initial form tab visit: - - - - (== default)
Edit form: form_edit abc - -
Save form: form_save abc abc abc
Create form: form_create - - -
Save new form: form_save abc* - abc (* 4.6: $name empty)
Delete form: form_multi_edit - - -
Rename form*: form_save xyc* abc xyz (* 4.6: $name contains old name)
*with/without modifications on the way
*/
if (empty($step) && empty($name)) // initial form tab visit
$name = 'default';
if ($step == 'form_multi_edit') // form delete, so default to default
$name = 'default';
$newname = gps('newname');
if ($newname) // TXP 4.6 - save new or rename
$name = $newname;
// retrieve form contents from DB
$row = safe_row('Form','txp_form'," name='".$name."'");
if ($row)
$data = $row['Form'];
else
$data = '';
}
if ($adi_form_links_debug) $debug.= ", deduced=$name".br;
// get all tags from current page/form
$all_tags = adi_form_links_parse($data);
// sort out wheat from chaff
$forms = array();
$debug .= 'BLACKLIST:'.br;
$debug .= implode(br,$adi_form_links_blacklist);
$debug .= br.'TAGS, ATTS & VALUES (** is a pass):'.br;
foreach ($all_tags as $taginfo) {
$atts = adi_form_links_splat($taginfo['atts']); // get array of atts & values
if ($atts)
foreach ($atts as $att => $value) {
$this_tag = array();
if (preg_match("/.*form$/i",$att)) { // * "[something]form" attribute is a good start
$debug .= '*';
if (!preg_match("/[<>]/i",$value)) { // ** no embedded tags is the business
$pattern = '/[<>&"\']/';
// officially: anything goes as long as it's a string, and with out <>&"\'
// unofficially: Holy Cr@p! (fixed in 4.6)
if (trim($value) && is_string($value) && !preg_match($pattern,$value)) { // check valid name: basic format, but not blanks or single zero
$debug .= '*';
$this_tag['tag'] = $taginfo['tag'];
$this_tag['att'] = $att;
$this_tag['form'] = htmlentities($value);
if (array_search($this_tag['tag'].','.$this_tag['att'],$adi_form_links_blacklist) === FALSE)
$forms[] = $this_tag;
else
$debug .= ' (blacklisted) ';
}
else
$debug .= ' (invalid form name) ';
}
}
$debug .= ' [tag:'.$taginfo['tag'].', attr:'.$att.', form name:'.htmlentities($value).']'.br;
}
else // no attributes
$debug .= $taginfo['tag'].br;
}
if (!$adi_form_links_debug) $debug = '';
// generate select list & link list markup
$select_list = '';
$link_list = '<ul>';
foreach ($forms as $this_tag) {
$link_text = $this_tag['form'];
if (safe_row('name','txp_form'," name='".$this_tag['form']."'",$adi_form_links_debug)) { // existing form
$option_class = '';
$link_list .= '<li>'.elink('form','form_edit','name',$this_tag['form'],$link_text).' ('.$this_tag['tag'].')'.'</li>';
}
else { // form doesn't exist
$option_class = ' class="adi_form_links_new"';
if ($adi_form_links_txp460) // "name" var causes TXP 4.6 to go into form edit mode rather than form create, so jQuery will come into play
$link_list .= '<li class="adi_form_links_new">'.elink('form','form_create','adi_form_links_newname',$this_tag['form'],$link_text).' ('.$this_tag['tag'].')'.'</li>';
else
$link_list .= '<li class="adi_form_links_new">'.elink('form','form_create','name',$this_tag['form'],$link_text).' ('.$this_tag['tag'].')'.'</li>';
}
$select_list .= '<option'.$option_class.' value="'.$this_tag['form'].'">'.$this_tag['form'].' ('.$this_tag['tag'].')</option>';
}
$link_list .= '</ul>';
if ($forms)
if ($adi_form_links_prefs['adi_form_links_type']['value'] == 'list')
return $debug.$link_list;
else // popup
return $debug.tag('<option value=""> </option>'.$select_list,'select',' id="adi_form_links_forms" name="name"');
else
return $debug;
}
function adi_form_links_parse($thing) {
// get all tags & their attributes
// ripped off (& modified) from publish.php
$f = '@(</?txp:\w+(?:\s+\w+\s*=\s*(?:"(?:[^"]|"")*"|\'(?:[^\']|\'\')*\'|[^\s\'"/>]+))*\s*/?'.chr(62).')@s';
$t = '@:(\w+)(.*?)/?.$@s';
$parsed = preg_split($f, $thing, -1, PREG_SPLIT_DELIM_CAPTURE);
$level = 0;
$out = array();
$inside = '';
$istag = FALSE;
foreach ($parsed as $chunk)
{
if ($istag)
{
if ($level === 0) {
preg_match($t, $chunk, $tag);
if (substr($chunk, -2, 1) === '/')
{ # self closing
TRUE; // do nothing but keep for reference
}
else
{ # opening
$level++;
}
// $tag[1] = the tag, $tag[2] = the attributes
$out[] = array('tag' => trim($tag[1]), 'atts' => trim($tag[2]));
$out = array_merge($out,adi_form_links_parse($tag[2])); // parse tags within tags
}
else
{
if (substr($chunk, 1, 1) === '/')
{ # closing
if (--$level === 0)
{
$out = array_merge($out,adi_form_links_parse($inside)); // parse contained tags
$inside = '';
}
else
{
$inside .= $chunk;
}
}
elseif (substr($chunk, -2, 1) !== '/')
{ # opening inside open
++$level;
$inside .= $chunk;
}
else
{
$inside .= $chunk;
}
}
}
else
{
if ($level)
{
$inside .= $chunk;
}
}
$istag = !$istag;
}
return $out;
}
function adi_form_links_splat($text) {
// get tag attributes
// ripped off (& modified) from txplib_misc.php
$atts = array();
if (preg_match_all('@(\w+)\s*=\s*(?:"((?:[^"]|"")*)"|\'((?:[^\']|\'\')*)\'|([^\s\'"/>]+))@s', $text, $match, PREG_SET_ORDER))
{
foreach ($match as $m)
{
switch (count($m))
{
case 3:
$val = str_replace('""', '"', $m[2]);
break;
case 4:
$val = str_replace("''", "'", $m[3]);
break;
case 5:
$val = $m[4];
break;
}
$atts[strtolower($m[1])] = $val;
}
}
return $atts;
}
function adi_form_links_list() {
// arcane magic that gets adi_form_links's list into standard TXP tabs
ob_start('adi_form_links_inject');
}
function adi_form_links_inject($buffer) {
// another bit of the magic that gets adi_form_links's section popup into standard TXP tabs
global $DB,$event;
if(!isset($DB)) $DB = new db;
if ($event == 'page')
$pattern = '#id="page_form".*</form>#sU';
else if ($event == 'form')
$pattern = '#id="form_form".*</form>#sU';
else
return '';
$insert = 'adi_form_links_markup';
$buffer = preg_replace_callback($pattern, $insert, $buffer);
return $buffer;
}
function adi_form_links_markup($matches) {
// generate markup
global $adi_form_links_prefs;
$name = gps('name');
$forms_found = adi_form_links_forms($name);
if ($forms_found)
if ($adi_form_links_prefs['adi_form_links_type']['value'] == 'list') // link list
$markup = graf(strong(gTxt('adi_forms_referenced'))).$forms_found;
else // popup
$markup =
form(
tag(
tag(strong(gTxt('adi_forms_referenced')),'label',' for="adi_form_links_forms"')
.$forms_found
.fInput("submit","edit_form",gTxt('adi_edit_form'),"smallerbox")
.eInput("form")
.sInput("form_edit")
,'p')
);
else // none found
$markup = strong(gTxt('adi_forms_referenced')).br.gTxt('adi_none_found');
return $matches[0] // the admin page chunk, plus:
.tag(
$markup
,'div'
,' id="adi_form_links"'
);
}
function adi_form_links_markup_46($matches) {
// generate markup
global $adi_form_links_prefs;
$name = gps('name');
$forms_found = adi_form_links_forms($name);
if ($forms_found)
if ($adi_form_links_prefs['adi_form_links_type']['value'] == 'list') // link list
$markup = graf(strong(gTxt('adi_forms_referenced'))).$forms_found;
else // popup
$markup =
form(
tag(
tag(strong(gTxt('adi_forms_referenced')),'label',' for="adi_form_links_forms"')
.br
.$forms_found
.fInput("submit","edit_form",gTxt('adi_edit_form'),"smallerbox")
.eInput("form")
.sInput("form_edit")
,'p')
);
else // none found
$markup = strong(gTxt('adi_forms_referenced')).br.gTxt('adi_none_found');
echo tag(
$markup
,'div'
,' id="adi_form_links"'
);
}
function adi_form_links_script() {
// jQuery-ism
global $adi_form_links_debug,$adi_form_links_newname;
// markup shifty
echo <<<END_SCRIPT
<script type="text/javascript">
$(function() {
// adi_form_links
$("div#adi_form_links").appendTo($("#main_content")); // shift form links markup from footer
});
</script>
END_SCRIPT;
}
function adi_form_links_script2() {
// jQuery-ism
global $adi_form_links_debug,$adi_form_links_newname;
// new form name field inject for TXP 4.6
if ($adi_form_links_debug) echo "adi_form_links_newname=$adi_form_links_newname".n;
if ($adi_form_links_newname)
echo <<<END_SCRIPT
<script type="text/javascript">
// adi_form_links
$().ready(function() {
console.log("$adi_form_links_newname");
$("input#new_form").val("$adi_form_links_newname");
});
</script>
END_SCRIPT;
}