1<?php
2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
3//
4// All Rights Reserved. See copyright.txt for details and a complete list of authors.
5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
6// $Id$
7
8//this script may only be included - so its better to die if called directly.
9if (strpos($_SERVER['SCRIPT_NAME'], basename(__FILE__)) !== false) {
10	header('location: index.php');
11	exit;
12}
13
14class cssLib extends TikiLib
15{
16	function list_layouts($theme = null, $theme_option = null)
17	{
18		global $prefs;
19
20		if (empty($theme) && empty($theme_option)) { // if you submit no parameters, return the current theme/theme option
21			if (isset($prefs['site_theme'])) {
22				$theme = $prefs['site_theme'];
23			}
24			if (isset($prefs['theme_option'])) {
25				$theme_option = $prefs['theme_option'];
26			}
27		}
28
29		$themelib = TikiLib::lib('theme');
30
31		$available_layouts = [];
32		foreach (scandir(TIKI_PATH . '/templates/layouts/') as $layoutName) {
33			if ($layoutName[0] != '.' && $layoutName != 'index.php') {
34				$available_layouts[$layoutName] = ucfirst($layoutName);
35			}
36		}
37		foreach (\Tiki\Package\ExtensionManager::getPaths() as $path) {
38			if (file_exists($path . '/templates/layouts/')) {
39				foreach (scandir($path . '/templates/layouts/') as $layoutName) {
40					if ($layoutName[0] != '.' && $layoutName != 'index.php') {
41						 $available_layouts[$layoutName] = ucfirst($layoutName);
42					}
43				}
44			}
45		}
46
47		$main_theme_path = $themelib->get_theme_path($theme, '', '', 'templates'); // path to the main site theme
48
49		if (file_exists(TIKI_PATH . "/" . $main_theme_path . '/layouts/')) {
50			foreach (scandir(TIKI_PATH . "/" . $main_theme_path . '/layouts/') as $layoutName) {
51				if ($layoutName[0] != '.' && $layoutName != 'index.php') {
52					$available_layouts[$layoutName] = ucfirst($layoutName);
53				}
54			}
55		}
56
57		if ($theme_option) {
58			$theme_path = $themelib->get_theme_path($theme, $theme_option, '', 'templates'); // path to the site theme options
59
60			if (file_exists(TIKI_PATH . "/" . $theme_path . '/layouts/')) {
61				foreach (scandir(TIKI_PATH . "/" . $theme_path . '/layouts/') as $layoutName) {
62					if ($layoutName[0] != '.' && $layoutName != 'index.php') {
63						$available_layouts[$layoutName] = ucfirst($layoutName);
64					}
65				}
66			}
67		}
68		return $available_layouts;
69	}
70
71	function list_user_selectable_layouts($theme = null, $theme_option = null)
72	{
73		global $prefs;
74
75		if (empty($theme) && empty($theme_option)) { // if you submit no parameters, return the current theme/theme option
76			if (isset($prefs['site_theme'])) {
77				$theme = $prefs['site_theme'];
78			}
79			if (isset($prefs['theme_option'])) {
80				$theme_option = $prefs['theme_option'];
81			}
82		}
83
84		$selectable_layouts = [];
85		$available_layouts = $this->list_layouts($theme, $theme_option);
86
87		foreach ($available_layouts as $layoutName => $layoutLabel) {
88			if ($layoutName == 'mobile'
89				|| $layoutName == 'layout_plain.tpl'
90				|| $layoutName == 'internal'
91			) {
92				// hide layouts that are for internal use only
93				continue;
94			} elseif ($layoutName == 'basic') {
95				$selectable_layouts[$layoutName] = tra('Single Container');
96			} elseif ($layoutName == 'classic') {
97				$selectable_layouts[$layoutName] = tra('Classic Tiki (3 containers - header, middle, footer)');
98			} elseif ($layoutName == 'social') {
99				$selectable_layouts[$layoutName] = tra('Classic Bootstrap (fixed top navbar)');
100			} else {
101				$selectable_layouts[$layoutName] = $layoutLabel;
102			}
103		}
104
105		return $selectable_layouts;
106	}
107
108	function list_css($path, $recursive = false)
109	{
110		$files = $this->list_files($path, '.css', $recursive);
111		foreach ($files as $i => $file) {
112			$files[$i] = preg_replace("|^$path/(.*)\.css$|", '$1', $file);
113		}
114		return $files;
115	}
116
117	function list_files($path, $extension, $recursive)
118	{
119		$back = [];
120
121		$handle = opendir($path);
122
123		while ($file = readdir($handle)) {
124			if ((substr($file, -4, 4) == $extension) and (preg_match('/^[-_a-zA-Z0-9\.]*$/', $file))) {
125				$back[] = "$path/$file";
126			} elseif ($recursive
127								&& $file != '.svn'
128								&& $file != '.'
129								&& $file != '..'
130								&& is_dir("$path/$file")
131								&& ! file_exists("db/$file/local.php")
132			) {
133				$back = array_merge($back, $this->list_files("$path/$file", $extension, $recursive));
134			}
135		}
136		closedir($handle);
137		sort($back);
138		return $back;
139	}
140
141	function browse_css($path)
142	{
143		if (! is_file($path)) {
144			return ['error' => "No such file : $path"];
145		}
146
147		$meat = implode('', file($path));
148
149		$find[0] = '/\}/';
150		$repl[0] = "\n}\n";
151
152		$find[1] = '/\{/';
153		$repl[1] = "\n{\n";
154
155		$find[2] = '/\/\*/';
156		$repl[2] = "\n/*\n";
157
158		$find[3] = '/\*\//';
159		$repl[3] = "\n*/\n";
160
161		$find[4] = '/;/';
162		$repl[4] = ";\n";
163
164		$find[5] = '/(W|w)hite/';
165		$repl[5] = '#FFFFFF';
166
167		$find[6] = '/(B|b)lack/';
168		$repl[6] = '#000000';
169
170		$res = preg_replace($find, $repl, $meat);
171		return [
172			'error' => '',
173			'content' => explode("\n", $res)
174		];
175	}
176
177	function parse_css($data)
178	{
179		$back = [];
180
181		$index = 0;
182		$type = '';
183
184		foreach ($data as $line) {
185			$line = trim($line);
186
187			if ($line) {
188				if (($type != 'comment') and ($line == '/*')) {
189					$type = 'comment';
190
191					$index++;
192					$back["$index"]['comment'] = '';
193					$back["$index"]['items'] = [];
194					$back["$index"]['attributes'] = [];
195				} elseif (($type == 'comment') and ($line == '*/')) {
196					$type = '';
197				} elseif ($type == 'comment') {
198					$back["$index"]['comment'] .= "$line\n";
199				} elseif (($type == 'items') and ($line == '{')) {
200					$type = 'attributes';
201				} elseif ($type == 'items') {
202					$li = explode(',', $line);
203
204					foreach ($li as $l) {
205						$l = trim($l);
206
207						if ($l) {
208							$back["$index"]['items'][] = $l;
209						}
210					}
211				} elseif (($type == 'attributes') and ($line == '}')) {
212					$type = '';
213
214					$index++;
215					$back["$index"]['comment'] = '';
216					$back["$index"]['items'] = [];
217					$back["$index"]['attributes'] = [];
218				} elseif ($type == 'attributes') {
219					$parts = explode(':', str_replace(';', '', $line));
220
221					if (isset($parts[0]) && isset($parts[1])) {
222						$obj = trim($parts[0]);
223
224						$back["$index"]['attributes']["$obj"] = trim($parts[1]);
225					}
226				} else {
227					$li = explode(',', $line);
228
229					foreach ($li as $l) {
230						$l = trim($l);
231
232						if ($l) {
233							$back["$index"]['items'][] = $l;
234						}
235					}
236
237					$type = 'items';
238				}
239
240				$back['content'] = $line;
241			}
242		}
243
244		return $back;
245	}
246
247	/**
248	 * Find the version of Tiki that a CSS is compatible with
249	 *
250	 * @TODO: cache the results
251	 * @TODO: only read the first 30 lines or so of the file
252	 */
253	function version_css($path)
254	{
255		if (! file_exists($path)) {
256			return false;
257		}
258
259		$data = implode('', file($path));
260		$pos = strpos($data, '@version');
261
262		if ($pos === false) {
263			return false;
264		}
265		// get version
266		preg_match("/(@[V|v]ersion):?\s?([\d]+)\.([\d]+)/i", $data, $matches);
267		$version = $matches[2] . '.' . $matches[3];
268
269		return $version;
270	}
271}
272