PageRenderTime 53ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/themeEditor/class.themeEditor.php

https://bitbucket.org/dotclear/dotclear/
PHP | 372 lines | 302 code | 51 blank | 19 comment | 69 complexity | c9273ba9716ea01956ad86517883c432 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, Apache-2.0
  1. <?php
  2. # -- BEGIN LICENSE BLOCK ---------------------------------------
  3. #
  4. # This file is part of Dotclear 2.
  5. #
  6. # Copyright (c) 2003-2013 Olivier Meunier & Association Dotclear
  7. # Licensed under the GPL version 2.0 license.
  8. # See LICENSE file or
  9. # http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  10. #
  11. # -- END LICENSE BLOCK -----------------------------------------
  12. if (!defined('DC_RC_PATH')) { return; }
  13. class dcThemeEditor
  14. {
  15. protected $core;
  16. protected $user_theme;
  17. protected $parent_theme;
  18. protected $tplset_theme;
  19. protected $parent_name;
  20. protected $tplset_name;
  21. public $tpl = array();
  22. public $css = array();
  23. public $js = array();
  24. public $po = array();
  25. public function __construct($core)
  26. {
  27. $this->core =& $core;
  28. $this->default_theme = path::real($this->core->blog->themes_path.'/default');
  29. $this->user_theme = path::real($this->core->blog->themes_path.'/'.$this->core->blog->settings->system->theme);
  30. $this->tplset_theme = DC_ROOT.'/inc/public/default-templates/'.DC_DEFAULT_TPLSET;
  31. $this->tplset_name = DC_DEFAULT_TPLSET;
  32. if (null !== $this->core->themes) {
  33. $parent_theme = $this->core->themes->moduleInfo($this->core->blog->settings->system->theme,'parent');
  34. if ($parent_theme) {
  35. $this->parent_theme = path::real($this->core->blog->themes_path.'/'.$parent_theme);
  36. $this->parent_name = $parent_theme;
  37. }
  38. $tplset = $this->core->themes->moduleInfo($this->core->blog->settings->system->theme,'tplset');
  39. if ($tplset) {
  40. $this->tplset_theme = DC_ROOT.'/inc/public/default-templates/'.$tplset;
  41. $this->tplset_name = $tplset;
  42. }
  43. }
  44. $this->findTemplates();
  45. $this->findStyles();
  46. $this->findScripts();
  47. $this->findLocales();
  48. }
  49. public function filesList($type,$item='%1$s',$split=true)
  50. {
  51. $files = $this->getFilesFromType($type);
  52. if (empty($files)) {
  53. return '<p>'.__('No file').'</p>';
  54. }
  55. $list = '';
  56. if ($split) {
  57. $list_theme = ''; // Files from current theme
  58. $list_parent = ''; // Files from parent of current theme
  59. $list_tpl = ''; // Files from template set used by current theme
  60. foreach ($files as $k => $v)
  61. {
  62. if (strpos($v,$this->user_theme) === 0) {
  63. $li = sprintf('<li class="default-file">%s</li>',$item);
  64. $list_theme .= sprintf($li,$k,html::escapeHTML($k));
  65. } elseif ($this->parent_theme && strpos($v,$this->parent_theme) === 0) {
  66. $li = sprintf('<li class="parent-file">%s</li>',$item);
  67. $list_parent .= sprintf($li,$k,html::escapeHTML($k));
  68. } else {
  69. $li = sprintf('<li>%s</li>',$item);
  70. $list_tpl .= sprintf($li,$k,html::escapeHTML($k));
  71. }
  72. }
  73. $list .= ($list_theme != '' ? sprintf('<li class="group-file">'.__('From theme:').'<ul>%s</ul></li>',$list_theme) : '');
  74. $list .= ($list_parent != '' ? sprintf('<li class="group-file">'.__('From parent:').' %s<ul>%s</ul></li>',
  75. $this->parent_name,$list_parent) : '');
  76. $list .= ($list_tpl != '' ? sprintf('<li class="group-file">'.__('From template set:').' %s<ul>%s</ul></li>',
  77. $this->tplset_name,$list_tpl) : '');
  78. } else {
  79. foreach ($files as $k => $v)
  80. {
  81. if (strpos($v,$this->user_theme) === 0) {
  82. $li = sprintf('<li class="default-file">%s</li>',$item);
  83. } elseif ($this->parent_theme && strpos($v,$this->parent_theme) === 0) {
  84. $li = sprintf('<li class="parent-file">%s</li>',$item);
  85. } else {
  86. $li = sprintf('<li>%s</li>',$item);
  87. }
  88. $list .= sprintf($li,$k,html::escapeHTML($k));
  89. }
  90. }
  91. return sprintf('<ul>%s</ul>',$list);
  92. }
  93. public function getFileContent($type,$f)
  94. {
  95. $files = $this->getFilesFromType($type);
  96. if (!isset($files[$f])) {
  97. throw new Exception(__('File does not exist.'));
  98. }
  99. $F = $files[$f];
  100. if (!is_readable($F)) {
  101. throw new Exception(sprintf(__('File %s is not readable'),$f));
  102. }
  103. return array(
  104. 'c' => file_get_contents($F),
  105. 'w' => $this->getDestinationFile($type,$f) !== false,
  106. 'type' => $type,
  107. 'f' => $f
  108. );
  109. }
  110. public function writeFile($type,$f,$content)
  111. {
  112. $files = $this->getFilesFromType($type);
  113. if (!isset($files[$f])) {
  114. throw new Exception(__('File does not exist.'));
  115. }
  116. try
  117. {
  118. $dest = $this->getDestinationFile($type,$f);
  119. if ($dest == false) {
  120. throw new Exception();
  121. }
  122. if ($type == 'tpl' && !is_dir(dirname($dest))) {
  123. files::makeDir(dirname($dest));
  124. }
  125. if ($type == 'po' && !is_dir(dirname($dest))) {
  126. files::makeDir(dirname($dest));
  127. }
  128. $fp = @fopen($dest,'wb');
  129. if (!$fp) {
  130. throw new Exception('tocatch');
  131. }
  132. $content = preg_replace('/(\r?\n)/m',"\n",$content);
  133. $content = preg_replace('/\r/m',"\n",$content);
  134. fwrite($fp,$content);
  135. fclose($fp);
  136. # Updating inner files list
  137. $this->updateFileInList($type,$f,$dest);
  138. }
  139. catch (Exception $e)
  140. {
  141. throw new Exception(sprintf(__('Unable to write file %s. Please check your theme files and folders permissions.'),$f));
  142. }
  143. }
  144. public function deletableFile($type,$f)
  145. {
  146. if ($type != 'tpl') {
  147. // Only tpl files may be deleted
  148. return false;
  149. }
  150. $files = $this->getFilesFromType($type);
  151. if (isset($files[$f])) {
  152. $dest = $this->getDestinationFile($type,$f);
  153. if ($dest) {
  154. if (file_exists($dest) && is_writable($dest)) {
  155. // Is there a model (parent theme or template set) ?
  156. if (isset($this->tpl_model[$f])) {
  157. return true;
  158. }
  159. }
  160. }
  161. }
  162. return false;
  163. }
  164. public function deleteFile($type,$f)
  165. {
  166. if ($type != 'tpl') {
  167. // Only tpl files may be deleted
  168. return;
  169. }
  170. $files = $this->getFilesFromType($type);
  171. if (!isset($files[$f])) {
  172. throw new Exception(__('File does not exist.'));
  173. }
  174. try
  175. {
  176. $dest = $this->getDestinationFile($type,$f);
  177. if ($dest) {
  178. // File exists and may be deleted
  179. unlink($dest);
  180. // Updating template files list
  181. $this->findTemplates();
  182. }
  183. }
  184. catch (Exception $e)
  185. {
  186. throw new Exception(sprintf(__('Unable to delete file %s. Please check your theme files and folders permissions.'),$f));
  187. }
  188. }
  189. protected function getDestinationFile($type,$f)
  190. {
  191. if ($type == 'tpl') {
  192. $dest = $this->user_theme.'/tpl/'.$f;
  193. } elseif ($type == 'po') {
  194. $dest = $this->user_theme.'/locales/'.$f;
  195. } else {
  196. $dest = $this->user_theme.'/'.$f;
  197. }
  198. if (file_exists($dest) && is_writable($dest)) {
  199. return $dest;
  200. }
  201. if ($type == 'tpl' && !is_dir(dirname($dest))) {
  202. if (is_writable($this->user_theme)) {
  203. return $dest;
  204. }
  205. }
  206. if ($type == 'po' && !is_dir(dirname($dest))) {
  207. if (is_writable($this->user_theme)) {
  208. return $dest;
  209. }
  210. }
  211. if (is_writable(dirname($dest))) {
  212. return $dest;
  213. }
  214. return false;
  215. }
  216. protected function getFilesFromType($type)
  217. {
  218. switch ($type)
  219. {
  220. case 'tpl':
  221. return $this->tpl;
  222. case 'css':
  223. return $this->css;
  224. case 'js':
  225. return $this->js;
  226. case 'po':
  227. return $this->po;
  228. default:
  229. return array();
  230. }
  231. }
  232. protected function updateFileInList($type,$f,$file)
  233. {
  234. switch ($type)
  235. {
  236. case 'tpl':
  237. $list =& $this->tpl;
  238. break;
  239. case 'css':
  240. $list =& $this->css;
  241. break;
  242. case 'js':
  243. $list =& $this->js;
  244. break;
  245. case 'po':
  246. $list =& $this->po;
  247. break;
  248. default:
  249. return;
  250. }
  251. $list[$f] = $file;
  252. }
  253. protected function findTemplates()
  254. {
  255. $this->tpl = array_merge(
  256. $this->getFilesInDir($this->tplset_theme),
  257. $this->getFilesInDir($this->parent_theme.'/tpl')
  258. );
  259. $this->tpl_model = $this->tpl;
  260. $this->tpl = array_merge($this->tpl,$this->getFilesInDir($this->user_theme.'/tpl'));
  261. # Then we look in 'default-templates' plugins directory
  262. $plugins = $this->core->plugins->getModules();
  263. foreach ($plugins as $p) {
  264. // Looking in default-templates directory
  265. $this->tpl = array_merge($this->getFilesInDir($p['root'].'/default-templates'),$this->tpl);
  266. $this->tpl_model = array_merge($this->getFilesInDir($p['root'].'/default-templates'),$this->tpl_model);
  267. // Looking in default-templates/tplset directory
  268. $this->tpl = array_merge($this->getFilesInDir($p['root'].'/default-templates/'.$this->tplset_name),$this->tpl);
  269. $this->tpl_model = array_merge($this->getFilesInDir($p['root'].'/default-templates/'.$this->tplset_name),$this->tpl_model);
  270. }
  271. uksort($this->tpl,array($this,'sortFilesHelper'));
  272. }
  273. protected function findStyles()
  274. {
  275. $this->css = $this->getFilesInDir($this->user_theme,'css');
  276. $this->css= array_merge($this->css,$this->getFilesInDir($this->user_theme.'/style','css','style/'));
  277. $this->css= array_merge($this->css,$this->getFilesInDir($this->user_theme.'/css','css','css/'));
  278. }
  279. protected function findScripts()
  280. {
  281. $this->js = $this->getFilesInDir($this->user_theme,'js');
  282. $this->js = array_merge($this->js,$this->getFilesInDir($this->user_theme.'/js','js','js/'));
  283. }
  284. protected function findLocales()
  285. {
  286. $langs = l10n::getISOcodes(1,1);
  287. foreach ($langs as $k => $v) {
  288. if ($this->parent_theme) {
  289. $this->po = array_merge($this->po,$this->getFilesInDir($this->parent_theme.'/locales/'.$v,'po',$v.'/'));
  290. }
  291. $this->po = array_merge($this->po,$this->getFilesInDir($this->user_theme.'/locales/'.$v,'po',$v.'/'));
  292. }
  293. }
  294. protected function getFilesInDir($dir,$ext=null,$prefix='',$model=null)
  295. {
  296. $dir = path::real($dir);
  297. if (!$dir || !is_dir($dir) || !is_readable($dir)) {
  298. return array();
  299. }
  300. $d = dir($dir);
  301. $res = array();
  302. while (($f = $d->read()) !== false)
  303. {
  304. if (is_file($dir.'/'.$f) && !preg_match('/^\./',$f) && (!$ext || preg_match('/\.'.preg_quote($ext).'$/i',$f))) {
  305. if (!$model || preg_match('/^'.preg_quote($model).'$/i', $f)) {
  306. $res[$prefix.$f] = $dir.'/'.$f;
  307. }
  308. }
  309. }
  310. return $res;
  311. }
  312. protected function sortFilesHelper($a,$b)
  313. {
  314. if ($a == $b) {
  315. return 0;
  316. }
  317. $ext_a = files::getExtension($a);
  318. $ext_b = files::getExtension($b);
  319. return strcmp($ext_a.'.'.$a,$ext_b.'.'.$b);
  320. }
  321. }