trunk /sally/core/lib/sly/Layout.php

Language PHP Lines 452
MD5 Hash 9ad98c2179f7a237049e433927a051de Estimated Cost $3,841 (why?)
Repository https://bitbucket.org/SallyCMS/trunk View Raw File
  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
<?php
/*
 * Copyright (c) 2012, webvariants GbR, http://www.webvariants.de
 *
 * This file is released under the terms of the MIT license. You can find the
 * complete text in the attached LICENSE file or online at:
 *
 * http://www.opensource.org/licenses/mit-license.php
 */

/**
 * Base class for layouts
 *
 * Layouts are responsible for handling and rendering the HTML head and footer.
 * This class lays out the general API for all concrete layouts (like XHTML
 * or XHTML5).
 *
 * @ingroup layout
 * @author  Zozi
 */
abstract class sly_Layout extends sly_Viewable {
	protected $title           = '';       ///< string
	protected $cssCode         = '';       ///< string
	protected $javaScriptCode  = '';       ///< string
	protected $favIcon         = null;     ///< string
	protected $cssFiles        = array();  ///< array
	protected $javaScriptFiles = array();  ///< array
	protected $feedFiles       = array();  ///< array
	protected $bodyAttrs       = array();  ///< array
	protected $httpMetas       = array();  ///< array
	protected $metas           = array();  ///< array
	protected $links           = array();  ///< array
	protected $content         = '';       ///< string
	protected $base            = '';       ///< string

	/**
	 * Open a new buffer
	 *
	 * This method is just a wrapper for ob_start().
	 */
	public function openBuffer() {
		ob_start();
	}

	/**
	 * Close the buffer
	 *
	 * This method closes the buffer and stores the output inside the content
	 * field of this instance.
	 */
	public function closeBuffer() {
		$this->content = ob_get_clean();
	}

	/**
	 * Close all buffers
	 */
	public function closeAllBuffers() {
		while (ob_get_level()) ob_end_clean();
	}

	/**
	 * Set the page content directly
	 *
	 * @param string $content
	 */
	public function setContent($content) {
		$this->content = trim($content);
	}

	/**
	 * Render the page
	 *
	 * This method starts a buffer, prints the header, content and footer and
	 * then returns the complete page's content.
	 *
	 * @return string
	 */
	public function render() {
		ob_start();
		$this->printHeader();
		print $this->content;
		$this->printFooter();
		return ob_get_clean();
	}

	/**
	 * Set the page title
	 *
	 * @param string $title  the new title
	 */
	public function setTitle($title) {
		$this->title = $title;
	}

	/**
	 * Append something to the title
	 *
	 * @param string $title  the string to append to the current title
	 */
	public function appendToTitle($title) {
		$this->title .= $title;
	}

	/**
	 * Set the fav icon
	 *
	 * @param string $iconPath  the full URI to the favicon
	 */
	public function setFavIcon($iconPath) {
		$this->favIcon = trim($iconPath);
	}

	/**
	 * Set the base URI
	 *
	 * @param string $base  the base URI
	 */
	public function setBase($base) {
		$this->base = trim($base);
	}

	/**
	 * Add inline CSS to the page
	 *
	 * Use this method if you have to generate dynamic CSS and add it directly to
	 * the page, using a <style> tag. All added inline CSS will be printed in a
	 * single <style> tag.
	 *
	 * @param string $css  the inline CSS code
	 */
	public function addCSS($css) {
		$css = trim($css);
		$this->cssCode .= "\n$css";
	}

	/**
	 * Add CSS file
	 *
	 * This method adds a new CSS file to the layout. Files will be put into
	 * groups, so that addOns can partially access them. Files must be unique
	 * (or else the method returns false).
	 *
	 * @param  string $cssFile  path to css file
	 * @param  string $media    media attribute f?r den CSS link
	 * @param  string $group    group files by this param
	 * @return boolean          true if the file was added, false if it already existed
	 */
	public function addCSSFile($cssFile, $media = 'all', $group = 'default') {
		$cssFile = trim($cssFile);

		foreach ($this->cssFiles as $files) {
			foreach ($files as $list) {
				foreach ($list as $file) {
					if ($file['src'] == $cssFile) return false;
				}
			}
		}

		$this->cssFiles[trim($group)][trim($media)][] = array('src' => $cssFile);
		return true;
	}

