-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathadmin.php
477 lines (400 loc) · 15.1 KB
/
admin.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
<?php
/**
* Delete unnecessary languages -> administration function
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Taggic <[email protected]>
*/
// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();
/** Implicit data type:
*
* ^Lang is an array that looks like the following
* { "core": [ $lang... ],
* "templates": [ $tpl_name: [ $lang... ], ... ],
* "plugins": [ $plugin_name: [ $lang... ], ... ]
* }
* where $lang is a DokuWiki language code
* $tpl_name is the template name
* $plugin_name is the plugin name
* The $lang arrays are zero-indexed
*/
/** CSS Classes:
*
* ul.languages is an inline list of language codes
* if li.active is set, the text will be highlighted
* if li.enabled is set, the text is normal,
* otherwise it's red and striked-out
* .module is set on text that represent module names: template names,
* plugin names and "dokuwiki"
*
* #langshortlist is the list of language with checkboxes
* #langlonglist is the list of list of languages available for each module
* .langdelete__text is the class set on the section wrapper around all the text
*/
/**
* All DokuWiki plugins to extend the admin function
* need to inherit from this class
*/
class admin_plugin_langdelete extends DokuWiki_Admin_Plugin {
/** Fallback language */
const DEFAULT_LANG = 'en';
/** data stdObject assigned by ->handle() and used in ->html() */
private $d;
/** return sort order for position in admin menu */
function getMenuSort() { return 20; }
/** Called when dispatching the DokuWiki action;
* Puts the required data for ->html() in $->d */
function handle() {
$d =& $this->d;
$d = new stdClass; // reset
$d->submit = isset($_REQUEST['submit']);
$submit =& $d->submit;
/* Check security token */
if ($submit) {
$valid =& $d->valid;
$valid = True;
if (!checkSecurityToken()) {
$valid = False;
return;
}
}
/* Set DokuWiki language info */
$d->langs = $this->list_languages();
$langs =& $d->langs;
// $u_langs is in alphabetical (?) order because directory listing
$d->u_langs = $this->lang_unique($langs);
$u_langs =& $d->u_langs;
/* Grab form data */
if ($submit) {
$d->dryrun = $_REQUEST['dryrun'];
$lang_str = $_REQUEST['langdelete_w'];
}
/* What languages do we keep ? */
$lang_keep[] = self::DEFAULT_LANG; // add 'en', the fallback
$lang_keep[] = $conf['lang']; // add current lang
if ($submit) {
/* Add form data to languages to keep */
if (strlen ($lang_str) > 0) {
$lang_keep = array_merge ($lang_keep, explode(',', $lang_str));
}
} else {
// Keep every language on first run
$lang_keep = $u_langs;
}
$lang_keep = array_values(array_filter(array_unique($lang_keep)));
$d->lang_keep =& $lang_keep;
/* Does the language we want to keep actually exist ? */
$non_langs = array_diff ($lang_keep, $u_langs);
if ($non_langs) {
$d->nolang_s = implode (",", $non_langs);
}
/* Prepare data for deletion */
if ($submit) {
$d->langs_to_delete = $this->_filter_out_lang ($langs, $lang_keep);
}
/* What do the checkboxes say ? */
if ($submit) {
/* Grab checkboxes */
$d->shortlang = array_keys ($_REQUEST['shortlist']);
$shortlang =& $d->shortlang;
/* Prevent discrepancy between shortlist and text form */
if (array_diff ($lang_keep, $shortlang)
|| array_diff ($shortlang, $lang_keep))
{
$d->discrepancy = True;
}
} else {
// Keep every language on first run
$d->shortlang = $u_langs;
}
}
/**
* langdelete Output function
*
* Prints a table with all found language folders.
* HTML and data processing are done here at the same time
*
* @author Taggic <[email protected]>
*/
function html() {
global $conf; // access DW configuration array
$d =& $this->d; // from ->handle()
// In case we want to fetch the files from gh
#$version = getVersionData();
// langdelete__intro
echo $this->locale_xhtml('intro');
// input anchor
echo '<a name="langdelete_inputbox"></a>'.NL;
echo $this->locale_xhtml('guide');
// input form
$this->_html_form($d);
$langs = $this->list_languages();
$u_langs = $this->lang_unique($langs);
/* Switch on form submission state */
if (!$d->submit) {
/* Show available languages */
echo '<section class="langdelete__text">';
echo $this->getLang('available_langs');
$this->print_shortlist ($d);
$this->html_print_langs($d->langs);
echo '</section>';
} else {
/* Process form */
/* Check token */
if (!$d->valid) {
echo "<p>Invalid security token</p>";
return;
}
if ($d->discrepancy) {
msg($this->getLang('discrepancy_warn'), 2);
}
if ($d->nolang_s) {
msg($this->getLang('nolang') . $d->nolang_s , 2);
}
echo '<h2>'.$this->getLang('h2_output').'</h2>'.NL;
if ($d->dryrun) {
/* Display what will be deleted */
msg($this->getLang('langdelete_willmsg'), 2);
echo '<section class="langdelete__text">';
echo $this->getLang('available_langs');
$this->print_shortlist ($d);
$this->html_print_langs($d->langs, $d->lang_keep);
echo '</section>';
msg($this->getLang('langdelete_attention'), 2);
echo '<a href="#langdelete_inputbox">'.$this->getLang('backto_inputbox').'</a>'.NL;
} else {
/* Delete and report what was deleted */
msg($this->getLang('langdelete_delmsg'), 0);
echo '<section class="langdelete__text">';
$this->html_print_langs($d->langs_to_delete);
echo '</section>';
echo '<pre>';
$this->remove_langs($d->langs_to_delete);
echo '</pre>';
}
}
}
/**
* Display the form with input control to let the user specify,
* which languages to be kept beside en
*
* @author Taggic <[email protected]>
*/
private function _html_form (&$d) {
global $ID, $conf;
echo '<form id="langdelete__form" action="'.wl($ID).'" method="post">';
echo '<input type="hidden" name="do" value="admin" />'.NL;
echo '<input type="hidden" name="page" value="'.$this->getPluginName().'" />'.NL;
formSecurityToken();
echo '<fieldset class="langdelete__fieldset"><legend>'.$this->getLang('i_legend').'</legend>'.NL;
echo '<label class="formTitle">'.$this->getLang('i_using').':</label>';
echo '<div class="box">'.$conf['lang'].'</div>'.NL;
echo '<label class="formTitle" for="langdelete_w">'.$this->getLang('i_shouldkeep').':</label>';
echo '<input type="text" name="langdelete_w" class="edit" value="'.hsc(implode(',', $d->lang_keep)).'" />'.NL;
echo '<label class="formTitle" for="option">'.$this->getLang('i_runoption').':</label>';
echo '<div class="box">'.NL;
echo '<input type="checkbox" name="dryrun" checked="checked" /> ';
echo '<label for="dryrun">'.$this->getLang('i_dryrun').'</label>'.NL;
echo '</div>'.NL;
echo '<button name="submit">'.$this->getLang('btn_start').'</button>'.NL;
echo '</fieldset>'.NL;
echo '</form>'.NL;
}
/** Print the language shortlist and cross-out those not in $keep */
function print_shortlist (&$d) {
$shortlang =& $d->shortlang;
echo '<ul id="langshortlist" class="languages">';
# As the disabled input won't POST
echo '<input type="hidden" name="shortlist['.self::DEFAULT_LANG.']"'
.' form="langdelete__form" />';
foreach ($d->u_langs as $l) {
$checked = in_array($l, $shortlang) || $l == self::DEFAULT_LANG;
echo '<li'.($checked ? ' class="enabled"' : '').'>';
echo '<input type="checkbox" id="shortlang-'.$l.'"'
.' name="shortlist['.$l.']"'
.' form="langdelete__form"'
.($checked ? ' checked' : '')
.($l == self::DEFAULT_LANG ? ' disabled' : '')
.' />';
echo '<label for="shortlang-'.$l.'">';
if ($checked) {
echo $l;
} else {
echo '<del>'.$l.'</del>';
}
echo '</label>';
echo '</li>';
}
echo '</ul>';
}
/** Display the languages in $langs for each module as a HTML list;
* Cross-out those not in $keep
*
* Signature: ^Lang, Array => () */
private function html_print_langs ($langs, $keep = null) {
/* Print language list, $langs being an array;
* Cross out those not in $keep */
$print_lang_li = function ($langs) use ($keep) {
echo '<ul class="languages">';
foreach ($langs as $val) {
// If $keep is null, we keep everything
$enabled = is_null($keep) || in_array ($val, $keep);
echo '<li val="'.$val.'"'
.($enabled ? ' class="enabled"' : '')
.'>';
if ($enabled) {
echo $val;
} else {
echo '<del>'.$val.'</del>';
}
echo '</li>';
}
echo '</ul>';
};
echo '<ul id="langlonglist">';
// Core
echo '<li><span class="module">'.$this->getLang('dokuwiki_core').'</span>';
$print_lang_li ($langs['core']);
echo '</li>';
// Templates
echo '<li>'.$this->getLang('templates');
echo '<ul>';
foreach ($langs['templates'] as $name => $l) {
echo '<li><span class="module">'.$name.':</span>';
$print_lang_li ($l);
echo '</li>';
}
echo '</ul>';
echo '</li>';
// Plugins
echo '<li>'.$this->getLang('plugins');
echo '<ul>';
foreach ($langs['plugins'] as $name => $l) {
echo '<li><span class="module">'.$name.':</span>';
$print_lang_li ($l);
echo '</li>';
}
echo '</ul>';
echo '</li>';
echo '</ul>';
}
/** Returns the available languages for each module
* (core, template or plugin)
*
* Signature: () => ^Lang
*/
private function list_languages () {
// See https://www.dokuwiki.org/devel:localization
/* Returns the subfolders of $dir as an array */
$dir_subfolders = function ($dir) {
$sub = scandir($dir);
$sub = array_filter ($sub, function ($e) use ($dir) {
return is_dir ("$dir/$e")
&& !in_array ($e, array('.', '..'));
} );
return $sub;
};
/* Return an array of template names */
$list_templates = function () use ($dir_subfolders) {
return $dir_subfolders (DOKU_INC."lib/tpl");
};
/* Return an array of languages available for the module
* (core, template or plugin) given its $root directory */
$list_langs = function ($root) use ($dir_subfolders) {
$dir = "$root/lang";
if (!is_dir ($dir)) return;
return $dir_subfolders ($dir);
};
/* Get templates and plugins names */
global $plugin_controller;
$plugins = $plugin_controller->getList();
$templates = $list_templates();
return array(
"core" => $list_langs (DOKU_INC."inc"),
"templates" => array_combine ($templates,
array_map ($list_langs,
array_prefix ($templates, DOKU_INC."lib/tpl/"))),
"plugins" => array_combine ($plugins,
array_map ($list_langs,
array_prefix ($plugins, DOKU_PLUGIN)))
);
}
/** Remove $lang_keep from the module languages $e
*
* Signature: ^Lang, Array => ^Lang */
private function _filter_out_lang ($e, $lang_keep) {
// Recursive function with cases being an array of arrays, or an array
if (count ($e) > 0 && is_array (array_values($e)[0])) {
foreach ($e as $k => $elt) {
$out[$k] = $this->_filter_out_lang ($elt, $lang_keep);
}
return $out;
} else {
return array_filter ($e, function ($v) use ($lang_keep) {
return !in_array ($v, $lang_keep);
});
}
}
/** Return an array of the languages in $l
*
* Signature: ^Lang => Array */
private function lang_unique ($l) {
foreach ($l['core'] as $lang) {
$count[$lang]++;
}
foreach ($l['templates'] as $tpl => $arr) {
foreach ($arr as $lang) {
$count[$lang]++;
}
}
foreach ($l['plugins'] as $plug => $arr) {
foreach ($arr as $lang) {
$count[$lang]++;
}
}
return array_keys ($count);
}
/** Delete the languages from the modules as specified by $langs
*
* Signature: ^Lang => () */
private function remove_langs($langs) {
foreach ($langs['core'] as $l) {
$this->rrm(DOKU_INC."inc/lang/$l");
}
foreach ($langs['templates'] as $tpl => $arr) {
foreach ($arr as $l) {
$this->rrm(DOKU_INC."lib/tpl/$tpl/lang/$l");
}
}
foreach ($langs['plugins'] as $plug => $arr) {
foreach ($arr as $l) {
$this->rrm(DOKU_INC."lib/plugins/$plug/lang/$l");
}
}
}
/** Recursive file removal of $path with reporting */
private function rrm ($path) {
if (is_dir ($path)) {
$objects = scandir ($path);
foreach ($objects as $object) {
if (!in_array ($object, array('.', '..'))) {
$this->rrm("$path/$object");
}
}
$sucess = @rmdir ($path);
if (!$sucess) { echo "Failed to delete $path/\n"; }
else echo "Delete $path\n";
} else {
$sucess = @unlink ($path);
if (!$sucess) { echo "Failed to delete $path\n"; }
else echo "Delete $path\n";
}
}
}
/** Returns an array with each element of $arr prefixed with $prefix */
function array_prefix ($arr, $prefix) {
return array_map (
function ($p) use ($prefix) { return $prefix.$p; },
$arr);
}