1+ <?php
2+ /**
3+ * DokuWiki Plugin const (Action Component)
4+ *
5+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
6+ * @author lisps
7+ */
8+
9+ if (!defined ('DOKU_INC ' ))
10+ define ('DOKU_INC ' , realpath (dirname (__FILE__ ) . '/../../ ' ) . '/ ' );
11+ if (!defined ('DOKU_PLUGIN ' ))
12+ define ('DOKU_PLUGIN ' , DOKU_INC . 'lib/plugins/ ' );
13+
14+ require_once (DOKU_PLUGIN . 'action.php ' );
15+
16+ /**
17+ * All DokuWiki plugins to extend the parser/rendering mechanism
18+ * need to inherit from this class
19+ */
20+ class action_plugin_const extends DokuWiki_Action_Plugin {
21+ /**
22+ * return some info
23+ */
24+ private $ autoindexer = 0 ;
25+ private $ invalidate = FALSE ;
26+
27+ /**
28+ * offsets-at-character-position. recorded as tuples {charpos,offset}, where charpos is the
29+ * position in the MODIFIED data, not the position in the original data, and offset is the
30+ * CUMULATIVE offset at that position, not the offset relative to the previous location.
31+ */
32+ var $ offsets = array ();
33+
34+ /**
35+ * pagename for which calculation is made
36+ *
37+ */
38+ var $ page = '' ;
39+
40+ /**
41+ * During the run, contains the original wiki data.
42+ */
43+ var $ original ;
44+
45+ /**
46+ * During the run, contains the modified wiki data.
47+ */
48+ var $ wikified ;
49+
50+
51+ //hook before rendering starts
52+ function register (&$ controller ) {
53+ $ controller ->register_hook ('PARSER_WIKITEXT_PREPROCESS ' , 'BEFORE ' , $ this , '_doreplace ' );
54+ $ controller ->register_hook ('PARSER_HANDLER_DONE ' , 'BEFORE ' , $ this , '_fixsecedit ' );
55+ $ controller ->register_hook ('PARSER_CACHE_USE ' , 'BEFORE ' , $ this , '_cache_control ' );
56+ }
57+
58+
59+ function _replacecallback ($ hits ) {
60+ return ($ this ->autoindexer ++);
61+ }
62+
63+ //trigger
64+ function _doreplace (&$ event , $ param ) {
65+ global $ ID ;
66+
67+ require_once (dirname (__FILE__ ) . "/class.evalmath.php " );
68+ $ math = new evalmath ();
69+
70+ $ this ->invalidate = FALSE ;
71+
72+ $ this ->original = $ event ->data ;
73+ $ this ->wikified = $ this ->original ;
74+
75+ //catch anonymous access
76+ $ username =isset ($ _SERVER ['REMOTE_USER ' ])?$ _SERVER ['REMOTE_USER ' ]:"anonymous " ;
77+
78+ //get const definitions
79+ $ data = array ();
80+ if (preg_match ('§<const[^>]*>([^<]*)</const>§ ' , $ event ->data , $ data ) > 0 ) {
81+ //split entries
82+ $ data = array_pop ($ data );
83+ $ data = preg_split ('/[\r\n]+/ ' , $ data , -1 , PREG_SPLIT_NO_EMPTY );
84+
85+ //process wiki-data
86+ $ autoindex = 0 ;
87+ foreach ($ data as $ entry ) {
88+ //normal const
89+ $ item = explode ("= " , trim ($ entry ));
90+ if (count ($ item ) === 2 ) {
91+ //special string-replace
92+ switch ($ item [1 ]) {
93+ case "%USER% " :
94+ $ item [1 ] = $ username ;
95+ $ this ->invalidate = TRUE ;
96+ break ; //pagename
97+ case "%ID% " :
98+ $ item [1 ] = noNS (cleanID (getID ()));
99+ break ; //pagename
100+ case "%NAMESPACE% " :
101+ $ item [1 ] = getNS (cleanID (getID ()));
102+ break ; //namespace
103+ case "%RANDOM% " :
104+ $ item [1 ] = strval (rand ());
105+ $ this ->invalidate = TRUE ;
106+ break ; //random number
107+ case "%YEAR% " :
108+ $ item [1 ] = date ("Y " );
109+ break ; //current year
110+ case "%MONTH% " :
111+ $ item [1 ] = date ("m " );
112+ break ; //current month
113+ case "%MONTHNAME% " :
114+ $ item [1 ] = date ("F " );
115+ break ; //current month
116+ case "%WEEK% " :
117+ $ item [1 ] = date ("W " );
118+ $ this ->invalidate = TRUE ;
119+ break ; //current week (iso)
120+ case "%DAY% " :
121+ $ item [1 ] = date ("d " );
122+ $ this ->invalidate = TRUE ;
123+ break ; //current day
124+ case "%DAYNAME% " :
125+ $ item [1 ] = date ("l " );
126+ $ this ->invalidate = TRUE ;
127+ break ; //current day
128+ case "%AUTOINDEX% " :
129+ $ item [1 ] = "%%INDEX# " . (++$ autoindex ) . "%% " ; //special automatic indexer
130+ break ;
131+ default :
132+ $ item [1 ] = trim ($ item [1 ]);
133+ break ;
134+ }
135+
136+ //replace in wiki
137+ $ this ->wikified = str_replace ("%% " . trim ($ item [0 ]) . "%% " , $ item [1 ], $ this ->wikified );
138+
139+ //load evaluator
140+ @$ math ->evaluate ($ item [0 ]."= " .$ item [1 ]);
141+ } else {
142+ //evaluate expression
143+ $ item = explode (": " , $ entry );
144+ if (count ($ item ) === 2 ) {
145+ $ this ->wikified = str_replace ("%% " . trim ($ item [0 ]) . "%% " , @$ math ->evaluate ($ item [1 ]), $ this ->wikified );
146+ }
147+ }
148+ }
149+
150+ //autoindex?
151+ while ($ autoindex > 0 ) {
152+ $ this ->autoindexer = 1 ;
153+ //replace all
154+ $ this ->wikified = preg_replace_callback ("|%%INDEX# " . $ autoindex . "%%| " , array (
155+ $ this ,
156+ "_replacecallback "
157+ ), $ this ->wikified );
158+ $ autoindex --;
159+ }
160+
161+ $ event ->data = $ this ->wikified ;
162+
163+ $ this ->original = explode ("\n" , $ this ->original );
164+ $ this ->wikified = explode ("\n" , $ this ->wikified );
165+
166+ // fill offset array to deal with section editing issues
167+ for ($ l = 0 ; $ l < count ($ this ->wikified ); $ l ++) {
168+ // record offsets at the start of this line
169+ $ this ->offsets [] = array (
170+ 'pos ' => $ char_pos ,
171+ 'offset ' => $ text_offset
172+ );
173+ // calculate position / offset for next line
174+ $ char_pos += strlen ($ this ->wikified [$ l ]) + 1 ;
175+ $ text_offset += strlen ($ this ->wikified [$ l ]) - strlen ($ this ->original [$ l ]);
176+ //echo '(' . $char_pos . '/' . $text_offset . ')' . ' ';
177+ }
178+ }
179+
180+ unset($ this ->original );
181+ unset($ this ->wikified );
182+
183+ //save invalidation info to metadata
184+ p_set_metadata ($ ID , array (
185+ 'plugin_const ' => array (
186+ 'invalidate ' => $ this ->invalidate
187+ )
188+ ), FALSE , TRUE );
189+ }
190+
191+ /**
192+ * force cache invalidation for certain constants
193+ */
194+ function _cache_control (&$ event , $ param ) {
195+ global $ conf ;
196+
197+ $ cache =& $ event ->data ;
198+
199+ if ((isset ($ cache ->page ) == TRUE ) && ($ cache ->mode == "i " )) {
200+ //cache purge requested?
201+ $ const = p_get_metadata ($ cache ->page , 'plugin_const ' );
202+
203+ //force initial purge
204+ if (!isset ($ const ['invalidate ' ])) {
205+ $ const ['invalidate ' ] = TRUE ;
206+ }
207+
208+ $ cache ->depends ["purge " ] = $ const ["invalidate " ];
209+ }
210+ }
211+
212+ /**
213+ * modifying the raw data has as side effect that the sectioning is based on the
214+ * modified data, not the original. This means that after processing, we need to
215+ * adjust the section start/end markers so that they point to start/end positions
216+ * in the original data, not the modified data.
217+ */
218+ function _fixsecedit (&$ event , $ param ) {
219+ global $ ID ;
220+ if ($ ID != $ this ->page ) return ;
221+
222+ $ calls =& $ event ->data ->calls ;
223+ $ count = count ($ calls );
224+
225+ // iterate through the instruction list and set the file offset values
226+ // back to the values they would be if no const syntax has been added by this plugin
227+ for ($ i = 0 ; $ i < $ count ; $ i ++) {
228+ if ($ calls [$ i ][0 ] == 'section_open ' || $ calls [$ i ][0 ] == 'section_close ' || $ calls [$ i ][0 ] == 'header ' || $ calls [$ i ][0 ] == 'p_open ' ) {
229+ $ calls [$ i ][2 ] = $ this ->_convert ($ calls [$ i ][2 ]);
230+ }
231+ if ($ calls [$ i ][0 ] == 'header ' ) {
232+ $ calls [$ i ][1 ][2 ] = $ this ->_convert ($ calls [$ i ][1 ][2 ]);
233+ }
234+ // be aware of headernofloat plugin
235+ if ($ calls [$ i ][0 ] == 'plugin ' && $ calls [$ i ][1 ][0 ] == 'headernofloat ' ) {
236+ $ calls [$ i ][1 ][1 ]['pos ' ] = $ this ->_convert ($ calls [$ i ][1 ][1 ]['pos ' ]);
237+ $ calls [$ i ][2 ] = $ this ->_convert ($ calls [$ i ][2 ]);
238+ }
239+ }
240+ }
241+
242+ /**
243+ * Convert modified raw wiki offset value pos back to the unmodified value
244+ */
245+ function _convert ($ pos ) {
246+ // find the offset that applies to this character position
247+ $ offset = 0 ;
248+ foreach ($ this ->offsets as $ tuple ) {
249+ if ($ pos >= $ tuple ['pos ' ]) {
250+ $ offset = $ tuple ['offset ' ];
251+ } else {
252+ break ;
253+ }
254+ }
255+
256+ // return corrected position
257+ return $ pos - $ offset ;
258+ }
259+ }
0 commit comments