	/**
	 * Add inline JavaScript to the page
	 *
	 * Use this method if you have to generate dynamic JS and add it directly to
	 * the page, using a <script> tag. All added inline JS will be printed in a
	 * single <script> tag.
	 *
	 * @param string $javascript  the inline JavaScript code
	 */
	public function addJavaScript($javascript) {
		$javascript = trim($javascript);
		$this->javaScriptCode .= "\n$javascript";
	}

	/**
	 * Add JavaScript file
	 *
	 * This method adds a new JS file to the layout. Files will be put into
	 * groups, so that addOns can partially access them. Files must be unique
	 * (or else the method returns false).
	 *
	 * @param  string $cssFile  path to js file
	 * @param  string $group    group files by this param
	 * @return boolean          true if the file was added, false if it already existed
	 */
	public function addJavaScriptFile($javascriptFile, $group = 'default') {
		$javascriptFile = trim($javascriptFile);

		foreach ($this->javaScriptFiles as $files) {
			if (in_array($javascriptFile, $files)) return false;
		}

		$this->javaScriptFiles[trim($group)][] = $javascriptFile;
		return true;
	}

	/**
	 * Add an attribute to the body tag
	 *
	 * Attributes beginning with 'on' will not be added to the tag, but rather
	 * as JavaScript event handler using inline JavaScript.
	 *
	 * @param string $name   attribute name
	 * @param string $value  attribute value
	 */
	public function setBodyAttr($name, $value) {
		$name  = trim($name);
		$value = trim($value);

		if (sly_Util_String::startsWith($name, 'on')) {
			$this->addJavaScript('window.'.$name.' = function() { '.$value.' }');
		}
		else {
			$this->bodyAttrs[$name] = $value;
		}
	}

	/**
	 * Get body attribute(s)
	 *
	 * @param  string $name  the attribute name or null for 'all'
	 * @return mixed         either an array or a string
	 */
	public function getBodyAttr($name = null) {
		return ($name && isset($this->bodyAttrs[$name])) ? $this->bodyAttrs[$name] : $this->bodyAttrs;
	}

	/**
	 * Appends a class name to the body
	 *
	 * @param string $class  a single or multiple classes as a string (like 'foo bar')
	 */
	public function appendBodyClass($class) {
		$classes = $this->getBodyAttr('class');
		$classes = $classes ? explode(' ', $classes) : array();

		foreach (explode(' ', $class) as $cl) {
			$classes[] = $cl;
		}

		$this->setBodyAttr('class', implode(' ', array_unique($classes)));
	}

	/**
	 * Add meta tag
	 *
	 * Adds a regular meta tag to the page header.
	 *
	 * @param string $name     meta name
	 * @param string $content  content attribute of the tag
	 */
	public function addMeta($name, $content) {
		$this->metas[trim($name)] = trim($content);
	}

	/**
	 * Add a http-equiv meta tag
	 *
	 * Adds a meta tag for HTTP equivalents to the page header. Use this to
	 * specify the content-type.
	 *
	 * @param string $name     meta name
	 * @param string $content  content attribute of the tag
	 */
	public function addHttpMeta($name, $content) {
		$this->httpMetas[trim($name)] = trim($content);
	}

	/**
	 * Add generic link
	 *
	 * This methods adds a generic <link> tag to the head. Use specialized
	 * methods (like addCSSFile) whenever possible. Note that the links are not
	 * made unique!
	 *
	 * @param string $rel    rel attribute value
	 * @param string $href   href attribute value
	 * @param string $type   type attribute value
	 * @param string $title  title attribute value
	 */
	public function addLink($rel, $href, $type = '', $title= '') {
		$this->links[] = array('rel' => trim($rel), 'href' => trim($href), 'type' => trim($type), 'title' => trim($title));
	}

	/**
	 * Add a feed
	 *
	 * This method is a specialized version of addLink() and adds a RSS/Atom link
	 * to the page header, automatically setting the title and type.
	 *
	 * @param string $feedFile  the URL to the feed
	 * @param string $type      the type (rss, rss1, rss2 or atom)
	 */
	public function addFeedFile($feedFile, $type = '') {
		if (!in_array($type, array('rss', 'rss1', 'rss2', 'atom'))) {
			$type = 'rss';
		}

		static $types  = array('rss' => 'rss', 'rss1' => 'rss', 'rss2' => 'rss', 'atom' => 'atom');
		static $titles = array('rss' => 'RSS-Feed', 'rss1' => 'RSS-Feed 1.0', 'rss2' => 'RSS-Feed 2.0', 'atom' => 'Atom-Feed');

		$title = $titles[$type];
		$type  = 'application/'.$types[$type].'+xml';

		$this->addLink('alternate', $feedFile, $type, $title);
	}

