1<?php 2if( !defined( 'DOKU_INC' ) ) die(); 3if( !defined( 'DOKU_PLUGIN' ) ) define( 'DOKU_PLUGIN', 4 DOKU_INC . 'lib/plugins/' ); 5require_once (DOKU_PLUGIN . 'action.php'); 6 7class action_plugin_crosspost extends DokuWiki_Action_Plugin 8{ 9 10 function register(Doku_Event_Handler $controller) 11 { 12 $controller->register_hook( 'ACTION_ACT_PREPROCESS', 'BEFORE', $this, 13 'handle_act' ); 14 $controller->register_hook( 'DOKUWIKI_STARTED', 'BEFORE', $this, 15 'check_cp_redirect' ); 16 $controller->register_hook( 'HTML_EDITFORM_OUTPUT', 'BEFORE', $this, 17 'print_edit_form' ); 18 if( $this->getConf( 'cp_add_links' ) ) 19 { 20 $controller->register_hook( 'TPL_CONTENT_DISPLAY', 'BEFORE', $this, 21 'add_cp_links' ); 22 } 23 } 24 25 /* 26 * Save page: create and delete crossposts here 27 */ 28 function handle_act(&$e, $param) 29 { 30 global $ID; 31 global $INPUT; 32 global $conf; 33 34 if( !is_object( $INPUT ) || !$INPUT->post || 35 !$INPUT->post->param( 'crosspost_plugin' ) ) return; 36 37 $match = $INPUT->post->param( 'crosspost_to' ); 38 $match = preg_split( '/[\s,]+/', $match, -1, PREG_SPLIT_NO_EMPTY ); 39 40 $meta = p_get_metadata( $ID, 'crosspost_to' ); 41 $meta = preg_split( '/[\s,]+/', $meta, -1, PREG_SPLIT_NO_EMPTY ); 42 43 $name = noNS( $ID ); 44 $save = array(); 45 46 foreach( $match as $page ) 47 { 48 if( strpos( $ID, ':' ) === false ) $page .= ':' . $ID; 49 else $page .= ':' . $name; 50 51 if( auth_quickaclcheck( $page ) < AUTH_CREATE ) continue; 52 53 $exists = @file_exists( wikiFN( $page ) ); 54 if( $ID != $page && !$exists ) 55 { 56 saveWikiText( $page, "{{page>$ID}}", 'link from ' . $ID ); 57 p_set_metadata( $page, 58 array('crosspost_source' => $ID 59 ) ); 60 } 61 else 62 { 63 p_set_metadata( $page, 64 array('cache' => 'expire' 65 ), false, false ); 66 } 67 if( !in_array( $page, $save ) ) $save[] = $page; 68 } 69 foreach( $meta as $page ) 70 { 71 if( !in_array( $page, $match ) ) 72 { 73 @unlink( wikiFN( $page ) ); 74 p_set_metadata( $page, 75 array('crosspost_source' => '','cache' => 'expire' 76 ), false, false ); 77 } 78 } 79 80 p_set_metadata( $ID, 81 array('crosspost_to' => join( ',', $save ),'cache' => 'expire' 82 ) ); 83 84 $sidebar = isset( $conf['sidebar'] ) ? $conf['sidebar'] : 'sidebar'; 85 if( $sidebar ) p_set_metadata( $sidebar, 86 array('cache' => 'expire' 87 ), false, false ); 88 } 89 90 /* 91 * Redirect to "original" page if edited page is copy 92 */ 93 function check_cp_redirect(&$e, $param) 94 { 95 global $ID; 96 global $ACT; 97 98 if( $ACT != 'edit' ) return; 99 $meta = p_get_metadata( $ID, 'crosspost_source' ); 100 if( !$meta ) return; 101 if( $meta == $ID ) return; 102 send_redirect( wl( $meta ) . '?do=edit' ); 103 } 104 105 private function _getTitle($mode, $entry) 106 { 107 $title = $entry; 108 $header = false; 109 if( $mode == 'title' ) 110 { 111 $header = p_get_first_heading( $entry ); 112 } 113 elseif( $mode == 'section' ) 114 { 115 $header = p_get_first_heading( getNS( $entry ) ); 116 } 117 elseif( $mode == 'last section:title' ) 118 { 119 $header = p_get_first_heading( $entry ); 120 if( $header ) 121 { 122 $ns = p_get_first_heading( getNS( $entry ) ); 123 if( $ns ) $header = $ns . ':' . $header; 124 } 125 } 126 elseif( $mode == 'full title' ) 127 { 128 $header = p_get_first_heading( $entry ); 129 if( $header ) 130 { 131 $allns = explode( ':', $entry ); 132 array_pop( $allns ); 133 while( count( $allns ) ) 134 { 135 $ns = p_get_first_heading( join( ':', $allns ) ); 136 if( $ns ) 137 { 138 $header = "$ns:$header"; 139 array_pop( $allns ); 140 } 141 else 142 { 143 $header = array_pop( $allns ) . ":$header"; 144 } 145 } 146 } 147 } 148 return $header ? $header : $title; 149 } 150 151 private function _skip_ns($xns, $ns) 152 { 153 foreach( $xns as $x ) 154 { 155 if( $x{0} == '!' ) 156 { 157 $pos = strpos( $ns, ltrim( $x, '!' ) ); 158 if( $pos !== false && $pos == 0 ) return true; 159 } 160 else 161 { 162 if( $x == $ns ) return true; 163 } 164 } 165 return false; 166 } 167 168 /* 169 * Add NS selection to edit page form 170 */ 171 function print_edit_form(&$e, $param) 172 { 173 global $ID; 174 global $ACT; 175 global $conf; 176 177 if( $ACT != 'edit' ) return; 178 179 $xns = $this->getConf( 'cp_disable_on' ); 180 $xns = preg_split( '/[\s,+]/', $xns, -1, PREG_SPLIT_NO_EMPTY ); 181 if( $this->_skip_ns( $xns, getNS( $ID ) ) ) return; 182 183 $title_mode = $this->getConf( 'cp_form_titles' ); 184 $namespaces = array(); 185 search( $namespaces, $conf['datadir'], 'search_namespaces', array() ); 186 $this_ns = ''; 187 188 $meta = p_get_metadata( $ID, 'crosspost_to' ); 189 $meta = preg_split( '/[\s,+]/', $meta, -1, PREG_SPLIT_NO_EMPTY ); 190 191 for( $i = 0; $i < count( $meta ); $i++ ) 192 { 193 $ns = getNS( $meta[$i] ); 194 if( $meta[$i] == $ID ) 195 { 196 array_splice( $meta, $i, 1 ); 197 $this_ns = $ns; 198 } 199 else 200 { 201 if( auth_quickaclcheck( $ns ) >= AUTH_CREATE ) 202 { 203 $meta[$i] = $ns; 204 } 205 else 206 { 207 array_splice( $meta, $i, 1 ); 208 } 209 } 210 } 211 212 if( !$this_ns ) $this_ns = getNS( $ID ); 213 $xns = $this->getConf( 'cp_ns_disabled' ); 214 $xns = preg_split( '/[\s,+]/', $xns, -1, PREG_SPLIT_NO_EMPTY ); 215 $links = array(); 216 217 foreach( $namespaces as $ns ) 218 { 219 if( $ns['id'] == $this_ns ) continue; 220 if( $this->_skip_ns( $xns, $ns['id'] ) ) continue; 221 222 $header = $this->_getTitle( $title_mode, $ns['id'] ); 223 $link = '<a '; 224 $class = 'crosspost'; 225 if( in_array( $ns['id'], $meta ) ) 226 { 227 $class = 'crosspost_added'; 228 } 229 $link .= 'href="#" onclick="' . 'return cp_link_clicked(this,"' . 230 $ns['id'] . '")' . '" class="' . $class . '">' . $header . 231 '</a>'; 232 $links[] = $link; 233 } 234 235 $input = '<b>' . $this->getlang( 'cp_to' ) . '</b><br/>' . 236 '<input type="hidden" name="crosspost_plugin" value="crosspost_plugin" />' . 237 '<input type="text" name="crosspost_to" id="crosspost_to" value="' . 238 join( ',', $meta ) . '" style="width:100%" class="crosspost" ' . 239 'onkeydown="return false;" onmousedown="return false;" ' . '/>' . 240 '<div class="crosspost_form">' . '<b>' . 241 $this->getlang( 'cp_click_to_add' ) . '</b><br/>' . 242 join( ' ', $links ) . '</div>'; 243 244 $e->data->insertElement( 2, $input ); 245 } 246 247 private function _add_link($mode, $page, $title) 248 { 249 $link_title = $this->_getTitle( $mode, $page ); 250 return '<span class="crosspost"><a href="' . wl( $page ) . '" title="' . 251 $title . '" ' . '" class = "crosspost_link">' . $link_title . 252 '</a></span>'; 253 } 254 255 function add_cp_links(&$e, $param) 256 { 257 global $ID; 258 259 $cs_source = p_get_metadata( $ID, 'crosspost_source' ); 260 $cc = p_get_metadata( $cs_source ? $cs_source : $ID, 'crosspost_to' ); 261 $cc = preg_split( '/[\s,+]/', $cc, -1, PREG_SPLIT_NO_EMPTY ); 262 if( count( $cc ) < 1 ) return; 263 $title_mode = $this->getConf( 'cp_link_titles' ); 264 $title_copy = $this->getLang( 'cp_link_copy' ); 265 $title_source = $this->getLang( 'cp_link_source' ); 266 267 if( !in_array( $ID, $cc ) ) $cc[] = $ID; 268 if( $cs_source && !in_array( $cs_source, $cc ) ) $cc[] = $cs_source; 269 270 $addlink = ''; 271 foreach( $cc as $page ) 272 { 273 if( $page != $ID ) 274 { 275 $addlink .= $this->_add_link( $title_mode, $page, 276 $page == $cs_source ? $title_source : $title_copy ) . " "; 277 } 278 } 279 280 if( $addlink ) ptln( '<div class="crosspost">' . $addlink . '</div>' ); 281 } 282} 283