1<?php 2/** 3 * DokuWiki Plugin bookmark2wiki (Action Component) 4 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 5 * @author dodotori <dodotori@localhost> 6 * forked from post2wiki.php by riny [at] bk [dot] ru 7 * To bookmark webpage using bookmarklet 8 * The app will add the url, title and hightlighed text you want to the end of the content of the targeted namespace. It does not directly read/write the dokuwiki page folder. 9 * Version 1.0 10 * @license GPL 2[](http://www.gnu.org/licenses/gpl.html) 11 * @author dodotori https://github.com/edwardcodelab 12 */ 13// TYPICAL USAGE : 14// Create bookmarklet as shown in the bookmarklet part below: 15// Change the window.open statement to reflect the location of the bookmark2wiki.php script. 16// Drag bookmarklet to your toolbar. 17// BOOKMARKLET : 18// javascript:Q=document.selection?document.selection.createRange().text:document.getSelection(); void(window.open('https://myserver/doku.php?do=bookmark2wiki&te='+escape(Q)+'&ur='+ escape(location.href)+'&ti='+escape(document.title),'dokuwikiadd','scrollbars=yes,resizable=yes,toolbars=yes,width=400,height=200,left=200,top=200,status=yes')); 19 20use dokuwiki\Extension\ActionPlugin; 21use dokuwiki\Extension\EventHandler; 22use dokuwiki\Extension\Event; 23 24class action_plugin_bookmark2wiki extends ActionPlugin 25{ 26 /** @inheritDoc */ 27 public function register(EventHandler $controller) 28 { 29 $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'allowMyAction'); 30 $controller->register_hook('TPL_ACT_UNKNOWN', 'BEFORE', $this, 'performMyAction'); 31 } 32 33 /** 34 * Event handler for ACTION_ACT_PREPROCESS 35 * 36 * @param Event $event event object by reference 37 * @param mixed $param optional parameter passed when event was registered 38 * @return void 39 */ 40 public function allowMyAction(Event $event, $param) { 41 if($event->data != 'bookmark2wiki') return; 42 $event->preventDefault(); 43 } 44 45 /** 46 * Event handler for TPL_ACT_UNKNOWN 47 * 48 * @param Event $event event object by reference 49 * @param mixed $param optional parameter passed when event was registered 50 * @return void 51 */ 52 public function performMyAction(Event $event, $param) { 53 if($event->data != 'bookmark2wiki') return; 54 $event->preventDefault(); 55 56 // Get params (support both GET from bookmarklet and POST from form) 57 $te = $_REQUEST['te'] ?? ''; 58 $ur = $_REQUEST['ur'] ?? ''; 59 $ti = $_REQUEST['ti'] ?? ''; 60 61 // Decode unicode (from original) 62 $string = preg_replace('/%u([0-9A-F]+)/', '&#x$1;', $ti); 63 $ti = html_entity_decode($string, ENT_COMPAT, 'UTF-8'); 64 $string = preg_replace('/%u([0-9A-F]+)/', '&#x$1;', $te); 65 $te = html_entity_decode($string, ENT_COMPAT, 'UTF-8'); 66 67 if (!$ur || !$ti) { 68 echo 'Error: Missing URL or title.'; 69 return; 70 } 71 72 // Basic URL validation 73 if (!filter_var($ur, FILTER_VALIDATE_URL)) { 74 echo 'Error: Invalid URL.'; 75 return; 76 } 77 78 $timestamp = date("Y:m:d:H:i:s"); 79 $new_entry = " * [[" . $ur . "|" . $ti . "]] \\\\ " . $te . " -- " . $timestamp; 80 81 if (isset($_POST['save'])) { 82 // Handle form submit: directly save using DokuWiki functions 83 $namespace = cleanID($_POST['page']); 84 if (!$namespace) { 85 echo 'Error: No page selected.'; 86 return; 87 } 88 89 // Check edit permission 90 if (auth_quickaclcheck($namespace) < AUTH_EDIT) { 91 echo 'Error: No permission to edit the selected page.'; 92 return; 93 } 94 95 // Get raw position config and map to internal value 96 $raw_position = $this->getConf('position'); 97 $position_map = [ 98 'After Heading (prepend)' => 'top', 99 'End of Page (append)' => 'bottom' 100 ]; 101 $position = isset($position_map[$raw_position]) ? $position_map[$raw_position] : $raw_position; 102 // Fallback to 'bottom' if config is invalid 103 if (!in_array($position, ['top', 'bottom'])) { 104 $position = 'bottom'; 105 } 106 107 // Read current page content 108 $text = rawWiki($namespace); 109 $text = str_replace("\r", "", $text); // Normalize line endings to \n 110 111 if (trim($text) === '') { 112 $text = "====== New Bookmarks ====== \n"; 113 } 114 115 $lines = explode("\n", $text); 116 117 if ($position == 'top') { 118 // Find the position after the first heading (match after trim) 119 $insert_pos = 0; 120 $found_heading = false; 121 for ($i = 0; $i < count($lines); $i++) { 122 $trimmed = trim($lines[$i]); 123 if (preg_match('/^=+.*=+$/', $trimmed)) { 124 $insert_pos = $i + 1; 125 $found_heading = true; 126 break; 127 } 128 } 129 130 // Skip empty lines after the heading 131 while ($insert_pos < count($lines) && trim($lines[$insert_pos]) === '') { 132 $insert_pos++; 133 } 134 135 // Insert the new entry 136 array_splice($lines, $insert_pos, 0, $new_entry); 137 } else { 138 // Append to end, but add a newline if not empty 139 if (!empty(trim($lines[count($lines) - 1]))) { 140 $lines[] = ''; 141 } 142 $lines[] = $new_entry; 143 } 144 145 $newtext = implode("\n", $lines); 146 147 // Save the updated content 148 saveWikiText($namespace, $newtext, 'Added bookmark: ' . $ti, false); // false = not minor edit 149 150 echo 'Bookmark saved to ' . hsc($namespace) . '! <script>setTimeout(function(){window.close();}, 3000);</script>'; 151 } else { 152 // Display form for page selection 153 $configured_pages = explode("\n", trim($this->getConf('pages'))); 154 if (empty($configured_pages)) { 155 echo 'Error: No pages configured in plugin settings.'; 156 return; 157 } 158 159 echo '<form method="post" action="">'; 160 echo '<label for="page">Save to page:</label><br>'; 161 echo '<select name="page" id="page">'; 162 foreach ($configured_pages as $p) { 163 $p = trim($p); 164 if ($p) { 165 echo '<option value="' . hsc($p) . '">' . hsc($p) . '</option>'; 166 } 167 } 168 echo '</select><br>'; 169 echo '<input type="hidden" name="te" value="' . hsc($te) . '">'; 170 echo '<input type="hidden" name="ur" value="' . hsc($ur) . '">'; 171 echo '<input type="hidden" name="ti" value="' . hsc($ti) . '">'; 172 echo '<input type="submit" name="save" value="Save">'; 173 echo '</form>'; 174 } 175 } 176}