	/**
	 * Write the inline CSS
	 *
	 * This method will filter the inline CSS with the event HEADER_CSS and, if
	 * it's not empty, writes it by calling the layout specific
	 * printCSSConcrete() method.
	 */
	protected function printCSS() {
		$this->cssCode = sly_Core::dispatcher()->filter('HEADER_CSS', $this->cssCode);
		if (!empty($this->cssCode)) $this->printCSSConcrete();
	}

	/**
	 * Write the CSS files
	 *
	 * This method will filter the CSS files with the event HEADER_CSS_FILES and,
	 * if they're not empty, write them by calling the layout specific
	 * printCSSFilesConcrete() method.
	 */
	protected function printCSSFiles() {
		$this->cssFiles = sly_Core::dispatcher()->filter('HEADER_CSS_FILES', $this->cssFiles);
		$this->printCSSFilesConcrete();
	}

	/**
	 * Write the inline JavaScript
	 *
	 * This method will filter the inline JavaScript with the event
	 * HEADER_JAVASCRIPT and, if it's not empty, writes it by calling the layout
	 * specific printJavaScriptConcrete() method.
	 */
	protected function printJavaScript() {
		$this->javaScriptCode = sly_Core::dispatcher()->filter('HEADER_JAVASCRIPT', $this->javaScriptCode);
		if (!empty($this->javaScriptCode)) $this->printJavaScriptConcrete();
	}

	/**
	 * Write the JavaScript files
	 *
	 * This method will filter the JS files with the event
	 * HEADER_JAVASCRIPT_FILES and, if they're not empty, write them by calling
	 * the layout specific printJavaScriptFilesConcrete() method.
	 */
	protected function printJavaScriptFiles() {
		$this->javaScriptFiles = sly_Core::dispatcher()->filter('HEADER_JAVASCRIPT_FILES', $this->javaScriptFiles);
		$this->printJavaScriptFilesConcrete();
	}

	/**
	 * Print all links
	 *
	 * This function only loops over all links and calls printLink() for each
	 * one.
	 */
	protected function printLinks() {
		foreach ($this->links as $link) {
			$this->printLink($link);
		}
	}

	/**
	 * Print the inline CSS code
	 */
	abstract protected function printCSSConcrete();

	/**
	 * Print the list of CSS files
	 */
	abstract protected function printCSSFilesConcrete();

	/**
	 * Print the inline JavaScript code
	 */
	abstract protected function printJavaScriptConcrete();

	/**
	 * Print the list of JS files
	 */
	abstract protected function printJavaScriptFilesConcrete();

	/**
	 * Print the body attributes
	 */
	abstract protected function printBodyAttrs();

	/**
	 * Print regular meta tag
	 */
	abstract protected function printMetas();

	/**
	 * Print HTTP meta tag
	 */
	abstract protected function printHttpMetas();

	/**
	 * Prints a <link> tag
	 *
	 * @param array $attributes  a hash with all attributes (name => value)
	 */
	abstract protected function printLink($attributes);

	/**
	 * Print the header
	 *
	 * Starts the page by writing the html, head, title and body tag (no meta,
	 * no doctype, no links, no script, ...). Most layouts will override this
	 * method.
 	 */
	public function printHeader() {
		print '<html><head><title>'.sly_html(trim($this->title)).'</title></head><body>';
	}

	/**
	 * Print the footer
	 *
	 * Prints the closing body and html tags.
	 */
	public function printFooter() {
		$this->printJavaScriptFiles();
		$this->printJavaScript();
		print '</body></html>';
	}

	/**
	 * Get the full path for a view
	 *
	 * This methods prepends the filename of a specific view with its path. If
	 * the view is not found inside the core, an exception is thrown.
	 *
	 * @throws sly_Exception  if the view could not be found
	 * @param  string $file   the relative filename
	 * @return string         the full path to the view file
	 */
	protected function getViewFile($file) {
		$full = SLY_COREFOLDER.'/views/'.$file;
		if (file_exists($full)) return $full;

		throw new sly_Exceptiont(t('view_not_found', $file));
	}
}
Back to Top