PageRenderTime 73ms CodeModel.GetById 36ms RepoModel.GetById 0ms app.codeStats 0ms

/adi_recent_tab/adi_recent_tab.php

https://bitbucket.org/mrdale/txp-plugins
PHP | 1208 lines | 809 code | 134 blank | 265 comment | 248 complexity | 6872388b745edf454fc8988097281617 MD5 | raw 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'] = 'adi_recent_tab';
  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'] = '0.6';
  16. $plugin['author'] = 'Adi Gilbert';
  17. $plugin['author_uri'] = 'http://www.greatoceanmedia.com.au/';
  18. $plugin['description'] = 'Recent Items Tab';
  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'] = '1';
  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'] = '3';
  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. /*
  62. adi_recent_tab - Recent Items Tab
  63. Written by Adi Gilbert
  64. Released under the GNU General Public License
  65. Version history:
  66. 0.6 - refixed for critical, admin interface killing, bug in TXP 4.6
  67. - responsive layout & styling for recent items tab
  68. - fix: recognises "upload file from existing"
  69. - enhancement: pref for image alt text (for Uli)
  70. 0.5 - change: IDs display switched on by default
  71. - change: articles heading link now goes to Articles (list) tab rather than Write
  72. - fix: error when reordering images/files in list
  73. - fix: error when changing number of items per page
  74. - fix: error when file upload failed (e.g. file too big/file already exists)
  75. - fix: article titles etc that are blank with multiple spaces are treated as Untitled
  76. - fix: unslashed quotes in DB queries
  77. - fix: tabs no longer listed if user lacks privs
  78. - fix: upload thumbnail now ignored
  79. - fix: all new section names sanitised & recognised
  80. - enhancement: plugin privs
  81. - code tidy up (thanks gocom)
  82. - TXP 4.5+
  83. - tested & fixed for TXP 4.6
  84. 0.4 - TXP 4.5-ified (particularly to cope with new Sections tab & new-style Links tab)
  85. - fix: record new links properly
  86. - fix: losing image (file) name if both alt & caption blank
  87. 0.3 - style improvements to cope with long titles
  88. - fix: style for latest version of Hive theme (thanks Uli)
  89. - fix: error message in images & files search result page (thanks Uli)
  90. 0.2 - fix: cope with image replace & file replace properly
  91. - fix: cope with style create/save/delete properly
  92. - new pref: include article/image/link/file IDs
  93. 0.1 - initial release
  94. */
  95. if (@txpinterface == 'admin') {
  96. global $adi_recent_tab_debug;
  97. $adi_recent_tab_debug = 0;
  98. if (!version_compare(txp_version,'4.5.0','>=')) return;
  99. adi_recent_tab_init();
  100. }
  101. function adi_recent_tab_init() {
  102. global $event,$step,$textarray,$txp_user,$prefs,$adi_recent_tab_outlaws,$adi_recent_tab_url,$adi_recent_tab_plugin_status,$adi_recent_tab_event_gtxt,$adi_recent_tab_include,$adi_recent_tab_exclude_combo,$adi_recent_tab_include_combo,$adi_recent_tab_prefs,$adi_recent_tab_debug,$adi_recent_tab_txp460;
  103. // meet the new boss?
  104. $adi_recent_tab_txp460 = (version_compare(txp_version,'4.6-dev','>='));
  105. // plugin lifecycle
  106. register_callback('adi_recent_tab_lifecycle','plugin_lifecycle.adi_recent_tab');
  107. // Textpack
  108. $adi_recent_tab_url = array(
  109. 'textpack' => 'http://www.greatoceanmedia.com.au/files/adi_textpack.txt',
  110. 'textpack_download' => 'http://www.greatoceanmedia.com.au/textpack/download',
  111. 'textpack_feedback' => 'http://www.greatoceanmedia.com.au/textpack/?plugin=adi_recent_tab',
  112. );
  113. if (strpos($prefs['plugin_cache_dir'],'adi') !== FALSE) // use Adi's local version
  114. $adi_recent_tab_url['textpack'] = $prefs['plugin_cache_dir'].'/adi_textpack.txt';
  115. # --- BEGIN PLUGIN TEXTPACK ---
  116. $adi_recent_tab_gtxt = array(
  117. 'adi_include' => 'Include:',
  118. 'adi_include_ids' => 'Include IDs',
  119. 'adi_install_fail' => 'Unable to install',
  120. 'adi_installed' => 'Installed',
  121. 'adi_pref_update_fail' => 'Preference update failed',
  122. 'adi_recent_items' => 'Recent items',
  123. 'adi_recent_tab' => 'Recent',
  124. 'adi_recent_tab_max_items' => 'Maximum number of items',
  125. 'adi_tab' => 'Tab',
  126. 'adi_textpack' => 'Textpack',
  127. 'adi_textpack_fail' => 'Textpack installation failed',
  128. 'adi_textpack_feedback' => 'Textpack feedback',
  129. 'adi_textpack_online' => 'Textpack also available online',
  130. 'adi_uninstall' => 'Uninstall',
  131. 'adi_uninstall_fail' => 'Unable to uninstall',
  132. 'adi_uninstalled' => 'Uninstalled',
  133. 'adi_update_prefs' => 'Update preferences',
  134. );
  135. # --- END PLUGIN TEXTPACK ---
  136. // update $textarray
  137. $textarray += $adi_recent_tab_gtxt;
  138. /*
  139. Events & Steps - A minefield of inconsistencies ...
  140. Step other vars
  141. Event=article
  142. Write create - (empty create tab)
  143. Edit edit ID
  144. Save edit ID
  145. Publish create -> edit $GLOBALS['ID']
  146. Event=image
  147. Images list -
  148. (search) image_list
  149. (sort) list
  150. (paging) image_change_pageby
  151. Image upload image_insert $GLOBALS['ID']
  152. Image edit image_edit id
  153. Image save image_edit id
  154. Image replace image_replace id
  155. Thumbnail upld thumbnail_insert
  156. Event=page
  157. Pages/default -
  158. Page edit - name
  159. Save page_save name
  160. Copy page_save name, newname
  161. Create page page_save newname
  162. Event=form
  163. Forms/default -
  164. Form edit form_edit name
  165. Form save form_save
  166. Event=link
  167. Links list - -> link_edit
  168. (search) link_list
  169. (sort) list
  170. (paging) link_change_pageby
  171. Link edit link_edit id
  172. Link save link_save id
  173. Link create link_post $GLOBALS['ID'] (pre-4.5.0)
  174. Link create link_save $GLOBALS['ID'] (post-4.5.0)
  175. Event=file
  176. Files list -
  177. (search) file_list
  178. (sort) list
  179. (paging) file_change_pageby
  180. Upload file_insert $GLOBALS['ID']
  181. Save file_save ?
  182. File edit file_edit id
  183. File replace file_replace id
  184. From existing file_create name
  185. Event=css
  186. Style/default -
  187. Style edit - name
  188. Save css_save name
  189. New style pour newname
  190. Copy style css_save name
  191. Event=section
  192. Section list -
  193. (search) sec_section_list
  194. (sort) list
  195. (paging) section_change_pageby
  196. Section edit section_edit name
  197. Section create section_edit - (empty create tab)
  198. Section save section_save name
  199. Section create section_save newname (post-4.5.0)
  200. */
  201. // the privileged few ...
  202. $adi_recent_tab_include = array('article','image','page','form','link','file','css','section'); // if you're not on the list, you're not getting in
  203. // privileges for the privileged
  204. $adi_recent_tab_include_privs = array(
  205. 'article' => 'list',
  206. 'image' => 'image',
  207. 'page' => 'page',
  208. 'form' => 'form',
  209. 'link' => 'link',
  210. 'file' => 'file',
  211. 'css' => 'css',
  212. 'section' => 'section',
  213. );
  214. if ($adi_recent_tab_debug)
  215. foreach ($adi_recent_tab_include as $index => $tab)
  216. if (has_privs($adi_recent_tab_include_privs[$tab]))
  217. echo $tab.sp.'- has privs'.br;
  218. else
  219. echo $tab.sp.'- no privs'.br;
  220. // weed out the unworthy
  221. foreach ($adi_recent_tab_include as $index => $tab)
  222. if (!has_privs($adi_recent_tab_include_privs[$tab]))
  223. unset($adi_recent_tab_include[$index]);
  224. // it's what we call 'em
  225. $adi_recent_tab_event_gtxt = array(
  226. 'article' => 'tab_list',
  227. 'css' => 'tab_style',
  228. 'file' => 'tab_file',
  229. 'form' => 'tab_forms',
  230. 'image' => 'tab_image',
  231. 'link' => 'tab_link',
  232. 'page' => 'tab_pages',
  233. 'section' => 'tab_sections',
  234. );
  235. // not so fast ...
  236. $adi_recent_tab_exclude_combo[] = array('event' => '^article$', 'step' => '^$'); // empty create article tab - event="article", step=blank
  237. $adi_recent_tab_exclude_combo[] = array('event' => '^image$', 'step' => '^$'); // image list tab - event="image", step=blank
  238. $adi_recent_tab_exclude_combo[] = array('event' => '^image$', 'step' => 'image_multi_edit'); // image list multi-edit - event="image", step contains image_multi_edit
  239. $adi_recent_tab_exclude_combo[] = array('event' => '^image$', 'step' => 'image_replace'); // image replace - event="image", step contains image_multi_edit
  240. $adi_recent_tab_exclude_combo[] = array('event' => '^image$', 'step' => 'list'); // image list - event="image", step contains list (search results=image_list,sort=list)
  241. $adi_recent_tab_exclude_combo[] = array('event' => '^image$', 'step' => '^thumbnail_insert$'); // thumbnail upload - event="image", step=thumbnail_insert
  242. $adi_recent_tab_exclude_combo[] = array('event' => '^page$', 'step' => 'page_new'); // new page tab - event="page", step contains page_new
  243. $adi_recent_tab_exclude_combo[] = array('event' => '^form$', 'step' => 'form_multi_edit'); // form list multi-edit - event="form", step contains form_multi_edit
  244. $adi_recent_tab_exclude_combo[] = array('event' => '^link$', 'step' => 'link_edit', 'id' => '^$'); // link list tab
  245. $adi_recent_tab_exclude_combo[] = array('event' => '^link$', 'id' => '^$'); // TXP 4.5 link list tab
  246. $adi_recent_tab_exclude_combo[] = array('event' => '^link$', 'step' => 'link_multi_edit'); // link list tab - event="link", step contains link_multi_edit
  247. $adi_recent_tab_exclude_combo[] = array('event' => '^file$', 'step' => '^$'); // file list tab - event="file", step=blank
  248. $adi_recent_tab_exclude_combo[] = array('event' => '^file$', 'step' => 'file_replace'); // file replace - event="file", step contains file_replace
  249. $adi_recent_tab_exclude_combo[] = array('event' => '^file$', 'step' => 'list'); // file list - event="file", step contains list (search results=file_list,sort=list)
  250. $adi_recent_tab_exclude_combo[] = array('event' => '^css$', 'step' => 'pour'); // style list tab - event="css", step=pour (create style)
  251. $adi_recent_tab_exclude_combo[] = array('event' => '^section$', 'step' => 'section_edit', 'name' => '^$'); // empty section create tab (TXP 4.5.0)
  252. $adi_recent_tab_exclude_combo[] = array('event' => '^section$', 'step' => 'list'); // section list - event="section", step contains list (search results=sec_section_list,sort=list)
  253. $adi_recent_tab_exclude_combo[] = array('event' => '.*', 'step' => 'save'); // any step containing "save" (e.g. page_save, form_save, link_save)
  254. $adi_recent_tab_exclude_combo[] = array('event' => '.*', 'step' => 'create'); // any step containing "create" (e.g. new article create, form create)
  255. $adi_recent_tab_exclude_combo[] = array('event' => '.*', 'step' => 'apply'); // any step containing "apply" - just in case!
  256. $adi_recent_tab_exclude_combo[] = array('event' => '.*', 'step' => 'update'); // any step containing "update" - just in case!
  257. $adi_recent_tab_exclude_combo[] = array('event' => '.*', 'step' => 'delete'); // any step containing "delete" - just in case!
  258. $adi_recent_tab_exclude_combo[] = array('event' => '.*', 'step' => 'change_pageby'); // any step containing "change_pageby", e.g. image_change_pageby, when changing # per page
  259. // don't log initial page/form/style tab visit (i.e. default by default)
  260. $adi_recent_tab_exclude_combo[] = array('event' => '^page$', 'step' => '^$', 'name' => '^$'); // default page tab (i.e. edit default)
  261. $adi_recent_tab_exclude_combo[] = array('event' => '^form$', 'step' => '^$', 'name' => '^$'); // default form tab (i.e. edit default)
  262. $adi_recent_tab_exclude_combo[] = array('event' => '^css$', 'step' => '^$', 'name' => '^$'); // default style tab (i.e. edit default)
  263. $adi_recent_tab_exclude_combo[] = array('event' => '^section$', 'step' => '^$', 'name' => '^$'); // default section list tab (TXP 4.5.0)
  264. // oh, go on then ...
  265. $adi_recent_tab_include_combo[] = array('event' => 'page', 'step' => 'page_save'); // create new page
  266. $adi_recent_tab_include_combo[] = array('event' => 'form', 'step' => 'form_save'); // create new form
  267. $adi_recent_tab_include_combo[] = array('event' => 'css', 'step' => 'css_save'); // create new form
  268. $adi_recent_tab_include_combo[] = array('event' => 'file', 'step' => 'file_create'); // create file from existing
  269. $adi_recent_tab_include_combo[] = array('event' => 'link', 'step' => 'link_post'); // create new link (pre-4.5.0)
  270. $adi_recent_tab_include_combo[] = array('event' => 'link', 'step' => 'link_save'); // create new link (post-4.5.0)
  271. $adi_recent_tab_include_combo[] = array('event' => 'section', 'step' => 'section_save'); // create new section (TXP 4.5.0+)
  272. // preferences & defaults
  273. $adi_recent_tab_prefs = array(
  274. 'adi_recent_tab_privs' => array('value' => '1,2,3,4,5,6', 'blank' => 1, 'private' => 0, 'input' => 'custom', 'label' => 'adi_plugin_privs', 'tab' => 'options'), // allowed to use plugin
  275. 'adi_recent_tab_list' => array('value' => implode(',',$adi_recent_tab_include), 'blank' => 0, 'private' => 1, 'input' => 'custom', 'label' => 'adi_include', 'tab' => 'admin'),
  276. 'adi_recent_tab_max_items' => array('value' => '5', 'blank' => 0, 'private' => 1, 'input' => 'text_input', 'label' => 'adi_recent_tab_max_items', 'tab' => 'admin'),
  277. 'adi_recent_tab_ids' => array('value' => '1', 'blank' => 1, 'private' => 1, 'input' => 'yesnoradio', 'label' => 'adi_include_ids', 'tab' => 'admin'),
  278. 'adi_recent_tab_img_alt' => array('value' => '1', 'blank' => 1, 'private' => 1, 'input' => 'yesnoradio', 'label' => 'alt_text', 'tab' => 'admin'),
  279. );
  280. // plugin privs to be excluded
  281. $adi_recent_tab_outlaws = array(0);
  282. // who's playing today?
  283. add_privs('adi_recent_tab',adi_recent_tab_pref('adi_recent_tab_privs')); // recent items tab
  284. add_privs('tab.recent',adi_recent_tab_pref('adi_recent_tab_privs')); // recent items menu
  285. // do the business
  286. if (adi_recent_tab_installed() && has_privs('adi_recent_tab')) {
  287. // menu style for all
  288. register_callback('adi_recent_tab_menu_style','admin_side','head_end');
  289. // tab style for tab only
  290. if ($event == "adi_recent_tab")
  291. register_callback('adi_recent_tab_style','admin_side','head_end');
  292. // adi_recent_tab tab
  293. register_callback("adi_recent_tab","adi_recent_tab");
  294. $textarray['tab_recent'] = gTxt('adi_recent_tab'); // to get something meaningful into tab
  295. // put logger in the footer - to catch the elusive newly created article/image IDs etc
  296. register_callback('adi_recent_tab_logger','admin_side','footer');
  297. // TXP 4.5: recent tab under recent items menu; TXP 4.6: recent tab under extensions menu (due to lack of top-level click-through)
  298. if ($adi_recent_tab_txp460) {
  299. // recent items tab under extensions
  300. register_tab('extensions','adi_recent_tab',gTxt('adi_recent_items'));
  301. // separate recent items menu
  302. add_privs('adi_recent_tab_menu',adi_recent_tab_pref('adi_recent_tab_privs')); // recent items tab
  303. register_tab('recent','adi_recent_tab_menu',gTxt('adi_recent_items'));
  304. register_callback('adi_recent_tab_menu','adi_recent_tab_menu');
  305. // inject markup to create recent items menu
  306. register_callback('adi_recent_tab_menu_markup_mega','admin_side','footer'); // markup in the footer, shifted by jQuery
  307. }
  308. else {
  309. // recent items tab under separate recent items menu
  310. register_tab('recent','adi_recent_tab',gTxt('adi_recent_items'));
  311. // inject markup to create recent items menu
  312. adi_recent_tab_menu_ob();
  313. }
  314. }
  315. // script
  316. if ($adi_recent_tab_txp460)
  317. register_callback('adi_recent_tab_script','admin_side','head_end');
  318. // plugin options
  319. $adi_recent_tab_plugin_status = fetch('status','txp_plugin','name','adi_recent_tab');
  320. if ($adi_recent_tab_plugin_status) { // proper install - options under Plugins tab
  321. add_privs('plugin_prefs.adi_recent_tab','1,2,6');
  322. register_callback('adi_recent_tab_options','plugin_prefs.adi_recent_tab');
  323. }
  324. else { // txpdev - options under Extensions tab
  325. add_privs('adi_recent_tab_options','1,2,6');
  326. register_tab('extensions','adi_recent_tab_options','adi_recent_tab options');
  327. register_callback('adi_recent_tab_options','adi_recent_tab_options');
  328. }
  329. }
  330. function adi_recent_tab_style() {
  331. // style for tab
  332. echo
  333. '<style type="text/css">
  334. /* adi_recent_tab */
  335. #adi_recent_tab_tab, #adi_recent_tab_tab ul { overflow:hidden; list-style:none; margin:0; padding:0 }
  336. #adi_recent_tab_tab li { list-style:none; margin:0; padding:0 }
  337. #adi_recent_tab_tab > li { float:left; width:47%; margin:0 6% 1% 0 }
  338. #adi_recent_tab_tab > li:nth-child(2n) { margin-right:0 }
  339. #adi_recent_tab .adi_recent_tab_prefs { margin:4em 0 2em; border-top:1px solid #ccc }
  340. #adi_recent_tab input.adi_recent_tab_max_items { width:3em }
  341. /* responsive */
  342. @media (max-width: 47em) {
  343. #adi_recent_tab_tab > li { float:none; width:100% }
  344. .adi_recent_tab_prefs p.adi_recent_tab_list label { display:block; margin-top:0.5em }
  345. }
  346. /* TXP 4.5 */
  347. div.txp-body h1, div.txp-body h2 { font-weight:bold }
  348. div.txp-body .adi_recent_tab_prefs h2 { margin-top:0.5em }
  349. /* Hive TXP 4.5 adjustments - recent tab page given class="recent" which is Hive styling for Recent Articles! */
  350. .txp-nav li { margin-left:0 }
  351. </style>';
  352. }
  353. function adi_recent_tab_menu_style() {
  354. // style for dropdown menu
  355. echo
  356. '<style type="text/css">
  357. /* adi_recent_tab */
  358. /* TXP 4.5 Remora */
  359. #nav .adi_recent_tab_menu_title { font-weight:bold }
  360. #nav a[href="?event=adi_recent_tab"] + ul { width:25em; padding-top:0.5em; padding-bottom:0.5em }
  361. #nav a[href="?event=adi_recent_tab"] + ul li { width:auto; height:auto }
  362. #nav a[href="?event=adi_recent_tab"] + ul li:first-child { display:none }
  363. #nav a[href="?event=adi_recent_tab"] + ul li a { width:23em; height:auto; line-height:1.2; padding-top:0.3em; padding-bottom:0.3em }
  364. #nav a[href="?event=adi_recent_tab"] + ul li a span { font-weight:bold }
  365. .txp-header #nav a[href="?event=adi_recent_tab"] + ul { z-index:9999 }
  366. /* TXP 4.5 Hive */
  367. div.txp-nav .adi_recent_tab_menu_title { font-weight:bold }
  368. div.txp-nav a[href="?event=adi_recent_tab"] + ul { padding-bottom:0.5em }
  369. div.txp-nav a[href="?event=adi_recent_tab"] + ul { width:25em }
  370. div.txp-nav a[href="?event=adi_recent_tab"] + ul > li { float:none; width:auto }
  371. div.txp-nav a[href="?event=adi_recent_tab"] + ul > li:hover { background-color:#ffefaf }
  372. /* TXP 4.6 Hive */
  373. nav.txp-nav a[href="?event=adi_recent_tab"] + ul > li:first-child { display:none }
  374. nav.txp-nav a[href="?event=adi_recent_tab"] + ul { width:50em }
  375. nav.txp-nav a[href="?event=adi_recent_tab"] + ul > li { float:left; width:50% }
  376. nav.txp-nav a[href="?event=adi_recent_tab"] + ul > li:hover { background-color:transparent }
  377. nav.txp-nav a[href="?event=adi_recent_tab"] + ul > li:nth-child(2n) { clear:left }
  378. nav.txp-nav a[href="?event=adi_recent_tab"] + ul li h2 { margin:0.5em 0 0; font-size:1em }
  379. nav.txp-nav a[href="?event=adi_recent_tab"] + ul li h2:hover { background-color:#ffefaf }
  380. nav.txp-nav a[href="?event=adi_recent_tab"] + ul li a { width:auto; padding-top:0.3em; padding-bottom:0.3em; word-wrap:break-word }
  381. nav.txp-nav a[href="?event=adi_recent_tab"] + ul ul { width:auto }
  382. nav.txp-nav a[href="?event=adi_recent_tab"] + ul { left:-20em; border-radius:0.5em }
  383. nav.txp-nav a[href="?event=adi_recent_tab"] + ul:before { left:18em } /* the pointy bit */
  384. /* bot_write_tab_customize tab overrides */
  385. body#page-bot_wtc_tab .txp-nav a[href="?event=adi_recent_tab"] + ul li h2 { margin:0.5em 0 0; padding:0; text-align:left }
  386. /* responsive */
  387. @media (max-width: 47em) {
  388. nav.txp-nav a[href="?event=adi_recent_tab"] + ul { width:auto }
  389. nav.txp-nav a[href="?event=adi_recent_tab"] + ul li a { width:auto; padding-top:0.5em; padding-bottom:0.5em }
  390. }
  391. </style>';
  392. }
  393. function adi_recent_tab_script() {
  394. // scriptimus
  395. echo <<<END_SCRIPT
  396. <script type="text/javascript">
  397. $(function() {
  398. // adi_recent_tab menu
  399. var closest_ul = $('a[href="?event=adi_recent_tab_menu"]').closest("ul"); // find (grand)parent ul
  400. var menu_id = $(closest_ul).attr('id'); // i.e. "#txp-nav-dropX-menu"
  401. $("ul#adi_recent_tab_inject > li").insertAfter($("ul#" + menu_id + " li")); // shift recent menu items from footer
  402. $("ul#adi_recent_tab_inject").remove(); // footer housekeeping
  403. var top_link = $(closest_ul).prev(); // get top level menu item link
  404. $(top_link).attr("href","?event=adi_recent_tab"); // restore click-through to recent_tab tab (also allows some styles to kick in)
  405. });
  406. </script>
  407. END_SCRIPT;
  408. }
  409. function adi_recent_tab_logger() {
  410. // monitor each TXP admin page visit & decide what's to be recorded by adi_recent_tab
  411. global $DB,$adi_recent_tab_debug,$event,$step,$txp_user,$adi_recent_tab_include,$adi_recent_tab_exclude_combo,$adi_recent_tab_include_combo,$adi_recent_tab_txp460;
  412. if (!adi_recent_tab_installed()) // in case it's just been uninstalled
  413. return;
  414. $id = gps('id'); // image id
  415. $name = gps('name'); // section/page/form/image name
  416. if ($adi_recent_tab_debug) {
  417. echo 'Event='.$event.', Final Step='.$step.', supplied id='.$id.', supplied name='.$name.'<br/>';
  418. echo 'Include event list:';
  419. dmp($adi_recent_tab_include);
  420. echo 'Exclude combo list:';
  421. dmp($adi_recent_tab_exclude_combo);
  422. echo 'Include combo list:';
  423. dmp($adi_recent_tab_include_combo);
  424. }
  425. // process included & excluded events/steps
  426. // events of interest
  427. $exclude = array_search($event,$adi_recent_tab_include) === FALSE;
  428. if ($adi_recent_tab_debug && $exclude)
  429. echo '($adi_recent_tab_include) EXCLUDE EVENT: '.$event.'<br/>';
  430. // sort the men from the boys
  431. if (!$exclude) {
  432. // event/step combos to be discounted
  433. $exclude = adi_recent_tab_filter($adi_recent_tab_exclude_combo,$event,$step,$id,$name);
  434. if ($adi_recent_tab_debug && $exclude)
  435. echo '($adi_recent_tab_exclude_combo) '."EXCLUDED EVENT/STEP/ID/NAME: $event,$step,$id,$name<br/>";
  436. // explicitly include these combos
  437. $include = adi_recent_tab_filter($adi_recent_tab_include_combo,$event,$step,$id,$name);
  438. if ($adi_recent_tab_debug && $include)
  439. echo '($adi_recent_tab_include_combo) '."INCLUDED EVENT/STEP/ID/NAME: $event,$step,$id,$name<br/>";
  440. if ($include)
  441. $exclude = FALSE;
  442. }
  443. if (!$exclude) { // massage stuff
  444. // ID
  445. if (empty($id)) // try finding an article ID
  446. $id = gps('ID');
  447. if (isset($GLOBALS['ID'])) // set the "newly created" ID to something
  448. $globals_id = $GLOBALS['ID'];
  449. else
  450. $globals_id = '';
  451. if (empty($id) && ($event == 'article')) // i.e. a newly created article
  452. $id = $globals_id;
  453. if (empty($id) && ($event == 'image')) // i.e. a newly created image
  454. $id = $globals_id;
  455. if (empty($id) && ($event == 'link')) // i.e. a newly created link
  456. $id = $globals_id;
  457. if (empty($id) && ($event == 'file')) // i.e. a newly uploaded file
  458. $id = $globals_id;
  459. // NAME
  460. if (($event == 'section') && ($step == 'section_save'))
  461. $name = strtolower(sanitizeForUrl($name)); // sanitise (create/edit) section name (from txp_section.php)
  462. if ((($event == 'page') || ($event == 'form')) && empty($name)) // fill in the "default" blank - needed if logging initial page/form tab visit
  463. $name = 'default';
  464. if ($event == 'image') // don't want to store image name coz we've got the ID (& the name might change)
  465. $name = '';
  466. $newname = sanitizeForPage(gps('newname')); // sanitise (create/copy) page name
  467. if ($newname)
  468. $name = $newname;
  469. // STEP
  470. $this_step = $step;
  471. if (($event== 'image') && ($step == 'image_insert')) // tweak step - new image
  472. $this_step = 'image_edit';
  473. if (($event== 'page') && ($step == 'page_save')) // new/save page
  474. $this_step = '';
  475. if (($event== 'form') && ($step == 'form_save')) // new/save form
  476. $this_step = 'form_edit';
  477. if (($event== 'css') && ($step == 'css_save')) // new style/save style
  478. $this_step = '';
  479. if (($event== 'form') && ($step == '')) // tweak step - click between forms
  480. $this_step = 'form_edit';
  481. if (($event== 'link') && ($step == 'link_post')) // new link (pre-4.5.0)
  482. $this_step = 'link_edit';
  483. if (($event== 'link') && ($step == 'link_save')) // new link (post-4.5.0)
  484. $this_step = 'link_edit';
  485. if (($event== 'section') && ($step == 'section_save')) // new section (post-4.5.0)
  486. $this_step = 'section_edit';
  487. if (($event== 'file') && ($step == 'file_insert')) // new file
  488. $this_step = 'file_edit';
  489. if (($event== 'file') && ($step == 'file_create')) // new file from existing
  490. $this_step = 'file_edit';
  491. if ($adi_recent_tab_debug)
  492. echo 'Event='.$event.', this_step='.$this_step.', massaged id='.$id.', massaged name='.$name.'<br/>';
  493. if ($id == '' && (($event == 'article') || ($event == 'image') || ($event == 'link') || ($event == 'file'))) {
  494. if ($adi_recent_tab_debug)
  495. echo 'No ID, no update!';
  496. }
  497. else {
  498. // update adi_recent_tab DB table
  499. $table = 'adi_recent_tab';
  500. $set = 'timestamp=now(), user="'.doSlash($txp_user).'", event="'.doSlash($event).'", step="'.doSlash($this_step).'", id="'.doSlash($id).'", name="'.doSlash($name).'"';
  501. $where = 'user="'.$txp_user.'" AND event="'.$event.'" AND step="'.$this_step.'" AND id="'.$id.'" AND name="'.$name.'"';
  502. // it's me own safe_upsert ...
  503. $r = safe_update($table,$set,$where,$adi_recent_tab_debug);
  504. if ($adi_recent_tab_txp460) {
  505. if (!($r and (mysqli_affected_rows($DB->link) or safe_count($table,$where,$adi_recent_tab_debug))))
  506. safe_insert($table,$set,$adi_recent_tab_debug);
  507. }
  508. else {
  509. if (!($r and (mysql_affected_rows() or safe_count($table,$where,$adi_recent_tab_debug))))
  510. safe_insert($table,$set,$adi_recent_tab_debug);
  511. }
  512. }
  513. }
  514. // tidy up
  515. adi_recent_tab_housekeeping();
  516. }
  517. function adi_recent_tab_filter($pattern_list,$event,$step,$id='',$name='') {
  518. // look for combination matches
  519. $match = FALSE;
  520. foreach ($pattern_list as $pair) {
  521. $this_match = TRUE;
  522. foreach ($pair as $var => $pattern)
  523. $this_match = $this_match && preg_match('/'.$pattern.'/',$$var);
  524. $match = $match || $this_match;
  525. }
  526. return $match;
  527. }
  528. function adi_recent_tab_installed($table='adi_recent_tab') {
  529. // test if table is present
  530. $rs = safe_query("SHOW TABLES LIKE '".safe_pfx($table)."'");
  531. $a = nextRow($rs);
  532. if ($a)
  533. return TRUE;
  534. else
  535. return FALSE;
  536. }
  537. function adi_recent_tab_install() {
  538. // install adi_recent_tab table in database
  539. global $adi_recent_tab_debug;
  540. $res = safe_query(
  541. // 'id' is a VARCHAR (rather than an INT) coz I need it to be blank sometimes
  542. "CREATE TABLE IF NOT EXISTS ".safe_pfx('adi_recent_tab')
  543. ."( `timestamp` datetime NOT NULL default '0000-00-00 00:00:00',
  544. `user` VARCHAR(64) NOT NULL DEFAULT '',
  545. `event` VARCHAR(64) NOT NULL DEFAULT '',
  546. `step` VARCHAR(64) NOT NULL DEFAULT '',
  547. `id` VARCHAR(12) NOT NULL DEFAULT '',
  548. `name` VARCHAR(64) NOT NULL DEFAULT ''
  549. );"
  550. ,$adi_recent_tab_debug);
  551. return $res;
  552. }
  553. function adi_recent_tab_uninstall() {
  554. // uninstall adi_recent_tab
  555. global $adi_recent_tab_debug,$adi_recent_tab_prefs;
  556. // delete table
  557. $res = safe_query("DROP TABLE ".safe_pfx('adi_recent_tab').";",$adi_recent_tab_debug);
  558. // delete preferences
  559. foreach ($adi_recent_tab_prefs as $this_pref => $value)
  560. $res = $res && safe_delete('txp_prefs',"name = '$this_pref'",$adi_recent_tab_debug);
  561. return $res;
  562. }
  563. function adi_recent_tab_lifecycle($event,$step) {
  564. // a matter of life & death
  565. // $event: "plugin_lifecycle.adi_recent_tab"
  566. // $step: "installed", "enabled", disabled", "deleted"
  567. // install/reinstall: "installed"; make active: "enabled"; make inactive: "disabled"; delete: "disabled" then "deleted"
  568. // (as of TXP 4.5, reinstall only triggers "installed" event)
  569. // adi_lifecycle: "installed" -> install() regardless, upgrade() if required; "deleted" -> uninstall(); "enabled" & disabled" -> do nothing
  570. global $adi_recent_tab_debug;
  571. $result = $upgrade_required = '?';
  572. if ($step == 'installed') {
  573. $result = adi_recent_tab_install();
  574. // $upgrade_required = adi_recent_tab_upgrade();
  575. // if ($upgrade_required)
  576. // $result &= adi_recent_tab_upgrade(TRUE);
  577. }
  578. if ($step == 'deleted')
  579. $result = adi_recent_tab_uninstall();
  580. if ($adi_recent_tab_debug)
  581. echo "event=$event,step=$step,result=$result,upgrade_required=$upgrade_required";
  582. }
  583. function adi_recent_tab_housekeeping() {
  584. // delete oldest recents that exceed max count; make sure items still exist in DB
  585. global $adi_recent_tab_debug,$txp_user,$adi_recent_tab_include,$adi_recent_tab_prefs;
  586. $max_recent = adi_recent_tab_pref('adi_recent_tab_max_items');
  587. $sort = ' ORDER BY timestamp desc';
  588. $default_where = " AND user='$txp_user'";
  589. if ($adi_recent_tab_debug)
  590. echo '<br/>Housekeeping (deceased entries):<br/>';
  591. // delete entries that don't exist ... the recently deceased
  592. foreach ($adi_recent_tab_include as $recent) {
  593. $table = 'txp_'.$recent;
  594. if ($recent == 'article')
  595. $table = 'textpattern';
  596. $rs = safe_rows('*','adi_recent_tab',"event='".$recent."'".$default_where.$sort,$adi_recent_tab_debug);
  597. foreach ($rs as $index => $row) {
  598. extract($row);
  599. // "id" entries
  600. if (($recent == 'article') || ($recent == 'image') || ($recent == 'link') || ($recent == 'file')) {
  601. $row = safe_row('*',$table,"id='$id'",$adi_recent_tab_debug);
  602. if (empty($row)) {
  603. $where = 'user="'.$txp_user.'" AND event="'.$event.'" AND step="'.$step.'" AND id="'.$id.'" AND name="'.doSlash($name).'"';
  604. safe_delete('adi_recent_tab',$where,$adi_recent_tab_debug);
  605. }
  606. }
  607. // "name" entries
  608. if (($recent == 'page') || ($recent == 'form') || ($recent == 'css') || ($recent == 'section')) {
  609. $row = safe_row('*',$table,"name='".doSlash($name)."'",$adi_recent_tab_debug);
  610. if (empty($row)) {
  611. $where = 'user="'.$txp_user.'" AND event="'.$event.'" AND step="'.$step.'" AND id="'.$id.'" AND name="'.doSlash($name).'"';
  612. safe_delete('adi_recent_tab',$where,$adi_recent_tab_debug);
  613. }
  614. }
  615. }
  616. }
  617. if ($adi_recent_tab_debug)
  618. echo 'Housekeeping (remove surplus):<br/>';
  619. // lose the surplus
  620. foreach ($adi_recent_tab_include as $recent) {
  621. $rs = safe_rows('*','adi_recent_tab',"event='".$recent."'".$default_where.$sort,$adi_recent_tab_debug);
  622. if (count($rs) > $max_recent)
  623. foreach ($rs as $index => $row) {
  624. extract($row);
  625. if (!($index < $max_recent)) {
  626. $where = 'user="'.$txp_user.'" AND event="'.$event.'" AND step="'.$step.'" AND id="'.$id.'" AND name="'.doSlash($name).'"'; // BIG GLOBAL FOR THIS WHERE???
  627. safe_delete('adi_recent_tab',$where,$adi_recent_tab_debug);
  628. }
  629. }
  630. }
  631. }
  632. function adi_recent_tab_links($event,$wrap=TRUE) {
  633. // return a <ul><li> or <li> of all the "recent" links
  634. global $adi_recent_tab_debug,$adi_recent_tab_prefs,$txp_user;
  635. // $sort_method = 'timestamp';
  636. $sort_method = 'alphanumeric';
  637. $default_where = " AND user = '$txp_user'";
  638. if ($sort_method == 'timestamp') {
  639. $sort = ' ORDER BY timestamp desc';
  640. $rs = safe_rows('*','adi_recent_tab',"event = '$event'".$default_where.$sort,$adi_recent_tab_debug);
  641. }
  642. else if ($sort_method == 'alphanumeric') {
  643. if ($event == 'article') {
  644. $sort = ' ORDER BY Title';
  645. $rs = safe_rows('Title,textpattern.ID,adi_recent_tab.*','textpattern, adi_recent_tab',"event = '$event' AND textpattern.ID = adi_recent_tab.id".$default_where.$sort,$adi_recent_tab_debug);
  646. }
  647. else if ($event == 'image') {
  648. $sort = ' ORDER BY alt,txp_image.name';
  649. // note that actual name is last in list of fields - image name not stored by adi_recent_tab, so don't want blank to override proper name
  650. $rs = safe_rows('adi_recent_tab.*,alt,txp_image.name','txp_image, adi_recent_tab',"event = '$event' AND txp_image.id = adi_recent_tab.id".$default_where.$sort,$adi_recent_tab_debug);
  651. }
  652. else if ($event == 'file') {
  653. $sort = ' ORDER BY title,filename';
  654. $rs = safe_rows('title,filename,adi_recent_tab.*','txp_file, adi_recent_tab',"event = '$event' AND txp_file.id = adi_recent_tab.id".$default_where.$sort,$adi_recent_tab_debug);
  655. }
  656. else if ($event == 'link') {
  657. $sort = ' ORDER BY linkname,url';
  658. $rs = safe_rows('linkname,url,adi_recent_tab.*','txp_link, adi_recent_tab',"event = '$event' AND txp_link.id = adi_recent_tab.id".$default_where.$sort,$adi_recent_tab_debug);
  659. }
  660. else { // page, form, style, section
  661. $sort = ' ORDER BY name';
  662. $rs = safe_rows('*','adi_recent_tab',"event='$event'".$default_where.$sort,$adi_recent_tab_debug);
  663. }
  664. }
  665. if ($adi_recent_tab_debug)
  666. dmp($rs);
  667. $out = '';
  668. foreach ($rs as $index => $row) {
  669. $item = '';
  670. extract($row);
  671. // link text fiddling
  672. if ($event == 'article') { // use article title, or Untitled if empty
  673. $Title = trim($Title);
  674. if (empty($Title))
  675. $link_text = gTxt('untitled');
  676. else
  677. $link_text = $Title;
  678. }
  679. else if ($event == 'image') { // use alt text, or name if blank
  680. $alt = trim($alt);
  681. if (empty($alt) || !adi_recent_tab_pref('adi_recent_tab_img_alt'))
  682. $link_text = $name;
  683. else
  684. $link_text = $alt;
  685. }
  686. else if ($event == 'link') { // use link name, or url if blank
  687. $linkname = trim($linkname);
  688. if (empty($linkname))
  689. $link_text = $url;
  690. else
  691. $link_text = $linkname;
  692. }
  693. else if ($event == 'file') { // use title, or filename if blank
  694. $title = trim($title);
  695. if (empty($title))
  696. $link_text = $filename;
  697. else
  698. $link_text = $title;
  699. }
  700. else if ($event == 'section') // use name
  701. $link_text = $name;
  702. // include IDs?
  703. if (adi_recent_tab_pref('adi_recent_tab_ids') && ($id != ''))
  704. $link_text .= ' ('.tag($id,'span').')';
  705. // links to items
  706. if ($event == 'article')
  707. $item .= '<a href="?event='.$event.a.'step='.$step.a.'ID='.$id.'">'.$link_text.'</a>';
  708. else if (($event == 'image') || ($event == 'link') || ($event == 'file'))
  709. $item .= '<a href="?event='.$event.a.'step='.$step.a.'id='.$id.'">'.$link_text.'</a>';
  710. else if ($event == 'section')
  711. $item .= '<a href="?event='.$event.a.'step='.$step.a.'name='.$name.'">'.$link_text.'</a>';
  712. else
  713. $item .= '<a href="?event='.$event.a.'name='.$name.'">'.$name.'</a>';
  714. $out .= tag($item,'li',' class="adi_recent_tab_menu_item"').n;
  715. }
  716. if ($wrap)
  717. return tag($out,'ul');
  718. else
  719. return $out;
  720. }
  721. function adi_recent_tab($event,$step) {
  722. // the page that displays all the "recent" links
  723. global $adi_recent_tab_debug,$adi_recent_tab_event_gtxt,$adi_recent_tab_include,$adi_recent_tab_prefs,$adi_recent_tab_txp460;
  724. $message= '';
  725. if ($step == 'update_prefs') {
  726. $result = adi_recent_tab_update_prefs('admin');
  727. $result ? $message = gTxt('preferences_saved') : $message = array(gTxt('adi_pref_update_fail'),E_ERROR);
  728. adi_recent_tab_housekeeping(); // do extra housekeeping to reflect possible change in max items (habitually done at bottom of page)
  729. }
  730. // generate page
  731. pagetop('adi_recent_tab '.gTxt('adi_recent_tab'),$message);
  732. echo '<div id="adi_recent_tab">';
  733. echo tag(gTxt('adi_recent_items'),'h1');
  734. // generate list of recents
  735. echo tag(implode(n,adi_recent_tab_list_markup()),'ul',' id="adi_recent_tab_tab"');
  736. // preferences
  737. echo adi_recent_tab_pref_inputs($event,'admin');
  738. echo '</div>';
  739. if ($adi_recent_tab_debug)
  740. echo adi_recent_tab_db_dump();
  741. }
  742. function adi_recent_tab_menu_ob() {
  743. // the old-fashioned magic that gets the recent items into adi_recent_tab's menu - TXP 4.5
  744. ob_start('adi_recent_tab_menu_inject');
  745. }
  746. function adi_recent_tab_menu_inject($buffer) {
  747. // another bit of arcane magic - TXP 4.5
  748. global $DB, $adi_recent_tab_txp460;
  749. if(!isset($DB)) $DB = new db;
  750. $pattern = '#'.gTxt('adi_recent_items').'</a></li>#sU';
  751. $insert = 'adi_recent_tab_menu_markup';
  752. $buffer = preg_replace_callback($pattern, $insert, $buffer); // this causes grief in 4.6 (seemingly just for me!)
  753. return $buffer;
  754. }
  755. function adi_recent_tab_menu_markup($matches) {
  756. // generate markup for adi_recent_tab recent item lists - TXP 4.5
  757. global $adi_recent_tab_event_gtxt,$adi_recent_tab_include,$adi_recent_tab_prefs;
  758. $out = '';
  759. $tab_list = do_list(adi_recent_tab_pref('adi_recent_tab_list'));
  760. foreach ($tab_list as $this_event) {
  761. $link_event = $this_event;
  762. if ($this_event == 'article')
  763. $link_event = 'list';
  764. $out .=
  765. '<li><a class="adi_recent_tab_menu_title" href="?event='.$link_event.'">'
  766. .gTxt($adi_recent_tab_event_gtxt[$this_event])
  767. .'</a></li>'
  768. .adi_recent_tab_links($this_event,FALSE);
  769. }
  770. return $matches[0].$out;
  771. }
  772. function adi_recent_tab_list_markup() {
  773. // generate markup for dropdown or tab
  774. // <ul>
  775. // <li>
  776. // <h2><a>TAB</a></h2>
  777. // <a>RECENT LINK 1</a>
  778. // <a>RECENT LINK 2</a> etc
  779. // </li>
  780. global $adi_recent_tab_event_gtxt,$adi_recent_tab_include,$adi_recent_tab_prefs;
  781. $out = array();
  782. $tab_list = do_list(adi_recent_tab_pref('adi_recent_tab_list'));
  783. foreach ($tab_list as $index => $this_event) {
  784. $tab_event = $this_event;
  785. if ($this_event == 'article')
  786. $tab_event = 'list';
  787. $out[] =
  788. tag(
  789. tag(
  790. '<a href="?event='.$tab_event.'">'.gTxt($adi_recent_tab_event_gtxt[$this_event]).'</a>'
  791. ,'h2'
  792. )
  793. .adi_recent_tab_links($this_event)
  794. ,'li'
  795. );
  796. }
  797. return $out;
  798. }
  799. function adi_recent_tab_menu_markup_mega() {
  800. // generate mega menu markup - TXP 4.6
  801. echo tag(implode(n,adi_recent_tab_list_markup()),'ul',' id="adi_recent_tab_inject"');
  802. }
  803. function adi_recent_tab_db_dump($table='adi_recent_tab') {
  804. // print out contents of database table
  805. $result = mysql_query("SELECT * FROM {$table}");
  806. $fields_num = mysql_num_fields($result);
  807. $out = "<br/><table><tr>";
  808. // table headers
  809. for ($i = 0; $i < $fields_num; $i++) {
  810. $field = mysql_fetch_field($result);
  811. $out .= "<td><b>{$field->name}</b>&nbsp;</td>";
  812. }
  813. $out .= "</tr>";
  814. // table rows
  815. while ($row = mysql_fetch_row($result)) {
  816. $out .= "<tr>";
  817. foreach($row as $cell)
  818. $out .= "<td>$cell&nbsp;</td>";
  819. $out .= "</tr>";
  820. }
  821. $out .= '</table><br/>';
  822. return $out;
  823. }
  824. function adi_recent_tab_pref($name,$value=NULL,$private=FALSE) {
  825. // read or set pref
  826. global $prefs,$adi_recent_tab_prefs;
  827. if ($value === NULL)
  828. return get_pref($name,$adi_recent_tab_prefs[$name]['value']);
  829. else {
  830. if (array_key_exists($name,$adi_recent_tab_prefs))
  831. $html = $adi_recent_tab_prefs[$name]['input'];
  832. else
  833. $html = 'text_input';
  834. $res = set_pref($name,$value,'adi_recent_tab_admin',2,$html,0,$private);
  835. $prefs[$name] = get_pref($name,$adi_recent_tab_prefs[$name]['value'],TRUE);
  836. return $res;
  837. }
  838. }
  839. function adi_recent_tab_pref_inputs($event,$tab=NULL) {
  840. // output preference input fields accoring to options/admin setting
  841. global $txp_groups,$adi_recent_tab_prefs,$adi_recent_tab_outlaws,$adi_recent_tab_admin_outlaws,$adi_recent_tab_include,$adi_recent_tab_event_gtxt;
  842. if ($tab === NULL) return;
  843. $out = '';
  844. foreach ($adi_recent_tab_prefs as $pref_name => $pref_info) {
  845. if ($pref_info['tab'] == $tab) {
  846. switch ($pref_info['input']) {
  847. case 'yesnoradio':
  848. $out .=
  849. graf(
  850. tag(gTxt($pref_info['label']),'label')
  851. .sp.sp
  852. .tag(radio($pref_name,'0',(adi_recent_tab_pref($pref_name) == '0')).sp.gTxt('no'),'label')
  853. .sp.sp
  854. .tag(radio($pref_name,'1',(adi_recent_tab_pref($pref_name) == '1')).sp.gTxt('yes'),'label')
  855. ,' class="'.$pref_name.'"'
  856. );
  857. break;
  858. case 'custom':
  859. // admin privs
  860. if ($pref_name == 'adi_recent_tab_admin_privs') {
  861. $priv_out = gTxt($pref_info['label']);
  862. $admin_privs = do_list(adi_recent_tab_pref('adi_recent_tab_admin_privs'));
  863. foreach ($txp_groups as $index => $group)
  864. if (array_search($index,$adi_recent_tab_admin_outlaws) === FALSE) // ignore the outlaws
  865. $priv_out .= tag(sp.sp.checkbox2("adi_recent_tab_admin_privs[$index]",(array_search($index,$admin_privs) !== FALSE),'','adi_recent_tab_admin_privs').sp.gTxt($group),'label');
  866. $out .= graf($priv_out,' class="'.$pref_name.'"');
  867. }
  868. // plugin privs
  869. if ($pref_name == 'adi_recent_tab_privs') {
  870. $priv_out = gTxt($pref_info['label']);
  871. $plugin_privs = do_list(adi_recent_tab_pref('adi_recent_tab_privs'));
  872. foreach ($txp_groups as $index => $group)
  873. if (array_search($index,$adi_recent_tab_outlaws) === FALSE) // ignore the outlaws
  874. $priv_out .= tag(sp.sp.checkbox2("adi_recent_tab_privs[$index]",(array_search($index,$plugin_privs) !== FALSE),'','adi_recent_tab_privs').sp.gTxt($group),'label');
  875. $out .= graf($priv_out,' class="'.$pref_name.'"');
  876. }
  877. // tab visibility
  878. if ($pref_name == 'adi_recent_tab_list') {
  879. $checkboxes = gTxt($pref_info['label']);
  880. $tab_list = do_list(adi_recent_tab_pref('adi_recent_tab_list'));
  881. foreach ($adi_recent_tab_include as $tab_name) {
  882. $checked = array_search($tab_name,$tab_list) !== FALSE;
  883. $checkboxes .=
  884. tag(
  885. sp.sp
  886. .checkbox("adi_recent_tab_list[$tab_name]",TRUE,$checked)
  887. .sp
  888. .gTxt($adi_recent_tab_event_gtxt[$tab_name])
  889. ,'label'
  890. );
  891. }
  892. $out .= graf($checkboxes,' class="'.$pref_name.'"');
  893. }
  894. break;
  895. default: // text_input
  896. $out .=
  897. graf(
  898. tag(gTxt($pref_info['label']),'label')
  899. .sp.sp
  900. .finput('text',$pref_name,stripslashes(adi_recent_tab_pref($pref_name)),$pref_name)
  901. ,' class="'.$pref_name.'"'
  902. );
  903. break;
  904. }
  905. }
  906. }
  907. if ($out)
  908. return form(
  909. tag(
  910. tag(gTxt('edit_preferences'),'h2')
  911. .$out
  912. .fInput('submit','do_something',gTxt('adi_update_prefs'),'smallerbox')
  913. .eInput($event)
  914. .sInput('update_prefs')
  915. ,'div'
  916. ,' class="adi_recent_tab_prefs"'
  917. )
  918. );
  919. }
  920. function adi_recent_tab_update_prefs($tab=NULL) {
  921. // update prefs
  922. global $txp_user,$adi_recent_tab_prefs;
  923. if ($tab === NULL)
  924. return FALSE;
  925. else {
  926. $result = TRUE;
  927. foreach ($adi_recent_tab_prefs as $pref_name => $pref_info) {
  928. if ($pref_info['tab'] == $tab) { // tab match?
  929. if (array_key_exists($pref_name,$_POST))
  930. $value = $_POST[$pref_name];
  931. else if ($pref_info['input'] == 'yesnoradio')
  932. $value = '0';
  933. else
  934. $value = $pref_info['value'];
  935. if (is_array($value)) { // string-ify arrays
  936. $values = array_keys($value); // need index values not 1s
  937. if ($pref_name == 'adi_recent_tab_admin_privs') {
  938. $user_priv = safe_field('privs','txp_users',"name='".doSlash($txp_user)."'");
  939. $values = array_unique(array_merge($values,array(1,$user_priv))); // can't kill off Publisher or self
  940. }
  941. $value = implode(',',$values);
  942. }
  943. // some values not allowed to be blank, reset to default
  944. if ((!$pref_info['blank']) && (trim($value) == ''))
  945. $value = $adi_recent_tab_prefs[$pref_name]['value'];
  946. // update pref
  947. $private = ($pref_info['tab'] == 'options' ? FALSE : $pref_info['private']); // "options" prefs can't be private
  948. $result &= adi_recent_tab_pref($pref_name,$value,$private);
  949. }
  950. }
  951. return $result;
  952. }
  953. }
  954. function adi_recent_tab_options($event,$step) {
  955. // plugin options page
  956. global $adi_recent_tab_debug,$adi_recent_tab_url,$textarray,$adi_recent_tab_prefs,$adi_recent_tab_include,$adi_recent_tab_event_gtxt,$adi_recent_tab_plugin_status;
  957. $message = '';
  958. // step-tastic
  959. if ($step == 'textpack') {
  960. if (function_exists('install_textpack')) {
  961. $adi_textpack = file_get_contents($adi_recent_tab_url['textpack']);
  962. if ($adi_textpack) {
  963. $result = install_textpack($adi_textpack);
  964. $message = gTxt('textpack_strings_installed', array('{count}' => $result));
  965. $textarray = load_lang(LANG); // load in new strings
  966. }
  967. else
  968. $message = array(gTxt('adi_textpack_fail'),E_ERROR);
  969. }
  970. }
  971. else if ($step == 'install') {
  972. $result = adi_recent_tab_install();
  973. $result ? $message = gTxt('adi_installed') : $message = array(gTxt('adi_install_fail'),E_ERROR);
  974. }
  975. else if ($step == 'uninstall') {
  976. $result = adi_recent_tab_uninstall();
  977. $result ? $message = gTxt('adi_uninstalled') : $message = array(gTxt('adi_uninstall_fail'),E_ERROR);
  978. }
  979. else if ($step == 'update_prefs') {
  980. $result = adi_recent_tab_update_prefs('options');
  981. $result ? $message = gTxt('preferences_saved') : $message = array(gTxt('adi_pref_update_fail'),E_ERROR);
  982. }
  983. // generate page
  984. pagetop('adi_recent_tab - '.gTxt('plugin_prefs'),$message);
  985. // *nstall buttons
  986. $install_button =
  987. form(
  988. fInput('submit','do_something',gTxt('install'),'publish','',"return verify('".gTxt('are_you_sure')."')")
  989. .eInput($event).sInput('install')
  990. );
  991. $uninstall_button =
  992. form(
  993. fInput('submit','do_something',gTxt('adi_uninstall'),'publish','',"return verify('".gTxt('are_you_sure')."')")
  994. .eInput($event).sInput('uninstall')
  995. ,'margin-top:3em'
  996. );
  997. if ($adi_recent_tab_plugin_status) // proper plugin install, so lifecycle takes care of install/uninstall
  998. $install_button = $uninstall_button = '';
  999. $installed = adi_recent_tab_installed();
  1000. // options
  1001. echo tag(
  1002. tag('adi_recent_tab '.gTxt('plugin_prefs'),'h2')
  1003. .( $installed ?
  1004. // link to plugin admin tab
  1005. graf(href(gTxt('adi_recent_items'),'?event=adi_recent_tab'))
  1006. // prefs
  1007. .adi_recent_tab_pref_inputs($event,'options')
  1008. // textpack links
  1009. .graf(href(gTxt('install_textpack'),'?event='.$event.a.'step=textpack'),' style="margin-top:3em"')
  1010. .graf(href(gTxt('adi_textpack_online'),$adi_recent_tab_url['textpack_download']))
  1011. .graf(href(gTxt('adi_textpack_feedback'),$adi_recent_tab_url['textpack_feedback']))
  1012. .$uninstall_button
  1013. : $install_button
  1014. )
  1015. ,'div'
  1016. ,' style="text-align:center; margin-bottom:3em"'
  1017. );
  1018. if ($adi_recent_tab_debug) {
  1019. echo '<b>$adi_textpack ('.$adi_recent_tab_url['textpack'].'):</b>';
  1020. $adi_textpack = file_get_contents($adi_recent_tab_url['textpack']);
  1021. dmp($adi_textpack);
  1022. }
  1023. }
  1024. # --- END PLUGIN CODE ---
  1025. if (0) {
  1026. ?>
  1027. <!--
  1028. # --- BEGIN PLUGIN HELP ---
  1029. <h1><strong>adi_recent_tab</strong> &#8211; Recent Items</h1>
  1030. <p>To help speed up workflow &#8211; especially during website construction &#8211; this plugin gives you a menu of recently accessed Textpattern Admin items.</p>
  1031. <h2><strong>Usage</strong></h2>
  1032. <p>Install &amp; activate the plugin in the normal way. A new top level Admin tab will then be available.</p>
  1033. <p>The Recent dropdown menu shows a list of articles/images/links/pages/forms etc that you have recently visited in the Admin interface.</p>
  1034. <p>This menu contains items that you have <em>visited</em> &#8211; as opposed to the Recent articles list in the Article tab which only contains articles that have been recently modified.</p>
  1035. <h2><strong>The Menu</strong></h2>
  1036. <p>The Recent menu gives you direct access to:</p>
  1037. <ul>
  1038. <li>recently visited items</li>
  1039. <li>and their tabs</li>
  1040. </ul>
  1041. <h2><strong>The Tab</strong></h2>
  1042. <p>The recent items are also available on a standalone page &#8211; in <span class="caps">TXP</span> 4.5 simply click on the Recent tab itself, in <span class="caps">TXP</span> 4.6 look in the Extensions menu.</p>
  1043. <p>Here you will also find preferences to:</p>
  1044. <ul>
  1045. <li>specify which recently visited items you want to record</li>
  1046. <li>set the number of items to remember</li>
  1047. <li>choose whether to have article/image/link/file IDs included in the menu</li>
  1048. <li>choose whether to have image alt used in the menu</li>
  1049. </ul>
  1050. <h2><strong>Privileges</strong></h2>
  1051. <p>You can adjust who gets to use the plugin by setting the privileges in options.</p>
  1052. <h2><strong>Textpack</strong></h2>
  1053. <p>To install the Textpack, go to the plugin&#8217;s Options tab and click on Install textpack. This will copy &amp; install it from a remote server. The number of language strings installed for your language will be displayed.</p>
  1054. <p>If the Textpack installation fails (possibly due to an error accessing the remote site), the alternative is to click the <a href="http://www.greatoceanmedia.com.au/textpack" rel="nofollow">Textpack also available online</a> link. This will take you to a website where the Textpack can be manually copied &amp; pasted into the <em>Admin &#8211; Language</em> tab.</p>
  1055. <p>Additions and corrections to the Textpack are welcome &#8211; please use the <a href="http://www.greatoceanmedia.com.au/textpack/?plugin=adi_recent_tab" rel="nofollow">Textpack feedback</a> form.</p>
  1056. <h2><strong>Additional information</strong></h2>
  1057. <p>Support and further information can be obtained from the <a href="http://forum.textpattern.com/viewtopic.php?id=36928" rel="nofollow">Textpattern support forum</a>. A copy of this help is also available <a href="http://www.greatoceanmedia.com.au/txp/?plugin=adi_recent_tab" rel="nofollow">online</a>. More adi_plugins can be found <a href="http://www.greatoceanmedia.com.au/txp/" rel="nofollow">here</a>.</p>
  1058. # --- END PLUGIN HELP ---
  1059. -->
  1060. <?php
  1061. }
  1062. ?>