PageRenderTime 241ms CodeModel.GetById 43ms RepoModel.GetById 2ms app.codeStats 1ms

/~enabled/ied_plugin_composer.php

https://bitbucket.org/mrdale/txp-plugins
PHP | 3921 lines | 3026 code | 449 blank | 446 comment | 506 complexity | a0783449ec6e81388632c1026390cdfb MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. // This is a PLUGIN TEMPLATE for Textpattern CMS.
  3. // Copy this file to a new name like abc_myplugin.php. Edit the code, then
  4. // run this file at the command line to produce a plugin for distribution:
  5. // $ php abc_myplugin.php > abc_myplugin-0.1.txt
  6. // Plugin name is optional. If unset, it will be extracted from the current
  7. // file name. Plugin names should start with a three letter prefix which is
  8. // unique and reserved for each plugin author ("abc" is just an example).
  9. // Uncomment and edit this line to override:
  10. $plugin['name'] = 'ied_plugin_composer';
  11. // Allow raw HTML help, as opposed to Textile.
  12. // 0 = Plugin help is in Textile format, no raw HTML allowed (default).
  13. // 1 = Plugin help is in raw HTML. Not recommended.
  14. # $plugin['allow_html_help'] = 1;
  15. $plugin['version'] = '1.05';
  16. $plugin['author'] = 'Yura Linnyk / Stef Dawson / Steve Dickinson';
  17. $plugin['author_uri'] = 'http://stefdawson.com/';
  18. $plugin['description'] = 'Create, publish and edit plugins from within Textpattern';
  19. // Plugin load order:
  20. // The default value of 5 would fit most plugins, while for instance comment
  21. // spam evaluators or URL redirectors would probably want to run earlier
  22. // (1...4) to prepare the environment for everything else that follows.
  23. // Values 6...9 should be considered for plugins which would work late.
  24. // This order is user-overrideable.
  25. $plugin['order'] = '5';
  26. // Plugin 'type' defines where the plugin is loaded
  27. // 0 = public : only on the public side of the website (default)
  28. // 1 = public+admin : on both the public and admin side
  29. // 2 = library : only when include_plugin() or require_plugin() is called
  30. // 3 = admin : only on the admin side (no AJAX)
  31. // 4 = admin+ajax : only on the admin side (AJAX supported)
  32. // 5 = public+admin+ajax : on both the public and admin side (AJAX supported)
  33. $plugin['type'] = '5';
  34. // Plugin "flags" signal the presence of optional capabilities to the core plugin loader.
  35. // Use an appropriately OR-ed combination of these flags.
  36. // The four high-order bits 0xf000 are available for this plugin's private use
  37. if (!defined('PLUGIN_HAS_PREFS')) define('PLUGIN_HAS_PREFS', 0x0001); // This plugin wants to receive "plugin_prefs.{$plugin['name']}" events
  38. if (!defined('PLUGIN_LIFECYCLE_NOTIFY')) define('PLUGIN_LIFECYCLE_NOTIFY', 0x0002); // This plugin wants to receive "plugin_lifecycle.{$plugin['name']}" events
  39. $plugin['flags'] = '3';
  40. // Plugin 'textpack' is optional. It provides i18n strings to be used in conjunction with gTxt().
  41. // Syntax:
  42. // ## arbitrary comment
  43. // #@event
  44. // #@language ISO-LANGUAGE-CODE
  45. // abc_string_name => Localized String
  46. /** Uncomment me, if you need a textpack
  47. $plugin['textpack'] = <<<EOT
  48. #@admin
  49. #@language en-gb
  50. abc_sample_string => Sample String
  51. abc_one_more => One more
  52. #@language de-de
  53. abc_sample_string => Beispieltext
  54. abc_one_more => Noch einer
  55. EOT;
  56. **/
  57. // End of textpack
  58. if (!defined('txpinterface'))
  59. @include_once('zem_tpl.php');
  60. # --- BEGIN PLUGIN CODE ---
  61. // <?php
  62. /**
  63. * ied_plugin_composer
  64. *
  65. * A Textpattern CMS plugin for writing, editing and sharing plugins
  66. * -> Create and edit admin-side or public plugins
  67. * -> Supports plugin lifecycle events and prefs
  68. * -> Supports Textpacks
  69. * -> Optional syntax checker on save
  70. *
  71. * @author Yura Linnyk
  72. * @author Stef Dawson
  73. * @author Steve Dickinson
  74. * @link http://stefdawson.com/
  75. */
  76. // TODO:
  77. // * Use href() (from 4.6.+) for anchor creation to avoid double-encoded ampersands
  78. // * Figure out why syntax checker doesn't jump to line number sometimes (AJAX fails with error but it's not handled)
  79. // * Fix CSS/Markup so Textpack strings twisty label doesn't range right
  80. // * Show which langs have installed strings in the distribution section so the correct langs in the select list can be chosen
  81. // * Find out why uploading PHP files sometiems throws an error even though it succeeds
  82. // * jQuery on editor dropdowns in setup
  83. // * phpdoc
  84. global $ied_plugin_globals;
  85. $ied_plugin_globals = array(
  86. 'css_start' => '<!--',
  87. 'css_end' => '-->',
  88. 'dlm_start' => '#',
  89. 'dlm_end' => '',
  90. 'start' => ' --- BEGIN PLUGIN SECTION ---',
  91. 'end' => ' --- END PLUGIN SECTION ---',
  92. 'size_help' => '63535',
  93. 'size_css' => '2000',
  94. 'size_code' => '16777215',
  95. );
  96. if(@txpinterface == 'admin') {
  97. add_privs('ied_plugin_composer','1,2');
  98. add_privs('plugin_prefs.ied_plugin_composer','1,2');
  99. register_tab('extensions', 'ied_plugin_composer', gTxt('ied_plugin_lbl_composer'));
  100. register_callback('ied_plugin_composer', 'ied_plugin_composer');
  101. register_callback('ied_plugin_setup', 'plugin_prefs.ied_plugin_composer');
  102. register_callback('ied_plugin_welcome', 'plugin_lifecycle.ied_plugin_composer');
  103. register_callback('ied_plugin_inject_css', 'admin_side', 'head_end');
  104. global $ied_pc_event, $prefs;
  105. $ied_pc_event = 'ied_plugin_composer';
  106. } else {
  107. register_callback('ied_plugin_download', 'pretext');
  108. }
  109. // -------------------------------------------------------------
  110. // CSS definitions: hopefully kind to themers
  111. function ied_pc_get_style_rules() {
  112. $ied_pc_styles = array(
  113. 'ied_plugin' => '
  114. #ied_plugin64 { width:60%; }
  115. #ied_plugin_control h3 { text-align:left; }
  116. input[type="submit"] { margin:0.3em 0.7em; }
  117. .ied_label { margin:0 0.2em 0 0.6em;}
  118. .ied_plugin_setup { float:right; margin:-2em 0 0;}
  119. .ied_plugin_resizehandle { cursor:s-resize; float:left; text-align:center; font-size:1em; width:65%; padding:2px 0 6px; }
  120. .ied_plugin_info_bar { text-align:right; }
  121. #ied_plugin_jumpToLine { width:4em; margin:0 1em 0 0.4em; }
  122. .ied_editForm { width:{edwidth}; margin:0 auto; }
  123. .ied_subdue { color:gray; padding:1px 2px 2px 1px; }
  124. #ied_plugin_tp_controls input[type="text"] { width:16%; }
  125. #ied_plugin_tp_strings ul { list-style-type:none; }
  126. #ied_plugin_tp_strings ul label { margin:0 8px 0 0; }
  127. #ied_plugin_tp_strings ul input { width:450px; }
  128. .ied_plugin_edit_toolbar { text-align:right; width:95%; display:inline-block; margin:-2em 0 0 0; }
  129. #ied_plugin_msgpop { display:none; position:absolute; left:200px; max-width:500px; border:3px ridge #999; opacity:.92; filter:alpha(opacity:92); padding:15px 20px; background-color:#e2dfce; color:#80551e; }
  130. #ied_plugin_msgpop .publish { float:right; }
  131. ',
  132. );
  133. return $ied_pc_styles;
  134. }
  135. // -------------------------------------------------------------
  136. function ied_plugin_inject_css($evt, $stp) {
  137. global $ied_pc_event, $event;
  138. if ($event == $ied_pc_event) {
  139. $ied_plugin_prefs = ied_pc_get_prefs();
  140. $ied_plugin_styles = ied_pc_get_style_rules();
  141. // Possible variable replacements
  142. $edwidth = get_pref('ied_plugin_editor_width', $ied_plugin_prefs['ied_plugin_editor_width']['default']);
  143. $stylereps = array(
  144. '{edwidth}' => $edwidth,
  145. );
  146. echo '<style type="text/css">' . strtr($ied_plugin_styles['ied_plugin'], $stylereps) . '</style>';
  147. }
  148. return;
  149. }
  150. // -------------------------------------------------------------
  151. // Plugin jumpoff point
  152. function ied_plugin_composer($evt, $stp) {
  153. $available_steps = array(
  154. 'ied_plugin_code_save' => true,
  155. 'ied_plugin_create' => true,
  156. 'ied_plugin_delete' => true,
  157. 'ied_plugin_edit' => false,
  158. 'ied_plugin_generate_phpdoc' => true,
  159. 'ied_plugin_help' => true,
  160. 'ied_plugin_help_viewer' => false,
  161. 'ied_plugin_install' => true,
  162. 'ied_plugin_lang_set' => true,
  163. 'ied_plugin_table' => false,
  164. 'ied_plugin_multi_edit' => true,
  165. 'ied_plugin_prefs' => false,
  166. 'ied_plugin_restore' => true,
  167. 'ied_plugin_save' => true,
  168. 'ied_plugin_save_as_file' => true,
  169. 'ied_plugin_save_as_php_file' => true,
  170. 'ied_plugin_save_as_textpack' => true,
  171. 'ied_plugin_set_order' => true,
  172. 'ied_plugin_set_tp_prefix' => true,
  173. 'ied_plugin_switch_status' => true,
  174. 'ied_plugin_textpack_del' => true,
  175. 'ied_plugin_textpack_get' => true,
  176. 'ied_plugin_textpack_load' => true,
  177. 'ied_plugin_textpack_save' => true,
  178. 'ied_plugin_upload' => true,
  179. 'save_pane_state' => true,
  180. );
  181. if ($stp == 'save_pane_state') {
  182. $stp = 'ied_plugin_save_pane_state';
  183. } else if (!$stp or !bouncer($stp, $available_steps)) {
  184. $stp = 'ied_plugin_table';
  185. }
  186. $stp();
  187. }
  188. // -------------------------------------------------------------
  189. // Lifecycle handling, post-install / delete
  190. function ied_plugin_welcome($evt, $stp) {
  191. $msg = '';
  192. switch ($stp) {
  193. case 'installed':
  194. ied_plugin_prefs_update();
  195. $msg = 'Thanks for installing the plugin composer. Happy authoring :-)';
  196. break;
  197. case 'deleted':
  198. ied_plugin_prefs_remove(0);
  199. break;
  200. }
  201. return $msg;
  202. }
  203. // -------------------------------------------------------------
  204. // Table of plugins in both database and file system cache
  205. function ied_plugin_table($message='') {
  206. global $prefs, $ied_pc_event;
  207. pagetop(gTxt('ied_plugin_lbl_composer'),$message);
  208. require_privs('ied_plugin_composer');
  209. $ied_plugin_prefs = ied_pc_get_prefs();
  210. $lc_opts = do_list(get_pref('ied_plugin_lifecycle_options'));
  211. $auto_en = get_pref('ied_plugin_auto_enable');
  212. $cbout[] = '<p><label class="ied_label">'.gTxt('ied_plugin_run_install').'</label>';
  213. $checked = in_array('installed', $lc_opts);
  214. $cbout[] = yesnoradio('ied_plugin_installopts', $checked);
  215. $cbout[] = '<label class="ied_label">'.gTxt('ied_plugin_auto_enable').'</label>';
  216. $cbout[] = radioset($ied_plugin_prefs['ied_plugin_auto_enable']['content'], 'ied_plugin_autoenable', $auto_en).'</p>';
  217. extract(gpsa(array('sort', 'dir')));
  218. if ($sort === '') $sort = get_pref('ied_plugin_sort_column', 'name');
  219. if ($dir === '') $dir = get_pref('ied_plugin_sort_dir', 'asc');
  220. $dir = ($dir == 'desc') ? 'desc' : 'asc';
  221. if (!in_array($sort, array('name', 'status', 'author', 'version', 'load_order'))) $sort = 'name';
  222. $sort_sql = $sort.' '.$dir;
  223. set_pref('ied_plugin_sort_column', $sort, 'ied_plugin', PREF_HIDDEN, '', 0, PREF_PRIVATE);
  224. set_pref('ied_plugin_sort_dir', $dir, 'ied_plugin', PREF_HIDDEN, '', 0, PREF_PRIVATE);
  225. $switch_dir = ($dir == 'desc') ? 'asc' : 'desc';
  226. // Top control-panel part of screen
  227. echo '<h1 class="txp-heading">'.gTxt('ied_plugin_lbl_composer').sp.ied_plugin_anchor($ied_pc_event, 'ied_plugin_help_viewer', '?', array('name' => 'ied_plugin_composer'), array('class' => 'pophelp')).'</h1>'.
  228. n. '<div id="ied_plugin_control" class="txp-control-panel">'.
  229. n. sLink($ied_pc_event, 'ied_plugin_prefs', gTxt('ied_plugin_setup'), 'ied_plugin_setup').
  230. n. '<div class="summary-details"><h3 class="lever txp-summary'.(get_pref('pane_ied_plugin_cpanel_visible') ? ' expanded' : '').'"><a href="#ied_plugin_cpanel">' . gTxt('ied_plugin_cpanel_legend') . '</a></h3><div id="ied_plugin_cpanel" class="toggle" style="display:'.(get_pref('pane_ied_plugin_cpanel_visible') ? 'block' : 'none').'">'.
  231. n. '<form class="ied_plugin_form" enctype="multipart/form-data" action="index.php" method="post">'.
  232. n. '<p>'.
  233. n. '<label for="ied_plugin_newname" class="ied_label">'.gTxt('name').'</label>'.
  234. n. fInput('text', 'name', '', '', '', '', INPUT_REGULAR, '', 'ied_plugin_newname').
  235. n. fInput('submit', 'plugin_create', gTxt('ied_plugin_create_new')).
  236. n. '</p>'.
  237. n. '<p>'.
  238. n. '<label for="ied_plugin_file" class="ied_label">'.gTxt('ied_plugin_upload_php').'</label>'.
  239. n. fInput('file', 'thefile', '', '', '', '', '', '', 'ied_plugin_file').
  240. n. fInput('submit', 'plugin_upload', gTxt('upload')).
  241. n. '</p>'.
  242. n. '<p>'.
  243. n. '<label for="ied_plugin64" class="ied_label">'.gTxt('ied_plugin_install_txt').'</label>'.
  244. n. text_area('plugin64', '', '', '', 'ied_plugin64').
  245. n. fInput('submit', 'plugin_install', gTxt('install')).
  246. n. '</p>'.
  247. n. join(n, $cbout).
  248. n. eInput($ied_pc_event).
  249. n. sInput('ied_plugin_create').
  250. n. hInput('MAX_FILE_SIZE', 1000000).
  251. n. tInput().
  252. n. '</form>'.
  253. n. '</div>'.
  254. n. '</div>'.
  255. n. '</div>';
  256. // Main plugin list
  257. echo n. '<div id="ied_plugin_container" class="txp-container">';
  258. $rs = safe_rows('*', 'txp_plugin', '1=1 ORDER BY '.$sort_sql);
  259. if ($rs) {
  260. echo '<div class="summary-details">'.
  261. n. '<form action="index.php" id="ied_plugin_db_form" method="post">'.
  262. n. '<h3 class="lever txp-summary'.(get_pref('pane_ied_plugin_dbplugs_visible') ? ' expanded' : '').'">'.
  263. n. '<a href="#ied_plugin_dbplugs">' . gTxt('ied_plugin_dbplugs_legend') . '</a>'.
  264. n. '</h3>'.
  265. n. '<div id="ied_plugin_dbplugs" class="toggle" style="display:'.(get_pref('pane_ied_plugin_dbplugs_visible') ? 'block' : 'none').'">'.
  266. n. '<div class="txp-listtables">'.
  267. n. startTable('', '', 'txp-list').
  268. n.'<thead>'.
  269. n. tr(
  270. n.hCell(fInput('checkbox', 'select_all', 0, '', '', '', '', '', 'select_all'), '', ' title="'.gTxt('toggle_all_selected').'" class="multi-edit"')
  271. .n.column_head('plugin', 'name', 'ied_plugin_composer', true, $switch_dir, '', '', (('name' == $sort) ? "$dir " : '').'name')
  272. .n.column_head('author', 'author', 'ied_plugin_composer', true, $switch_dir, '', '', (('author' == $sort) ? "$dir " : '').'author')
  273. .n.column_head(gTxt('version').' ('.gTxt('plugin_modified').')', 'version', 'ied_plugin_composer', true, $switch_dir, '', '', (('version' == $sort) ? "$dir " : '').'version')
  274. .n.hCell(gTxt('description'), '', ' class="description"')
  275. .n.hCell(gTxt('manage'), '', ' class="manage"')
  276. .n.column_head('active', 'status', 'ied_plugin_composer', true, $switch_dir, '', '', (('status' == $sort) ? "$dir " : '').'status')
  277. ).
  278. n. '</thead>'.
  279. n. '<tbody>';
  280. foreach ($rs as $row) {
  281. extract($row);
  282. $ename = ied_plugin_anchor($ied_pc_event, 'ied_plugin_edit', $name, array('name' => $name));
  283. $hlink = ($help) ? ied_plugin_anchor($ied_pc_event, 'ied_plugin_help_viewer', gTxt('ied_plugin_docs'), array('name' => $name)) : gTxt('none');
  284. $fnames = ied_plugin_get_name($name, $version);
  285. $pubtag = ied_plugin_anchor($ied_pc_event, 'ied_plugin_save_as_file', gTxt('publish'), array('name' => $name), array('title' => gTxt('ied_plugin_export', array('{name}' => $fnames[0]))));
  286. $pubztag = ied_plugin_anchor($ied_pc_event, 'ied_plugin_save_as_file', gTxt('ied_plugin_compress'), array('name' => $name, 'type' => 'zip'), array('title' => gTxt('ied_plugin_export', array('{name}' => $fnames[1]))));
  287. $modified = (strtolower($code) != (strtolower($code_restore)));
  288. $plugpref = ($flags & PLUGIN_HAS_PREFS) ? (sp.ied_plugin_anchor('plugin_prefs.'.urlencode($name), '', '['.gTxt('plugin_prefs').']', array('name' => $name), array('class' => 'plugin_prefs'.( ($status) ? '' : ' empty'))) ) : '';
  289. echo tr(
  290. n.td(
  291. fInput('checkbox', 'selected[]', $name)
  292. ,'', 'multi-edit')
  293. .n.td($ename.$plugpref)
  294. .n.td(( ($author_uri) ? '<a href="'.txpspecialchars($author_uri).'">'.txpspecialchars($author).'</a>' : txpspecialchars($author)))
  295. .n.td(( ($modified) ? ied_plugin_anchor($ied_pc_event, 'ied_plugin_restore', $version, array('name' => $name), array('title' => gTxt('ied_plugin_restore_help'), 'onclick' => 'return verify(\''.gTxt('ied_plugin_restore_verify', array('{name}' => $name)).'\');')) : $version) . (($modified) ? sp.'('.gTxt('yes').')' : ''))
  296. .n.td(txpspecialchars($description))
  297. .n.td($pubtag .sp. '&#124;' .sp. $pubztag .sp. '&#124;' .sp. $hlink)
  298. .n.td(ied_plugin_status_link($status,$name,yes_no($status)))
  299. );
  300. unset($name,$page);
  301. }
  302. echo n. '</tbody>'.
  303. n. endTable().
  304. n. '</div>'.
  305. n. tInput().
  306. n. '</form>'.
  307. ied_plugin_multiedit_form('db', '', $sort, $dir, '', '').
  308. n. '</div>'.
  309. n. '</div>';
  310. }
  311. if (!empty($prefs['plugin_cache_dir']) && file_exists($prefs['plugin_cache_dir'])) {
  312. $filenames = array();
  313. $directory = dir($prefs['plugin_cache_dir']);
  314. while ($file = $directory->read()) {
  315. if($file != "." && $file != "..") {
  316. $fileaddr = $prefs['plugin_cache_dir'].DS.$file;
  317. if (!is_dir($fileaddr)) {
  318. $filenames[]=$file;
  319. }
  320. }
  321. }
  322. $directory->close();
  323. ($filenames)?natcasesort($filenames):'';
  324. $out = array();
  325. foreach($filenames as $filename) {
  326. $parts = explode ('.',$filename);
  327. $fileext = array_pop($parts);
  328. if ($fileext=='php') {
  329. $basename = basename($filename);
  330. $plugin = ied_plugin_read_file($prefs['plugin_cache_dir'].DS.$filename);
  331. $hlink = ($plugin['help']) ? ied_plugin_anchor($ied_pc_event, 'ied_plugin_help_viewer', gTxt('ied_plugin_docs'), array('filename' => $filename)) : gTxt('none');
  332. $efile = ied_plugin_anchor($ied_pc_event, 'ied_plugin_edit', $plugin['name'], array('filename' => $filename));
  333. $fnames = ied_plugin_get_name($plugin['name'], $plugin['version']);
  334. $plugpref = (($plugin['flags'] & PLUGIN_HAS_PREFS)) ? ' '.ied_plugin_anchor('plugin_prefs.'.urlencode($plugin['name']), '', ' ['.gTxt('plugin_prefs').']') : '';
  335. $pubtag = ied_plugin_anchor($ied_pc_event, 'ied_plugin_save_as_file', gTxt('publish'), array('filename' => $filename), array('title' => gTxt('ied_plugin_export', array('{name}' => $fnames[0]))));
  336. $pubztag = ied_plugin_anchor($ied_pc_event, 'ied_plugin_save_as_file', gTxt('ied_plugin_compress'), array('filename' => $filename, 'type' => 'zip'), array('title' => gTxt('ied_plugin_export', array('{name}' => $fnames[1]))));
  337. $out[] = tr(
  338. n.td(
  339. fInput('checkbox', 'selected-cache[]', $filename)
  340. ,'', 'multi-edit')
  341. .n.td(
  342. tag($filename,'div',' class="ied_subdue"')
  343. .(isset($plugin['name']) ? $efile.$plugpref.'<br />' : '').' '
  344. )
  345. .n.td(
  346. ( isset($plugin['author_uri']) ? '<a href="'.$plugin['author_uri'].'">' : '' ) .
  347. ( isset($plugin['author']) ? $plugin['author'] : '&nbsp;' ).
  348. ( isset($plugin['author_uri']) ? '</a>' : '' )
  349. )
  350. .n.td(
  351. (isset($plugin['version']) ? $plugin['version'] : '&nbsp;')
  352. )
  353. .n.td(
  354. (isset($plugin['description']) ? $plugin['description'] : '&nbsp;')
  355. )
  356. .n.td(
  357. (isset($plugin['name']) ? $pubtag .sp. '&#124;' .sp. $pubztag
  358. : tag('&nbsp;', 'span')
  359. )
  360. .sp. '&#124;' .sp. $hlink
  361. )
  362. );
  363. }
  364. }
  365. if ($out) {
  366. echo '<div class="summary-details">'.
  367. n. '<form action="index.php" id="ied_plugin_cache_form" method="post">'.
  368. n. '<h3 class="lever txp-summary'.(get_pref('pane_ied_plugin_cacheplugs_visible') ? ' expanded' : '').'">'.
  369. n. '<a href="#ied_plugin_cacheplugs">' . gTxt('ied_plugin_cacheplugs_legend') . '</a>'.
  370. n. '</h3>'.
  371. n. '<div id="ied_plugin_cacheplugs" class="toggle" style="display:'.(get_pref('pane_ied_plugin_cacheplugs_visible') ? 'block' : 'none').'">'.
  372. n. '<div class="txp-listtables ied_plugin_cacheplugs">'.
  373. n.startTable('', '', 'txp-list').
  374. n. '<thead>'.
  375. n. tr(
  376. n.hCell(fInput('checkbox', 'select_all', 0, '', '', '', '', '', 'select_all'), '', ' title="'.gTxt('toggle_all_selected').'" class="multi-edit"')
  377. .n.hCell(gTxt('plugin'), '', ' class="name"')
  378. .n.hCell(gTxt('author'), '', ' class="author"')
  379. .n.hCell(gTxt('version') . ' ('.gTxt('plugin_modified').')', '', ' class="version"')
  380. .n.hCell(gTxt('description'), '', ' class="description"')
  381. .n.hCell(gTxt('manage'), '', ' class="manage"')
  382. ).
  383. n. '</thead>'.
  384. n. '<tbody>'.
  385. n. join(n, $out).
  386. n. '</tbody>'.
  387. n. endTable().
  388. n. '</div>'.
  389. n. tInput().
  390. n. '</form>'.
  391. ied_plugin_multiedit_form('cache', '', $sort, $dir, '', '').
  392. n. '</div>'.
  393. n. '</div>';
  394. }
  395. }
  396. echo '</div>'.
  397. n. script_js( <<<EOS
  398. $(document).ready(function() {
  399. $('#ied_plugin_db_form').txpMultiEditForm({
  400. 'checkbox' : 'input[name="selected[]"][type=checkbox]'
  401. });
  402. $('#ied_plugin_cache_form').txpMultiEditForm({
  403. 'checkbox' : 'input[name="selected-cache[]"][type=checkbox]'
  404. });
  405. });
  406. EOS
  407. );
  408. // Show/hide "Options" link by setting the appropriate class on the plugin's TR
  409. echo script_js(<<<EOS
  410. textpattern.Relay.register('txpAsyncHref.success', function(event, data) {
  411. jQuery(data.this).closest('tr').find('a.plugin_prefs').toggleClass('empty');
  412. });
  413. EOS
  414. );
  415. }
  416. // -------------------------------------------------------------
  417. function ied_plugin_multiedit_form($flavour, $page, $sort, $dir, $crit, $search_method) {
  418. global $ied_pc_event;
  419. $orders = selectInput('order', array(1=>1, 2=>2, 3=>3, 4=>4, 5=>5, 6=>6, 7=>7, 8=>8, 9=>9), 5, false);
  420. $stati = selectInput('switch_status', array('toggle' => gTxt('ied_plugin_toggle'), 'on' => gTxt('on'), 'off' => gTxt('off')), 'toggle', false);
  421. $lifecycles = selectInput('ied_lc_event', array(
  422. 'installed' => gTxt('ied_plugin_lbl_lc_install'),
  423. 'enabled' => gTxt('ied_plugin_lbl_lc_enable'),
  424. 'installed,enabled' => gTxt('ied_plugin_lbl_lc_instable'),
  425. 'disabled' => gTxt('ied_plugin_lbl_lc_disable'),
  426. 'deleted' => gTxt('ied_plugin_lbl_lc_delete'),
  427. 'disabled,deleted' => gTxt('ied_plugin_lbl_lc_disdel'),
  428. ));
  429. if ($flavour === 'db') {
  430. $methods = array(
  431. 'changestatus' => array('label' => gTxt('changestatus'), 'html' => $stati),
  432. 'changeorder' => array('label' => gTxt('changeorder'), 'html' => $orders),
  433. 'lifecycle' => array('label' => gTxt('ied_plugin_lifecycle'), 'html' => $lifecycles),
  434. 'delete' => gTxt('delete'),
  435. );
  436. } else {
  437. $methods = array(
  438. 'lifecycle' => array('label' => gTxt('ied_plugin_lifecycle'), 'html' => $lifecycles),
  439. 'textpack' => array('label' => gTxt('ied_plugin_install_textpack')),
  440. 'delete' => gTxt('delete'),
  441. );
  442. }
  443. return multi_edit($methods, $ied_pc_event, 'ied_plugin_multi_edit', $page, $sort, $dir, $crit, $search_method);
  444. }
  445. // -------------------------------------------------------------
  446. function ied_plugin_multi_edit() {
  447. global $prefs;
  448. $selected = ps('selected');
  449. $selected_cache = ps('selected-cache');
  450. $method = assert_string(ps('edit_method'));
  451. if ($selected && is_array($selected))
  452. {
  453. $where = "name IN ('".join("','", doSlash($selected))."')";
  454. $lc_opts = do_list(get_pref('ied_plugin_lifecycle_options'));
  455. switch ($method)
  456. {
  457. case 'delete':
  458. foreach ($selected as $name)
  459. {
  460. if (safe_field('flags', 'txp_plugin', "name ='".doSlash($name)."'") & PLUGIN_LIFECYCLE_NOTIFY)
  461. {
  462. load_plugin($name, true);
  463. if (in_array('disabled', $lc_opts)) {
  464. callback_event("plugin_lifecycle.$name", 'disabled');
  465. }
  466. if (in_array('deleted', $lc_opts)) {
  467. callback_event("plugin_lifecycle.$name", 'deleted');
  468. }
  469. }
  470. }
  471. safe_delete('txp_plugin', $where);
  472. break;
  473. case 'changestatus':
  474. switch (ps('switch_status')) {
  475. case 'on':
  476. $newstat = '1';
  477. break;
  478. case 'off':
  479. $newstat = '0';
  480. break;
  481. case 'toggle':
  482. default:
  483. $newstat = '(1-status)';
  484. break;
  485. }
  486. foreach ($selected as $name) {
  487. if (safe_field('flags', 'txp_plugin', "name ='".doSlash($name)."'") & PLUGIN_LIFECYCLE_NOTIFY) {
  488. $status = safe_field('status', 'txp_plugin', "name ='".doSlash($name)."'");
  489. $status = $status ? 'disabled' : 'enabled';
  490. load_plugin($name, true);
  491. if (in_array($status, $lc_opts)) {
  492. callback_event("plugin_lifecycle.$name", $status);
  493. }
  494. }
  495. }
  496. safe_update('txp_plugin', 'status = '.$newstat, $where);
  497. break;
  498. case 'changeorder':
  499. $order = min(max(intval(ps('order')), 1), 9);
  500. safe_update('txp_plugin', 'load_order = '.$order, $where);
  501. break;
  502. case 'lifecycle':
  503. $lc_evs = do_list(ps('ied_lc_event'));
  504. foreach ($selected as $name) {
  505. foreach ($lc_evs as $lc_ev) {
  506. callback_event("plugin_lifecycle.$name", $lc_ev);
  507. }
  508. }
  509. break;
  510. }
  511. } else {
  512. $selected = array();
  513. }
  514. if ($selected_cache && is_array($selected_cache))
  515. {
  516. switch ($method)
  517. {
  518. case 'delete':
  519. foreach ($selected_cache as $name) {
  520. $filenames = array();
  521. $dir = dir($prefs['plugin_cache_dir']);
  522. while ($file = $dir->read()) {
  523. if($file != "." && $file != ".." && in_array($file, $selected_cache)) {
  524. $fileaddr = $prefs['plugin_cache_dir'].DS.$file;
  525. if (!is_dir($fileaddr)) {
  526. unlink($fileaddr);
  527. }
  528. }
  529. }
  530. $dir->close();
  531. }
  532. break;
  533. case 'lifecycle':
  534. $lc_evs = do_list(ps('ied_lc_event'));
  535. foreach ($selected_cache as $name) {
  536. $name = str_replace('.php', '', $name);
  537. foreach ($lc_evs as $lc_ev) {
  538. callback_event("plugin_lifecycle.$name", $lc_ev);
  539. }
  540. }
  541. break;
  542. case 'textpack':
  543. // Read the textpack from the .php file and call install_textpack()
  544. $textpack = array();
  545. foreach ($selected_cache as $name) {
  546. $fileaddr = $prefs['plugin_cache_dir'].DS.$name;
  547. $contents = file($fileaddr);
  548. $in_tp = $in_comment = false;
  549. foreach ($contents as $row) {
  550. if (strpos($row, '/**') === 0) {
  551. $in_comment = true;
  552. }
  553. if (strpos($row, '**/') === 0) {
  554. $in_comment = false;
  555. }
  556. if (strpos($row, 'EOT;') !== false) {
  557. break;
  558. }
  559. if ($in_tp === true) {
  560. $textpack[] = trim($row);
  561. }
  562. if (!$in_comment && strpos($row, '$plugin[\'textpack\']') !== false) {
  563. $in_tp = true;
  564. }
  565. }
  566. }
  567. $done = install_textpack(join(n, $textpack));
  568. break;
  569. }
  570. } else {
  571. $selected_cache = array();
  572. }
  573. $message = '';
  574. if ($selected || $selected_cache) {
  575. if ($method === 'delete') {
  576. $message = gTxt('plugin_deleted', array('{name}' => join(', ', array_merge($selected, $selected_cache))));
  577. } else if ($method === 'lifecycle') {
  578. $message = gTxt('ied_plugin_lc_fired', array('{name}' => join(', ', array_merge($selected, $selected_cache)), '{event}' => join(',', $lc_evs)));
  579. } else if ($method === 'textpack') {
  580. $message = gTxt('textpack_strings_installed', array('{count}' => $done));
  581. } else {
  582. $message = gTxt('plugin_updated', array('{name}' => join(', ', $selected)));
  583. }
  584. }
  585. ied_plugin_table($message);
  586. }
  587. // -------------------------------------------------------------
  588. function ied_plugin_anchor($evt, $stp, $linktext, $nv = array(), $atts = array()) {
  589. $nv['_txp_token'] = form_token();
  590. $atts['href'] = '?event='.$evt.($stp ? '&step='.$stp : '').'&'.http_build_query($nv);
  591. $attribs = '';
  592. foreach ($atts as $n => $v) {
  593. $attribs .= ' '.txpspecialchars($n).'="'.txpspecialchars($v).'"';
  594. }
  595. return tag($linktext, 'a', $attribs);
  596. }
  597. // -------------------------------------------------------------
  598. function ied_plugin_status_link($status, $name, $linktext) {
  599. return asyncHref($linktext, array('step' => 'ied_plugin_switch_status', 'thing' => $name),' title="'.($status==1 ? gTxt('disable') : gTxt('enable')).'"' );
  600. }
  601. // -------------------------------------------------------------
  602. function ied_plugin_switch_status() {
  603. extract(array_map('assert_string', gpsa(array('thing', 'value'))));
  604. $change = ($value == gTxt('yes')) ? 0 : 1;
  605. safe_update('txp_plugin', "status = $change", "name = '".doSlash($thing)."'");
  606. $lc_opts = do_list(get_pref('ied_plugin_lifecycle_options'));
  607. $stp = $change ? 'enabled' : 'disabled';
  608. if (in_array($stp, $lc_opts) && (safe_field('flags', 'txp_plugin', "name='".doSlash($thing)."'") & PLUGIN_LIFECYCLE_NOTIFY) ) {
  609. load_plugin($thing, true);
  610. $message = callback_event("plugin_lifecycle.$thing", $stp);
  611. }
  612. echo gTxt($change ? 'yes' : 'no');
  613. }
  614. // -------------------------------------------------------------
  615. function ied_plugin_set_order() {
  616. extract(doSlash(gpsa(array('name', 'load_order'))));
  617. $order = min(max( intval($load_order), 1), 9);
  618. safe_update('txp_plugin', "load_order = $load_order", "name = '$name'");
  619. ied_plugin_table(gTxt('plugin_saved', array('{name}' => $name)));
  620. }
  621. // -------------------------------------------------------------
  622. function ied_plugin_delete() {
  623. $name = doSlash(ps('name'));
  624. $lc_opts = do_list(get_pref('ied_plugin_lifecycle_options'));
  625. $lc_dis = in_array('disabled', $lc_opts);
  626. $lc_del = in_array('deleted', $lc_opts);
  627. if ( ($lc_del || $lc_dis) && (safe_field('flags', 'txp_plugin', "name='".$name."'") & PLUGIN_LIFECYCLE_NOTIFY) ) {
  628. load_plugin($name, true);
  629. if ($lc_dis) {
  630. callback_event("plugin_lifecycle.$name", 'disabled');
  631. }
  632. if ($lc_del) {
  633. callback_event("plugin_lifecycle.$name", 'deleted');
  634. }
  635. }
  636. safe_delete('txp_plugin', "name='$name'");
  637. ied_plugin_table(gTxt('plugin_deleted', array('{name}' => $name)));
  638. }
  639. // -------------------------------------------------------------
  640. function ied_plugin_restore() {
  641. $name = doSlash(gps('name'));
  642. safe_update("txp_plugin","code = code_restore","name='$name'");
  643. ied_plugin_table(gTxt('ied_plugin_restored', array('{name}' => $name)));
  644. }
  645. // -------------------------------------------------------------
  646. function ied_plugin_edit($message='', $newfile='') {
  647. global $prefs, $ied_plugin_globals, $ied_pc_event;
  648. $newname = trim(gps('newname'));
  649. $filename = gps('filename');
  650. $editfile = $filename ? 1 : 0;
  651. $name = empty($newname) ? gps('name') : $newname;
  652. $name = ($newfile) ? $newfile : (($filename) ? $filename : $name);
  653. pagetop(gTxt('ied_plugin_editing', array('{name}' => txpspecialchars($name))), $message);
  654. require_privs('ied_plugin_composer');
  655. echo ied_insert_editors();
  656. if (!$editfile) {
  657. $rs = safe_row("author, author_uri, version, description, code, help, status, type, load_order, flags", "txp_plugin", "name='".doSlash($name)."'");
  658. extract($rs);
  659. list($css,$help) = ($help) ? ied_plugin_extract_hunk($help, "CSS", "<!--|-->", true) : array('',$help);
  660. } else {
  661. $plugin = ied_plugin_read_file($prefs['plugin_cache_dir'].DS.$name);
  662. $filename = $name;
  663. $name = explode ('.', $name);
  664. $fileext = array_pop($name);
  665. $name = implode($name);
  666. extract($plugin);
  667. $status = ($fileext=='php')? 1: 0;
  668. }
  669. $ifel = get_pref('ied_plugin_interface_elems');
  670. $distblock = (strpos($ifel, 'distribution') !== false);
  671. $styleblock = (strpos($ifel, 'style') !== false);
  672. $distribution = '';
  673. list ($start_css, $end_css) = ied_plugin_make_markers("CSS", $ied_plugin_globals['css_start'], $ied_plugin_globals['css_end']);
  674. if ($distblock) {
  675. $plugin['name'] = $name;
  676. $plugin['author'] = $author;
  677. $plugin['author_uri'] = $author_uri;
  678. $plugin['version'] = $version;
  679. $plugin['description'] = $description;
  680. $plugin['help'] = ied_plugin_textile($name, $help, $css, $start_css, $end_css);
  681. $plugin['code'] = $code;
  682. $plugin['type'] = $type;
  683. $plugin['order'] = $load_order;
  684. $plugin['flags'] = $flags;
  685. $plugin['md5'] = md5( $plugin['code'] );
  686. $distribution = '<textarea name="distribution" rows="1" onclick="this.select()">'.base64_encode(serialize($plugin)).'</textarea>';
  687. }
  688. for ($i = 1; $i <= 9; $i++) $orders[$i] = $i;
  689. $tp_pfx = unserialize(get_pref('ied_plugin_tp_prefix', '', 1));
  690. $tp_pfx = isset($tp_pfx[$name]) ? $tp_pfx[$name] : '';
  691. $fnames = ied_plugin_get_name($name, $version);
  692. $namedLink = ($filename) ? array('filename' => $filename) : array('name' => $name);
  693. $zippedLink = array_merge($namedLink, array('type' => 'zip'));
  694. $slink = ied_plugin_anchor($ied_pc_event, 'ied_plugin_save_as_file', gTxt('ied_plugin_export', array('{name}' => $fnames[0])), $namedLink);
  695. $sziplink = ied_plugin_anchor($ied_pc_event, 'ied_plugin_save_as_file', gTxt('ied_plugin_export_zip', array('{name}' => $fnames[1])), $zippedLink);
  696. $sphplink = ied_plugin_anchor($ied_pc_event, 'ied_plugin_save_as_php_file', gTxt('ied_plugin_save_as', array('{name}' => $fnames[2])), $namedLink);
  697. $stxtlink = ied_plugin_anchor($ied_pc_event, 'ied_plugin_save_as_textpack', gTxt('ied_plugin_export_textpack'), $namedLink);
  698. $vhelplinkfull = ($help) ? '[ ' .ied_plugin_anchor($ied_pc_event, 'ied_plugin_help_viewer', gTxt('ied_plugin_docs'), $namedLink) . ' ]' : '';
  699. $msgpop = '<div id="ied_plugin_msgpop"><input type="button" class="publish" value="'.gTxt('ok').'" onclick="ied_plugin_toggle_msgpop(\'0\');" /><h2>'.gTxt('ied_plugin_msgpop_lbl').'</h2><span class="ied_plugin_msgpop_content"></span></div>';
  700. $newname = fInput('text', 'newname', $name, '', '', '', INPUT_REGULAR);
  701. $author_widget = fInput('text', 'author', $author, '', '', '', INPUT_REGULAR);
  702. $author_uri_widget = fInput('text', 'author_uri', $author_uri, '', '', '', INPUT_REGULAR);
  703. $version_widget = fInput('text', 'version', $version, 'input-small', '', '',INPUT_SMALL) .sp. (($editfile) ? checkbox('rename_file', '1', 0, '','rename_file') . ' <label for="rename_file">'.gTxt('ied_plugin_rename_file').'</label>' : checkbox('restore_point', '1', 0, '','restore_point') . ' <label for="restore_point">'.gTxt('ied_plugin_restore_point').'</label>');
  704. $description_widget = fInput('text', 'description', $description, 'input-xlarge', '', '', INPUT_LARGE);
  705. $codeblock = '<textarea name="code" id="plugin_editor" rows="'.INPUT_REGULAR.'" class="code codepress php" maxlength="'.$ied_plugin_globals['size_code'].'">'.txpspecialchars($code).'</textarea><div class="ied_plugin_info_bar"><span>'.gTxt('ied_plugin_jump_to_line').'</span><input type="text" id="ied_plugin_jumpToLine" size="5" maxlength="6" /><span class="ied_plugin_charsRemain"></span></div>';
  706. $help_widget = '<textarea name="help" rows="'.INPUT_REGULAR.'" class="mceEditor" maxlength="'.$ied_plugin_globals['size_help'].'">'.txpspecialchars($help).'</textarea><div class="ied_plugin_info_bar"><span class="ied_plugin_charsRemain"></span></div>';
  707. $css_widget = ($styleblock) ? '<textarea name="css" rows="'.INPUT_MEDIUM.'" class="code" maxlength="'.$ied_plugin_globals['size_css'].'">'.txpspecialchars($css).'</textarea><div class="ied_plugin_info_bar"><span class="ied_plugin_charsRemain"></span></div>' : '';
  708. $plugstatus = (!$editfile) ? sp.sp.checkbox('status',1,$status, '','status'). ' <label for="status">'.gTxt('ied_plugin_enable').'</label>' : '';
  709. $plugtype = radio('type',0,(($type==0)?1:0)).gTxt('ied_plugin_type_0')." "
  710. . radio('type',1,(($type==1)?1:0)).gTxt('ied_plugin_type_1')." "
  711. . radio('type',2,(($type==2)?1:0)).gTxt('ied_plugin_type_2')." "
  712. . radio('type',3,(($type==3)?1:0)).gTxt('ied_plugin_type_3')." "
  713. . radio('type',4,(($type==4)?1:0)).gTxt('ied_plugin_type_4')." "
  714. . radio('type',5,(($type==5)?1:0)).gTxt('ied_plugin_type_5');
  715. $plugorder = selectInput('load_order', $orders, $load_order, 0, 0);
  716. $flaglist = checkbox('flags[]',PLUGIN_HAS_PREFS,(($flags & PLUGIN_HAS_PREFS)?1:0)) . '<label>'.gTxt('ied_plugin_flag_has_prefs').'</label>&nbsp;&nbsp;'
  717. .checkbox('flags[]',PLUGIN_LIFECYCLE_NOTIFY,(($flags & PLUGIN_LIFECYCLE_NOTIFY)?1:0)) . '<label>'.gTxt('ied_plugin_flag_lifecycle_notify').'</label>&nbsp;&nbsp;';
  718. // .checkbox('flags[]',0x0004,(($flags & 0x0004)?1:0)) . '<label>Summat else</label>&nbsp;&nbsp;';
  719. $sub = fInput('submit', '', gTxt('save'), 'publish', '', '', '', '', 'ied_editSave');
  720. $codesub = (!$editfile) ? '<a class="navlink" name="ied_plugin_code_save" id="ied_plugin_code_save">' . gTxt('ied_plugin_code_save') . '</a>' : '';
  721. // Language info. ied_visible_langs is the user's choice of which ones they want to see available.
  722. // ied_available_langs is the list of actual, currently-installed langs
  723. $ied_listlangs = get_pref('ied_plugin_lang_choose', 'installed');
  724. $ied_visible_langs = ied_plugin_lang_list($ied_listlangs);
  725. $ied_available_langs = ($ied_listlangs == 'installed') ? $ied_visible_langs : ied_plugin_lang_list('installed');
  726. $dflt_lang = get_pref('ied_plugin_lang_default', $prefs['language']);
  727. $dflt_lang = array_key_exists($dflt_lang, $ied_visible_langs) ? $dflt_lang : $prefs['language'];
  728. $langsel = selectInput('ied_plugin_tp_lang', $ied_visible_langs, $dflt_lang, '', '', 'ied_plugin_tp_lang')
  729. .fInput('button', 'ied_plugin_tp_refresh', gTxt('ied_plugin_load'), '', '', '', '', '', 'ied_plugin_tp_refresh');
  730. $preselected = do_list(get_pref('ied_plugin_lang_selected', ''));
  731. $op_langs[] = '<select name="ied_plugin_tp_oplangs" id="ied_plugin_tp_oplangs" multiple="multiple"><option value=""></option>';
  732. foreach ($ied_available_langs as $langcode => $alang) {
  733. $sel = in_array($langcode, $preselected) ? ' selected="selected"' : '';
  734. $op_langs[] = '<option value="'.$langcode.'"'.$sel.'>'.$alang.'</option>';
  735. }
  736. $op_langs[] = '</select>';
  737. $tp_strings = array();
  738. $tp_rows = ied_plugin_textpack_grab($dflt_lang, $tp_pfx);
  739. foreach ($tp_rows as $tp_string) {
  740. $apsel = selectInput('ied_plugin_tp_event', array('admin' => gTxt('admin'), 'public' => gTxt('public'), 'common' => gTxt('both')), ($tp_string['event'] == 'public' ? 'public' : ($tp_string['event'] == 'common' ? 'common' : 'admin')) );
  741. $tp_strings[] = '<li>'.fInput('text', 'textpack_'.$tp_string['name'], $tp_string['data']).' '.$apsel.' <label>'.$tp_string['name'].'</label>'.'</li>';
  742. }
  743. $err_prefix = gTxt('ied_plugin_syntax_err');
  744. $codesave_ok = gTxt('ied_plugin_code_saved');
  745. $phpdoc = '';
  746. // TODO
  747. $classFinder = '/class[\s\n]+(\w+)[\s\n]*\{?(function[\s\n]+(\w+)[\s\n]*\(.*\)[\s\n]*\{?)*/';
  748. $functionFinder = '/function[\s\n]+(\w+)[\s\n]*\(.*\)[\s\n]*\{?/';
  749. preg_match_all($functionFinder, $code , $functionArray);
  750. // selectInput requires key and value to be the same
  751. //dmp($functionArray);
  752. $fnArray = array();
  753. /*
  754. foreach($functionArray[1] as $key => $val) {
  755. $fnArray[$val] = $functionArray[1][$key];
  756. }
  757. $phpdoc = selectInput('ied_plugin_to_phpdoc', $fnArray, '', false, '', 'ied_plugin_to_phpdoc')
  758. .'<a class="navlink" name="ied_plugin_btn_phpdoc" id="ied_plugin_btn_phpdoc">' . gTxt('ied_plugin_php_doc') . '</a>';
  759. */
  760. $phpdoc = '';
  761. echo
  762. hed(gTxt('ied_plugin_edit', array('{name}' => $name, '{version}' => $version)).n.$vhelplinkfull, 2).
  763. n. form(
  764. '<div id="ied_plugin_sub">'. ($sub).'</div>'
  765. .n. '<div class="summary-details"><h3 class="lever txp-summary'.(get_pref('pane_ied_plugin_meta_visible') ? ' expanded' : '').'"><a href="#ied_plugin_meta">' . gTxt('ied_plugin_meta_legend') . '</a></h3><div id="ied_plugin_meta" class="toggle" style="display:'.(get_pref('pane_ied_plugin_meta_visible') ? 'block' : 'none').'">'
  766. .n. '<p><label>' . gTxt('name') . '</label>' . sp . $newname . sp. '<label>' . gTxt('version') . '</label>' . sp . $version_widget . $plugstatus . ( ($filename) ? tag(sp.sp.'('.$filename.')','span',' style="color:gray;"').hInput('filename',$filename) : '' ) . '</p>'
  767. .n. '<p><label>' . gTxt('description') . '</label>' . sp . $description_widget . '</p>'
  768. .n. '<p><label>' . gTxt('author') . '</label>' . sp . $author_widget . sp. '<label>' . gTxt('website') . '</label>' .sp. $author_uri_widget. '</p>'
  769. .n. '<p><label>' . gTxt('ied_plugin_type') . '</label>' . sp . $plugtype . '</p>'
  770. .n. '<p><label>' . gTxt('ied_plugin_flags') . '</label>' . sp . $flaglist .sp. '<label>' . gTxt('ied_plugin_load_order') . '</label>' . sp . $plugorder . sp.sp . gTxt('ied_plugin_load_order_help') . '</p>'
  771. .n. '</div></div>'
  772. .n. '<div class="summary-details"><h3 class="lever txp-summary'.(get_pref('pane_ied_plugin_code_visible') ? ' expanded' : '').'"><a href="#ied_plugin_code">'.gTxt('ied_plugin_code_legend').'</a></h3><div id="ied_plugin_code" class="toggle" style="display:'.(get_pref('pane_ied_plugin_code_visible') ? 'block' : 'none').'">'
  773. .n. '<span class="ied_plugin_edit_toolbar">' . $msgpop . $phpdoc . sp . $codesub . '</span>'
  774. .n. '<div>' . $codeblock . '</div>'
  775. .n. '</div></div>'
  776. .n. '<div class="summary-details"><h3 class="lever txp-summary'.(get_pref('pane_ied_plugin_tp_strings_visible') ? ' expanded' : '').'"><a href="#ied_plugin_tp_strings">' . gTxt('ied_plugin_tp_legend') . ' <span id="ied_plugin_tp_count"></span></a></h3><div id="ied_plugin_tp_strings" class="toggle" style="display:'.(get_pref('pane_ied_plugin_tp_strings_visible') ? 'block' : 'none').'">'
  777. .n. '<div id="ied_plugin_tp_controls">'
  778. .n. '<label>'
  779. .n. gTxt('ied_plugin_tp_prefix')
  780. .n. '</label>'
  781. .n. fInput('text', 'ied_plugin_tp_prefix', $tp_pfx, '', '', '', '', '', 'ied_plugin_tp_prefix')
  782. .n. sp
  783. .n. $langsel
  784. .n. sp
  785. .n. fInput('hidden', 'ied_plugin_tp_lang_dflt', $dflt_lang, '', '', '', '', '', 'ied_plugin_tp_lang_dflt')
  786. .n. gTxt('ied_plugin_tp_populate').n.'</label>'.fInput('text', 'ied_plugin_tp_populate', '', '', '', '', '', '', 'ied_plugin_tp_populate') . sp . '<button id="ied_plugin_tp_load">'.gTxt('go').'</button>'
  787. .n. '<span id="ied_plugin_tp_load_count"></span>'
  788. .n. '</div>'
  789. .n. '<a href="#" id="ied_plugin_add_string">+</a>'
  790. .n. '<ul>'
  791. .n. join(n, $tp_strings)
  792. .n. '</ul></div></div>'
  793. .n. '<div class="summary-details"><h3 class="lever txp-summary'.(get_pref('pane_ied_plugin_docs_visible') ? ' expanded' : '').'"><a href="#ied_plugin_docs">'.gTxt('ied_plugin_docs_legend').'</a></h3><div id="ied_plugin_docs" class="toggle" style="display:'.(get_pref('pane_ied_plugin_docs_visible') ? 'block' : 'none').'">'
  794. .n. '<div>' . $help_widget . '</div>'
  795. .n. (($styleblock) ? '<div>' . gTxt( 'css' ) . $css_widget . '</div>' : '')
  796. .n. '</div></div>'
  797. .n. '<div>' . $sub . '</div>'
  798. .n. '<div class="summary-details"><h3 class="lever txp-summary'.(get_pref('pane_ied_plugin_utils_visible') ? ' expanded' : '').'"><a href="#ied_plugin_utils">'.gTxt('ied_plugin_utils_legend').'</a></h3><div id="ied_plugin_utils" class="toggle" style="display:'.(get_pref('pane_ied_plugin_utils_visible') ? 'block' : 'none').'">'
  799. .n. (($distblock) ? '<div>' . gTxt('ied_plugin_code_dist') . $distribution . '</div>' : '')
  800. .n. '<div>' . join(n, $op_langs) . '</div>'
  801. .n. '<div>' . $slink . '</div>'
  802. .n. '<div>' . $sziplink . '</div>'
  803. .n. '<div>' . $stxtlink . '</div>'
  804. .n. '<div>' . $sphplink . '</div>'
  805. .n. '</div></div>'
  806. .n. sInput('ied_plugin_save')
  807. .n. eInput($ied_pc_event)
  808. .n. hInput('name',$name)
  809. , '', '', 'post', 'ied_editForm').
  810. script_js(<<<EOF
  811. var ied_plugin_tp_total = 0;
  812. jQuery.fn.ied_plugin_resizehandle = function(curh) {
  813. return this.each(function() {
  814. var me = jQuery(this);
  815. me.animate({height: curh});
  816. me.after(
  817. jQuery('<div class="ied_plugin_resizehandle">--- + ---</div>').bind("mousedown", function(e) {
  818. var h = me.height();
  819. var y = e.clientY;
  820. var moveHandler = function(e) {
  821. me.height(Math.max(20, e.clientY + h - y));
  822. };
  823. var upHandler = function(e) {
  824. jQuery("html").unbind("mousemove",moveHandler).unbind("mouseup",upHandler);
  825. newh = me.height();
  826. setCookie('ied_plugin_edheight', newh, 365);
  827. };
  828. jQuery("html").bind("mousemove", moveHandler).bind("mouseup", upHandler);
  829. })
  830. );
  831. });
  832. }
  833. jQuery.fn.selectRange = function(start, end) {
  834. return this.each(function() {
  835. if(this.setSelectionRange) {
  836. this.focus();
  837. this.setSelectionRange(start, end);
  838. } else if(this.createTextRange) {
  839. var range = this.createTextRange();
  840. range.collapse(true);
  841. range.moveEnd('character', end);
  842. range.moveStart('character', start);
  843. range.select();
  844. }
  845. });
  846. };
  847. Array.prototype.unique = function () {
  848. var r = new Array();
  849. o:for(var i = 0, n = this.length; i < n; i++) {
  850. for(var x = 0, y = r.length; x < y; x++) {
  851. if(r[x]==this[i]) {
  852. continue o;
  853. }
  854. }
  855. r[r.length] = this[i];
  856. }
  857. return r;
  858. }
  859. function ied_goToLine() {
  860. var line = parseInt(jQuery('#ied_plugin_jumpToLine').val());
  861. var ied_ed = jQuery('#plugin_editor');
  862. var ied_edd = document.getElementById('plugin_editor'); // Dunno how to convert a jQuery obj back to DOM
  863. var lines = ied_ed.val().split('\\n');
  864. var numchars = 0;
  865. var count = 0;
  866. var findstr = '';
  867. jQuery.each(lines, function() {
  868. count++;
  869. if (count >= line) {
  870. findstr = this;
  871. return false;
  872. }
  873. numchars += (this.length)+2; // Don't ask. +2 is something to do with line endings I think
  874. });
  875. // Find the line containing the string we found. Start counting from the line before.
  876. // Those pesky line endings come into play again so we need to subtract the number
  877. // of lines found from the start character position *shrug*
  878. start = ied_ed.val().indexOf(findstr, numchars-count);
  879. start = (findstr == '') ? start+1 : start;
  880. end = start+findstr.length;
  881. ied_ed.selectRange(end-1, end);
  882. if(document.createEvent) {
  883. var ied_theCode = ied_ed.val().charCodeAt(end-1);
  884. if( window.KeyEvent ) {
  885. var ev = document.createEvent('KeyEvents');
  886. ev.initKeyEvent('keypress', false, true, window, false, false, false, false, 0, ied_theCode);
  887. } else {
  888. var ev = document.createEvent('UIEvents');
  889. ev.initUIEvent('keypress', false, true, window, 0);
  890. ev.keyCode = ied_theCode;
  891. }
  892. ied_edd.dispatchEvent(ev); // cause scroll to cursor by replacing last char with itself
  893. }
  894. ied_ed.selectRange(start, end);
  895. return false;
  896. }
  897. function ied_plugin_toggle_msgpop(state) {
  898. var obj = jQuery("#ied_plugin_msgpop");
  899. if (state != undefined) {
  900. if (state == 1) {
  901. obj.show('normal');
  902. } else {
  903. obj.hide('normal');
  904. }
  905. } else {
  906. obj.toggle('normal');
  907. }
  908. }
  909. function ied_plugin_rtrim(str, chars) {
  910. chars = chars || "\s";
  911. return str.replace(new RegExp("[" + chars + "]+$", "g"), "");
  912. }
  913. function ied_plugin_update_tp_count() {
  914. var tp_count = tp_warns = 0;
  915. jQuery('#ied_plugin_tp_strings ul label').each(function() {
  916. tp_count++;
  917. if (jQuery(this).hasClass('warning')) {
  918. tp_warns++;
  919. }
  920. });
  921. jQuery('#ied_plugin_tp_count').empty().append('('+tp_count+ ' | '+tp_warns+ ' warnings)');
  922. // Update the global var for use when loading strings
  923. ied_plugin_tp_total = tp_count;
  924. }
  925. jQuery(function() {
  926. curh = getCookie('ied_plugin_edheight');
  927. curh = (curh == null) ? '480' : curh;
  928. jQuery("#plugin_editor").ied_plugin_resizehandle(parseInt(curh));
  929. jQuery('textarea[maxlength]').keyup(function(){
  930. var max = parseInt(jQuery(this).attr('maxlength'));
  931. if(jQuery(this).val().length > max){
  932. jQuery(this).val(jQuery(this).val().substr(0, jQuery(this).attr('maxlength')));
  933. }
  934. jQuery(this).parent().find('.ied_plugin_charsRemain').html('Chars remaining: '+ (max - jQuery(this).val().length));
  935. });
  936. jQuery('textarea[maxlength]').keyup();
  937. jQuery('#ied_plugin_jumpToLine').keydown(function(e) {
  938. var code = (e.keyCode ? e.keyCode : e.which);
  939. if(code == 13) {
  940. e.preventDefault();
  941. e.stopPropagation();
  942. ied_goToLine();
  943. return false;
  944. }
  945. });
  946. // Store the prefix
  947. jQuery('#ied_plugin_tp_prefix').blur(function() {
  948. var pfx = jQuery(this).val();
  949. sendAsyncEvent(
  950. {
  951. event: textpattern.event,
  952. step: 'ied_plugin_set_tp_prefix',
  953. plugin: '{$name}',
  954. prefix: pfx
  955. });
  956. });
  957. // Find all occurrences of gTxt('something')
  958. jQuery('#plugin_editor, #ied_plugin_tp_prefix').blur(function() {
  959. var ied_tp_pfx = jQuery('#ied_plugin_tp_prefix').val();
  960. if (ied_tp_pfx != '') {
  961. var ied_gtxt_re = /gTxt\([\'\"]([a-zA-Z0-9_]*?)[\"\'][,\)]/gi;
  962. var ied_tp_ta = jQuery('#plugin_editor').val().replace(/\s*/g,''); // Strip spaces to make lookups easier
  963. var ied_tp_items = ied_tp_ta.match(ied_gtxt_re);
  964. // if JS RegExp captured parenthical expressions in global searches or it was easy to inject variables
  965. // into new RegExp() calls, this loop could be avoided
  966. var ied_tp_used = [];
  967. for (var idx = 0; idx < ied_tp_items.length; idx++) {
  968. var pos = ied_tp_items[idx].lastIndexOf("'");
  969. pos = (pos == -1) ? ied_tp_items[idx].lastIndexOf('"') : pos;
  970. tpstr = ied_tp_items[idx].substr(6,pos-6);
  971. if (tpstr.indexOf(ied_tp_pfx) == 0) {
  972. ied_tp_used[ied_tp_used.length] = tpstr;
  973. }
  974. }
  975. ied_tp_used = ied_tp_used.unique();
  976. // List of all current textpack strings in use (as of last Save operation)
  977. var ied_tp_curr = [];
  978. jQuery('#ied_plugin_tp_strings label').each(function() {
  979. ied_tp_curr[ied_tp_curr.length] = jQuery(this).text();
  980. });
  981. // Iterate over current array and check if each name is in the used textpack item list.
  982. // If it is, remove it from the final list.
  983. for (var idx = 0; idx < ied_tp_curr.length; idx++) {
  984. if ((pos = jQuery.inArray(ied_tp_curr[idx], ied_tp_used)) > -1) {
  985. ied_tp_used.splice(pos, 1);
  986. jQuery('#ied_plugin_tp_strings ul label:contains('+ied_tp_curr[idx]+')').toggleClass('warning', false).next(".ied_plugin_xbtn").remove();
  987. } else {
  988. setclass = 1;
  989. jQuery('#ied_plugin_tp_strings ul label:contains('+ied_tp_curr[idx]+')').toggleClass('warning', true).next(".ied_plugin_xbtn").remove().end().after('<a href="#" class="ied_plugin_xbtn">[x]</a>');
  990. }
  991. }
  992. // For each remaining item that has been used, add an input box
  993. // TODO: i18n the select options
  994. for (var idx = 0; idx < ied_tp_used.length; idx++) {
  995. jQuery('#ied_plugin_tp_strings ul').prepend('<li><input type="text" name="textpack_'+ied_tp_used[idx]+'" value="" /> <select name="ied_plugin_tp_event"><option value="admin">Admin</option><option value="public">Public</option><option value="common">Both</option></select> <label>'+ied_tp_used[idx]+'</label></li>');
  996. }
  997. ied_plugin_update_tp_count();
  998. }
  999. }).blur();
  1000. // Handle adding new strings manually
  1001. jQuery('#ied_plugin_add_string').click(function(ev) {
  1002. jQuery('#ied_plugin_tp_strings ul').before('<div id="ied_plugin_new_container"><label>'+jQuery('#ied_plugin_tp_prefix').val()+'_<input type="text" name="ied_plugin_tp_newname" id="ied_plugin_tp_newname" value="" /></label></div>');
  1003. jQuery('#ied_plugin_tp_newname').focus();
  1004. ev.preventDefault();
  1005. });
  1006. jQuery(document).on('blur', '#ied_plugin_tp_newname', function() {
  1007. var newname = ied_plugin_rtrim(jQuery('#ied_plugin_tp_prefix').val()+'_'+jQuery('#ied_plugin_tp_newname').val(), '_');
  1008. var newok = true;
  1009. jQuery('#ied_plugin_tp_strings ul li label').each(function() {
  1010. if (jQuery(this).text() == newname) {
  1011. jQuery('#ied_plugin_tp_newname').css('color', '#E00');
  1012. newok = false;
  1013. }
  1014. });
  1015. // TODO: i18n select option text
  1016. if (newok) {
  1017. jQuery('#ied_plugin_tp_strings ul').prepend('<li><input type="text" name="textpack_'+newname+'" value="" /> <select name="ied_plugin_tp_event"><option value="admin">Admin</option><option value="public">Public</option><option value="common">Both</option></select> <label>'+newname+'</label></li>');
  1018. jQuery('#ied_plugin_new_container').remove();
  1019. jQuery('input[name="textpack_'+newname+'"]').focus();
  1020. }
  1021. ied_plugin_update_tp_count();
  1022. });
  1023. // Initialise the generic AJAX error handler
  1024. jQuery('.ied_editForm').ajaxError(function(event, request, settings) {
  1025. var xhr = jQuery(request.responseText);
  1026. // phpdoc generation barfed
  1027. if (settings.data.indexOf('step=ied_plugin_generate_phpdoc') > -1)

Large files files are truncated, but you can click here to view the full file