3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
6 * Copyright (c) 2001-2019 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
9 * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
10 * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
11 \***************************************************************************/
14 * Fonctions pour l'affichage des informations de plugins
16 * @package SPIP\Core\Plugins
19 if (!defined('_ECRIRE_INC_VERSION')) {
22 include_spip('inc/charsets');
23 include_spip('inc/texte');
24 include_spip('inc/plugin'); // pour plugin_est_installe
26 // http://code.spip.net/@ligne_plug
27 function plugins_afficher_plugin_dist(
34 $dir_plugins = _DIR_PLUGINS
38 static $versions = array();
40 $force_reload = (_request('var_mode') == 'recalcul');
41 $get_infos = charger_fonction('get_infos', 'plugins');
42 $info = $get_infos($plug_file, $force_reload, $dir_plugins);
43 $prefix = $info['prefix'];
45 $checkable = ($dir_plugins !== _DIR_PLUGINS_DIST
);
46 $nom = plugin_nom($info, $dir_plugins, $plug_file);
49 if (!plugin_version_compatible($info['compatibilite'], $GLOBALS['spip_version_branche'], 'spip')) {
50 $info['slogan'] = _T('plugin_info_non_compatible_spip');
51 $erreur = http_img_pack("plugin-dis-32.png", _T('plugin_info_non_compatible_spip'), " class='picto_err'",
52 _T('plugin_info_non_compatible_spip'));
53 $class_li .= " disabled";
55 } elseif (isset($info['erreur'])) {
56 $class_li .= " error";
57 $erreur = http_img_pack("plugin-err-32.png", _T('plugin_info_erreur_xml'), " class='picto_err'",
58 _T('plugin_info_erreur_xml'))
59 . "<div class='erreur'>" . join('<br >', $info['erreur']) . "</div>";
61 } elseif (isset($GLOBALS['erreurs_activation_raw'][$dir_plugins . $plug_file])) {
62 $class_li .= " error";
63 $erreur = http_img_pack("plugin-err-32.png", _T('plugin_impossible_activer', array('plugin' => $nom)),
64 " class='picto_err'", _T('plugin_impossible_activer', array('plugin' => $nom)))
65 . "<div class='erreur'>" . implode("<br />",
66 $GLOBALS['erreurs_activation_raw'][$dir_plugins . $plug_file]) . "</div>";
68 $cfg = $actif ?
plugin_bouton_config($plug_file, $info, $dir_plugins) : "";
71 // numerotons les occurrences d'un meme prefix
72 $versions[$prefix] = $id = isset($versions[$prefix]) ?
intval($versions[$prefix]) +
1 : '';
74 $class_li .= ($actif ?
" actif" : "") . ($expose ?
" on" : "");
76 return "<li id='$prefix$id' class='$class_li'>"
77 . ((!$checkable and !$checked)
78 ?
'' : plugin_checkbox(++
$id_input, $dir_plugins . $plug_file, $checked))
79 . plugin_resume($info, $dir_plugins, $plug_file, $url_page)
82 . (($dir_plugins !== _DIR_PLUGINS_DIST
and plugin_est_installe($plug_file))
83 ?
plugin_desintalle($plug_file, $nom, $dir_plugins) : '')
84 . "<div class='details'>" // pour l'ajax de exec/info_plugin
85 . (!$expose ?
'' : affiche_bloc_plugin($plug_file, $info, $dir_plugins))
90 function plugin_bouton_config($nom, $infos, $dir) {
91 // la verification se base sur le filesystem
92 // il faut donc n'utiliser que des minuscules, par convention
93 $prefix = strtolower($infos['prefix']);
94 // si plugin.xml fournit un squelette, le prendre
95 if (isset($infos['config']) and $infos['config']) {
96 return recuperer_fond("$dir$nom/" . $infos['config'],
98 'script' => 'configurer_' . $prefix,
103 // si le plugin CFG est la, l'essayer
104 if (defined('_DIR_PLUGIN_CFG')) {
105 if (include_spip('inc/cfg')) // test CFG version >= 1.0.5
107 if ($cfg = icone_lien_cfg("$dir$nom", "cfg")) {
108 return "<div class='cfg_link'>$cfg</div>";
113 // sinon prendre le squelette std sur le nom std
114 return recuperer_fond("prive/squelettes/inclure/cfg",
116 'script' => 'configurer_' . $prefix,
121 // checkbox pour activer ou desactiver
122 // si ce n'est pas une extension
124 function plugin_checkbox($id_input, $file, $actif) {
125 $name = substr(md5($file), 0, 16);
127 return "<div class='check'>\n"
128 . "<input type='checkbox' name='s$name' id='label_$id_input'"
129 . ($actif ?
" checked='checked'" : "")
130 . " class='checkbox' value='O' />"
131 . "\n<label for='label_$id_input'>" . _T('activer_plugin') . "</label>"
135 function plugin_nom($info, $dir_plugins, $plug_file) {
136 $prefix = $info['prefix'];
137 $dir = "$dir_plugins$plug_file";
138 // Si dtd paquet, on traite le nom soit par son item de langue soit par sa valeur immediate a l'index "nom"
139 if ($info['dtd'] == "paquet") {
140 $nom = PtoBR(plugin_propre("{$prefix}_nom", "$dir/lang/paquet-$prefix"));
142 $nom = PtoBR(propre($info['nom']));
145 $nom = typo(attribut_html($info['nom']));
152 function plugin_resume($info, $dir_plugins, $plug_file, $url_page) {
153 $prefix = $info['prefix'];
154 $dir = "$dir_plugins$plug_file";
155 $slogan = PtoBR(plugin_propre($info['slogan'], "$dir/lang/paquet-$prefix"));
156 // une seule ligne dans le slogan : couper si besoin
157 if (($p = strpos($slogan, "<br />")) !== false) {
158 $slogan = substr($slogan, 0, $p);
160 // couper par securite
161 $slogan = couper($slogan, 80);
163 $nom = plugin_nom($info, $dir_plugins, $plug_file);
165 $url = parametre_url($url_page, "plugin", substr($dir, strlen(_DIR_RACINE
)));
167 if (isset($info['logo']) and $i = trim($info['logo'])) {
168 include_spip("inc/filtres_images_mini");
169 $i = inserer_attribut(image_reduire("$dir/$i", 32), 'alt', '');
170 $i = "<div class='icon'><a href='$url' rel='info'>$i</a></div>";
175 return "<div class='resume'>"
176 . "<h3><a href='$url' rel='info'>"
179 . " <span class='version'>" . $info['version'] . "</span>"
180 . " <span class='etat'> - "
181 . plugin_etat_en_clair($info['etat'])
183 . "<div class='short'>" . $slogan . "</div>"
188 function plugin_desintalle($plug_file, $nom, $dir_plugins = null) {
190 $dir_plugins = _DIR_PLUGINS
;
193 $action = redirige_action_auteur('desinstaller_plugin', "$dir_plugins::$plug_file", 'admin_plugin');
194 $text = _T('bouton_desinstaller');
195 $text2 = _T('info_desinstaller_plugin');
196 $file = basename($plug_file);
198 return "<div class='actions'>[" .
200 onclick='return confirm(\"$text $nom ?\\n$text2\")'>"
206 * Traduit un type d'état de plugin
208 * Si l'état n'existe pas, prendra par défaut 'developpement'
210 * @param string $etat
211 * Le type d'état (stable, test, ...)
213 * Traduction de l'état dans la langue en cours
215 function plugin_etat_en_clair($etat) {
216 if (!in_array($etat, array('stable', 'test', 'experimental'))) {
217 $etat = 'developpement';
220 return _T('plugin_etat_' . $etat);
223 // http://code.spip.net/@plugin_propre
224 function plugin_propre($texte, $module = '') {
225 // retirer le retour a la racine du module, car le find_in_path se fait depuis la racine
226 if (_DIR_RACINE
and strncmp($module, _DIR_RACINE
, strlen(_DIR_RACINE
)) == 0) {
227 $module = substr($module, strlen(_DIR_RACINE
));
229 if (preg_match("|^\w+_[\w_]+$|", $texte)) {
230 $texte = _T(($module ?
"$module:" : '') . $texte, array(), array('force' => false));
233 return propre($texte);
237 // http://code.spip.net/@affiche_bloc_plugin
238 function affiche_bloc_plugin($plug_file, $info, $dir_plugins = null) {
240 $dir_plugins = _DIR_PLUGINS
;
243 $prefix = $info['prefix'];
244 $dir = "$dir_plugins$plug_file/lang/paquet-$prefix";
247 // TODO: le traiter_multi ici n'est pas beau
248 // cf. description du plugin/_stable_/ortho/plugin.xml
250 if (isset($info['description'])) {
251 $description = plugin_propre($info['description'], $dir);
254 if (isset($info['documentation'])
255 and $lien = $info['documentation']
257 $description .= "<p><em class='site'><a href='$lien' class='spip_out'>" . _T('en_savoir_plus') . '</a></em></p>';
259 $s .= "<dd class='desc'>" . $description . "</dd>\n";
261 if (isset($info['auteur'])) {
262 if (is_array($info['auteur'])) {
263 $a = formater_credits($info['auteur'], ', ');
264 } // pour compat mais ne doit plus arriver
266 $a = trim($info['auteur']);
269 $s .= "<dt class='auteurs'>" . _T('public:par_auteur') . "</dt><dd class='auteurs'>" . PtoBR(propre($a,
274 if (isset($info['credit'])) {
275 if ($a = formater_credits($info['credit'], ', ')) {
276 $s .= "<dt class='credits'>" . _T('plugin_info_credit') . "</dt><dd class='credits'>" . PtoBR(propre($a,
281 if (isset($info['licence'])) {
282 if (is_array($info['licence'])) {
283 $a = formater_credits($info['licence'], ', ');
284 } // pour compat mais ne doit plus arriver
286 $a = trim($info['licence']);
289 $s .= "<dt class='licence'>" . _T('intitule_licence') . "</dt><dd class='licence'>" . PtoBR(propre($a,
294 $s = "<dl class='description'>$s</dl>";
297 // Ajouter les infos techniques
301 $version = "<dt>" . _T('version') . "</dt><dd>" . $info['version'];
303 if ($svn_revision = version_svn_courante($dir_plugins . $plug_file)) {
304 $version .= ($svn_revision < 0 ?
' SVN' : '') . ' [' . abs($svn_revision) . ']';
307 $infotech[] = $version;
308 $infotech[] = "<dt>" . _T('repertoire_plugins') . "</dt><dd>" . joli_repertoire("$dir_plugins$plug_file") . "</dd>";
309 // source zip le cas echeant
310 $infotech[] = (lire_fichier($dir_plugins . $plug_file . '/install.log', $log)
311 and preg_match(',^source:(.*)$,m', $log, $r))
312 ?
'<dt>' . _T('plugin_source') . '</dt><dd>' . trim($r[1]) . "</dd>"
315 $infotech[] = !$info['necessite'] ?
'' :
316 ('<dt>' . _T('plugin_info_necessite') . '</dt><dd>' . join(' ',
317 array_map('array_shift', $info['necessite'])) . '</dd>');
319 $s .= "<dl class='tech'>"
320 . join('', $infotech)
327 function formater_credits($infos, $sep = ', ') {
330 foreach ($infos as $_credit) {
334 // Si le credit en cours n'est pas un array c'est donc un copyright
336 (!is_array($_credit))
337 ?
PtoBR(propre($_credit))
338 : ($_credit['url'] ?
'<a href="' . $_credit['url'] . '">' : '') .
340 ($_credit['url'] ?
'</a>' : '');