You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

430 lines
17 KiB

  1. /**
  2. * Right Context Menu configuration
  3. *
  4. * Some usefull variables:
  5. * node.hns = headpage id;
  6. * node.isdir = node is namespace;
  7. * node.dokuid = the DW id (namespace parent in case of headpage);
  8. * id = the DW id of the selected node (headpage id in case of headpage);
  9. * index.config.urlbase = Url Base;
  10. * index.config.sepchar = Url separator;
  11. *
  12. * HOWTO EDIT:
  13. *
  14. * To override menu entries or add a menu entry:
  15. * - PLEASE EDIT ONLY the scripts/contextmenu.local.js file
  16. * - DON'T EDIT this file, it is overwritten at plugin update
  17. *
  18. * Base structure of the context menu is displayed below.
  19. * The entries with 'pg' are shown for page noded, these with 'ns' only for namespaces.
  20. *
  21. * Current available for everybody:
  22. * indexmenu_contextmenu['all']['pg']['view'] = [...array with menu description here... ];
  23. * indexmenu_contextmenu['all']['pg']['edit'] = [ ... ];
  24. * indexmenu_contextmenu['all']['ns']['view'] = [ ... ];
  25. *
  26. * Current available for admins:
  27. * indexmenu_contextmenu['pg']['view'] = [ ... ];
  28. * indexmenu_contextmenu['ns']['view'] = [ ... ];
  29. *
  30. * Current available for authenticated users:
  31. * indexmenu_contextmenu['pg']['view'] = [ ... ];
  32. * indexmenu_contextmenu['ns']['view'] = [ ... ];
  33. *
  34. * A menu description may contain four kind of entries:
  35. * - section title: array with one entry e.g.:
  36. * ['Section title (html allowed)']
  37. * - menu action: array with two entries e.g.:
  38. * ['Title of action 1 (html allowed)', 'javascript here ... see for examples scripts/contextmenu.js']
  39. * - menu action with custom tooltip: array with three entries e.g.:
  40. * ['Title of action 1 (html allowed)', 'javascript here ... see for examples scripts/contextmenu.js', 'Customized title']
  41. * - submenu: array with two entries where second entry is an array that describes again a menu e.g.:
  42. * ['title of submenu (html allowed)', [ ...array with menu actions... ]]
  43. *
  44. *
  45. * Examples:
  46. * A menu description array:
  47. * ... = [
  48. * ['section title'],
  49. * ['title of action 1', 'javascript here'],
  50. * ['title of submenu', [['title of subaction 1', 'javascript here'], ['title of subaction 1', 'javascript here', 'Click here for action']] ]
  51. * ];
  52. *
  53. * To Override the common menu title:
  54. * indexmenu_contextmenu['all']['pg']['view'][0] = ['customtitle'];
  55. *
  56. * To override a menu entry, for example the menu title:
  57. * indexmenu_contextmenu['all']['pg']['view'][0] = ['Custom Title'];
  58. *
  59. * To add option to page menu:
  60. * Array.splice(index, howManyToRemove, description1)
  61. * index = position to start (start counting at zero)
  62. * howManyToRemove = number of elements that are removed (set to 1 to replace a element)
  63. * description1 = array with menu entry description
  64. * -> optional: description2 = optional you can add more elements at once by splice(index, howManyToRemove, description1, description2, etc)
  65. *
  66. * indexmenu_contextmenu['all']['pg']['view'].splice(1, 0, ['Input new page', '"javascript: IndexmenuContextmenu.reqpage(\'"+index.config.urlbase+"\',\'"+index.config.sepchar+"\',\'"+node.dokuid+"\');"']);
  67. */
  68. /* global LANG */
  69. /* global DOKU_BASE */
  70. /* global JSINFO */
  71. // IMPORTANT: DON'T MODIFY THIS FILE, BUT EDIT contextmenu.local.js PLEASE!
  72. // THIS FILE IS OVERWRITTEN WHEN PLUGIN IS UPDATED
  73. /**
  74. * Right Context Menu configuration for all users:
  75. */
  76. indexmenu_contextmenu['all']['pg'] = {
  77. 'view': [
  78. ['<span class="indexmenu_titlemenu"><b>'+LANG.plugins.indexmenu.page+'</b></span>'],
  79. [LANG.plugins.indexmenu.revs, 'IndexmenuContextmenu.getid(index.config.urlbase,id)+"do=revisions"'],
  80. [LANG.plugins.indexmenu.tocpreview, '"javascript: IndexmenuContextmenu.createTocMenu(\'call=indexmenu&req=toc&id="+id+"\',\'picker_"+index.treeName+"\',\'s"+index.treeName+node.id+"\');"']
  81. ],
  82. //Menu items in edit mode, when previewing
  83. 'edit': [
  84. ['<span class="indexmenu_titlemenu"><b>'+LANG.plugins.indexmenu.editmode+'</b></span>'],
  85. [LANG.plugins.indexmenu.insertdwlink, '"javascript: IndexmenuContextmenu.insertTags(\'"+id+"\',\'"+index.config.sepchar+"\');"+index.treeName+".divdisplay(\'r\',0);"', LANG.plugins.indexmenu.insertdwlinktooltip]
  86. ]
  87. };
  88. indexmenu_contextmenu['all']['ns'] = {
  89. 'view': [
  90. ['<span class="indexmenu_titlemenu"><b>'+LANG.plugins.indexmenu.ns+'</b></span>'],
  91. [LANG.plugins.indexmenu.search, '"javascript: IndexmenuContextmenu.srchpage(\'"+index.config.urlbase+"\',\'"+index.config.sepchar+"\',\'"+node.isdir+"\',\'"+node.dokuid+"\');"', LANG.plugins.indexmenu.searchtooltip]
  92. ]
  93. };
  94. if (JSINFO && JSINFO.isadmin) {
  95. /**
  96. * Right Context Menu configuration for admin users:
  97. */
  98. indexmenu_contextmenu['pg'] = {
  99. 'view': [
  100. [LANG.plugins.indexmenu.edit, 'IndexmenuContextmenu.getid(index.config.urlbase,id)+"do=edit"'],
  101. ['<em>'+LANG.plugins.indexmenu.create+'--></em>', [
  102. [LANG.plugins.indexmenu.headpage, '"javascript: IndexmenuContextmenu.reqpage(\'"+index.config.urlbase+"\',\'"+index.config.sepchar+"\',\'"+node.dokuid+"\',\'"+node.name+"\');"', LANG.plugins.indexmenu.headpagetooltip],
  103. [LANG.plugins.indexmenu.startpage, 'IndexmenuContextmenu.getid(index.config.urlbase,id+index.config.sepchar+"start")+"do=edit"', LANG.plugins.indexmenu.startpagetooltip],
  104. [LANG.plugins.indexmenu.custompage, '"javascript: IndexmenuContextmenu.reqpage(\'"+index.config.urlbase+"\',\'"+index.config.sepchar+"\',\'"+node.dokuid+"\');"', LANG.plugins.indexmenu.custompagetooltip]
  105. ]],
  106. ['<em>'+LANG.plugins.indexmenu.more+'--></em>', [
  107. [LANG.plugins.indexmenu.acls, 'IndexmenuContextmenu.getid(index.config.urlbase,id)+"do=admin&page=acl"'],
  108. [LANG.plugins.indexmenu.purgecache, 'IndexmenuContextmenu.getid(index.config.urlbase,id)+"purge=true"'],
  109. [LANG.plugins.indexmenu.exporthtml, 'IndexmenuContextmenu.getid(index.config.urlbase,id)+"do=export_xhtml"'],
  110. [LANG.plugins.indexmenu.exporttext, 'IndexmenuContextmenu.getid(index.config.urlbase,id)+"do=export_raw"']
  111. ]]
  112. ]
  113. };
  114. indexmenu_contextmenu['ns'] = {
  115. 'view': [
  116. [LANG.plugins.indexmenu.newpage, '"javascript: IndexmenuContextmenu.reqpage(\'"+index.config.urlbase+"\',\'"+index.config.sepchar+"\',\'"+node.dokuid+"\');"', LANG.plugins.indexmenu.newpagetooltip],
  117. ['<em>'+LANG.plugins.indexmenu.more+'--></em>', [
  118. [LANG.plugins.indexmenu.headpagehere, '"javascript: IndexmenuContextmenu.reqpage(\'"+index.config.urlbase+"\',\'"+index.config.sepchar+"\',\'"+node.dokuid+"\',\'"+node.name+"\');"', LANG.plugins.indexmenu.headpageheretooltip],
  119. [LANG.plugins.indexmenu.acls, 'IndexmenuContextmenu.getid(index.config.urlbase,node.dokuid)+"do=admin&page=acl"']
  120. ]]
  121. ]
  122. };
  123. } else if (JSINFO && JSINFO.isauth) {
  124. /**
  125. * Right Context Menu configuration for authenticated users:
  126. */
  127. indexmenu_contextmenu['pg'] = {
  128. 'view': [
  129. [LANG.plugins.indexmenu.newpagehere, '"javascript: IndexmenuContextmenu.reqpage(\'"+index.config.urlbase+"\',\'"+index.config.sepchar+"\',\'"+node.dokuid+"\');"'],
  130. ['Edit', 'IndexmenuContextmenu.getid(index.config.urlbase,id)+"do=edit"', 1, 0 ],
  131. ['<em>'+LANG.plugins.indexmenu.more+'--></em>', [
  132. [LANG.plugins.indexmenu.headpagehere, '"javascript: IndexmenuContextmenu.reqpage(\'"+index.config.urlbase+"\',\'"+index.config.sepchar+"\',\'"+node.dokuid+"\',\'"+node.name+"\');"'],
  133. [LANG.plugins.indexmenu.purgecache, 'IndexmenuContextmenu.getid(index.config.urlbase,id)+"purge=true"'],
  134. [LANG.plugins.indexmenu.exporthtml, 'IndexmenuContextmenu.getid(index.config.urlbase,id)+"do=export_xhtml"']
  135. ]]
  136. ]
  137. };
  138. }
  139. var IndexmenuContextmenu = {
  140. /**
  141. * Common functions
  142. * Insert your custom functions (available for all users) here.
  143. */
  144. /**
  145. * Navigate to the search page
  146. *
  147. * @param {string} urlbase index.config.urlbase
  148. * @param {string} sepchar index.config.sepchar
  149. * @param {boolean} isdir whether a directory (probably boolean, might be string)
  150. * @param {string} nid page id of node (dokuid mentioned in indexmenu.js)
  151. */
  152. srchpage: function (urlbase, sepchar, isdir, nid) {
  153. const enteredText = prompt(LANG.plugins.indexmenu.insertkeywords, "");
  154. if (enteredText) {
  155. let fnid = nid;
  156. if (isdir == "0") {
  157. fnid = fnid.substring(0, nid.lastIndexOf(sepchar));
  158. }
  159. let b = urlbase, re = new RegExp(sepchar, 'g');
  160. fnid = fnid.replace(re, ":");
  161. b += (urlbase.indexOf("?id=") < 0) ? '?id=' : '';
  162. window.location.href = IndexmenuContextmenu.getid(b, enteredText + " @" + fnid) + "do=search";
  163. }
  164. },
  165. /**
  166. * Build a url to a wiki page
  167. *
  168. * @param {string} urlbase
  169. * @param {string} id
  170. * @returns {string}
  171. */
  172. getid: function (urlbase, id) {
  173. let url = (urlbase || '') + encodeURIComponent(id || '');
  174. url += (urlbase.indexOf("?") < 0) ? '?' : '&';
  175. return url;
  176. },
  177. /**
  178. * Navigate to the editor window
  179. *
  180. * @param {string} urlbase
  181. * @param {string} sepchar
  182. * @param {string} id
  183. * @param {string} pagename
  184. */
  185. reqpage: function (urlbase, sepchar, id, pagename) {
  186. let newpageid;
  187. if (pagename) {
  188. newpageid = id + sepchar + pagename;
  189. } else {
  190. newpageid = prompt(LANG.plugins.indexmenu.insertpagename, "");
  191. if (!newpageid) {
  192. return;
  193. }
  194. newpageid = id + sepchar + newpageid;
  195. }
  196. if (newpageid) {
  197. window.location.href = IndexmenuContextmenu.getid(urlbase, newpageid) + "do=edit";
  198. }
  199. },
  200. /**
  201. * Insert link syntax with given id in current editor window
  202. *
  203. * @param {string} lnk page id
  204. * @param {string} sepchar
  205. */
  206. insertTags: function (lnk, sepchar) {
  207. let r, l = lnk;
  208. if (sepchar) {
  209. r = new RegExp(sepchar, "g");
  210. l = lnk.replace(r, ':');
  211. }
  212. insertTags('wiki__text', '[[', ']]', l);
  213. },
  214. /**
  215. * Create or catch the picker and hide it, next call the ajax content loading to get the ToC
  216. *
  217. * @param {string} get query string
  218. * @param {string} picker id of picker
  219. * @param {string} btn id of button
  220. */
  221. createTocMenu: function (get, picker, btn) {
  222. var $toc_picker = jQuery('#' + picker);
  223. if (!$toc_picker.length) {
  224. $toc_picker = IndexmenuUtils.createPicker(picker, 'indexmenu_toc');
  225. $toc_picker
  226. .html('<a href="#"><img src="' + DOKU_BASE + 'lib/plugins/indexmenu/images/close.gif" class="indexmenu_close" /></a><div />')
  227. .children().first().click(function (event) {
  228. event.stopPropagation();
  229. return IndexmenuContextmenu.togglePicker($toc_picker, jQuery('#' + btn));
  230. });
  231. } else {
  232. $toc_picker.hide();
  233. }
  234. IndexmenuContextmenu.ajaxmenu(get, $toc_picker, jQuery('#' + btn), $toc_picker.children().last(), null);
  235. },
  236. /**
  237. * Shows the picker and adds to it or to an internal containter the ajax content
  238. *
  239. * @param {string} get query string
  240. * @param {jQuery} $picker
  241. * @param {jQuery} $btn
  242. * @param {jQuery} $container if defined ajax result is added to it, otherwise to $picker
  243. * @param {function} oncomplete called when defined to handle ajax result
  244. */
  245. ajaxmenu: function (get, $picker, $btn, $container, oncomplete) {
  246. var $indx_list;
  247. $indx_list = $container || $picker;
  248. if (!IndexmenuContextmenu.togglePicker($picker, $btn)) return;
  249. var onComplete = function (data) {
  250. $indx_list.html('');
  251. if (typeof oncomplete == 'function') {
  252. oncomplete(data, $indx_list);
  253. } else {
  254. $indx_list.html(data);
  255. }
  256. };
  257. //get content for picker/container
  258. jQuery.ajax({
  259. type: "POST",
  260. url: DOKU_BASE + 'lib/exe/ajax.php',
  261. data: get,
  262. beforeSend: function () {
  263. $indx_list.html('<div class="tocheader">'+LANG.plugins.indexmenu.loading+'</div>');
  264. },
  265. success: onComplete,
  266. dataType: 'html'
  267. });
  268. },
  269. /**
  270. * Hide/show picker, will be shown beside btn
  271. *
  272. * @param {string|jQuery} $picker
  273. * @param {jQuery} $btn
  274. * @return {Boolean} true if open, false closed
  275. */
  276. togglePicker: function ($picker, $btn) {
  277. var x = 8, y = 0;
  278. if (!$picker.is(':visible')) {
  279. var pos = $btn.offset();
  280. //position + width of button
  281. x += pos.left + $btn[0].offsetWidth;
  282. y += pos.top;
  283. $picker
  284. .show()
  285. .offset({
  286. left: x,
  287. top: y
  288. });
  289. return true;
  290. } else {
  291. $picker.hide();
  292. return false;
  293. }
  294. },
  295. /**
  296. * Fills the contextmenu by creating entries from the given configuration arrays and concatenating these
  297. * to the #r<id> picker
  298. *
  299. * @param {any[]} amenu (part of) the configuration array
  300. * @param {dTree} index the indexmenu object
  301. * @param {int} n node id
  302. */
  303. arrconcat: function (amenu, index, n) {
  304. var html, id, item, a, li;
  305. if (typeof amenu == 'undefined' || typeof amenu['view'] == 'undefined') {
  306. return;
  307. }
  308. var cmenu = amenu['view'];
  309. if (jQuery('#tool__bar')[0] && amenu['edit'] instanceof Array) {
  310. cmenu = amenu['edit'].concat(cmenu);
  311. }
  312. var node = index.aNodes[n];
  313. id = node.hns || node.dokuid;
  314. var createCMenuEntry = function (entry) {
  315. return '<a title="' + ((entry[2]) ? entry[2] : entry[0]) + '" href="' + eval(entry[1]) + '">' + entry[0] + '</a>';
  316. };
  317. jQuery.each(cmenu, function (i, cmenuentry) {
  318. if (cmenuentry == '') {
  319. return true;
  320. }
  321. item = document.createElement('li');
  322. var $cmenu = jQuery('#r' + index.treeName);
  323. if (cmenuentry[1]) {
  324. if (cmenuentry[1] instanceof Array) {
  325. html = document.createElement('ul');
  326. jQuery.each(cmenuentry[1], function (a, subcmenuentry) {
  327. li = document.createElement('li');
  328. li.innerHTML = createCMenuEntry(subcmenuentry);
  329. html.appendChild(li);
  330. });
  331. //}
  332. item.innerHTML = '<span class="indexmenu_submenu">' + cmenuentry[0] + '</span>';
  333. html.left = $cmenu[0].width;
  334. item.appendChild(html);
  335. } else {
  336. item.innerHTML = createCMenuEntry(cmenuentry);
  337. }
  338. } else {
  339. item.innerHTML = cmenuentry;
  340. }
  341. $cmenu.children().last().append(item);
  342. });
  343. },
  344. /**
  345. * Absolute positioning of the div at place of mouseclick
  346. *
  347. * @param obj div element
  348. * @param e
  349. */
  350. mouseposition: function (obj, e) {
  351. //http://www.quirksmode.org/js/events_properties.html
  352. var X = 0, Y = 0;
  353. if (!e) e = window.event;
  354. if (e.pageX || e.pageY) {
  355. X = e.pageX;
  356. Y = e.pageY;
  357. }
  358. else if (e.clientX || e.clientY) {
  359. X = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
  360. Y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
  361. }
  362. obj.style.left = X - 5 + 'px';
  363. obj.style.top = Y - 5 + 'px';
  364. },
  365. /**
  366. * Check mouse button onmousedown event, only for middle and right mouse button contextmenu is shown
  367. *
  368. * @param {int} n node id
  369. * @param {string|dTree} obj the unique name of a dTree object
  370. * @param {event} e
  371. */
  372. checkcontextm: function (n, obj, e) {
  373. e = e || event;
  374. // mouse clicks: which 3 === right, button 2 === right button
  375. if ((e.which === 3 || e.button === 2) || (window.opera && e.which === 1 && e.ctrlKey)) {
  376. obj.contextmenu(n, e);
  377. IndexmenuContextmenu.stopevt(e);
  378. }
  379. },
  380. /**
  381. * Prevent default oncontextmenu event
  382. *
  383. * @param {event} e
  384. * @returns {boolean}
  385. */
  386. stopevt: function (e) {
  387. if (!window.indexmenu_contextmenu) {
  388. return true;
  389. }
  390. e = e || event;
  391. e.preventDefault ? e.preventDefault() : e.returnValue = false;
  392. return false;
  393. }
  394. };