PageRenderTime 63ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/phocoa/framework/WFSkin.php

https://github.com/SwissalpS/phocoa
PHP | 789 lines | 302 code | 64 blank | 423 comment | 33 complexity | d76cb6e568b89686ff2a6a8a56d4e4ef MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. /**
  4. * Skin System.
  5. *
  6. * A collection of classes and infrastructure for supporting skins of any layout, with multiple "themes" per skin.
  7. *
  8. * The system ships with a simple skin, "default", which is a simple wrapper. You can create your own skins.
  9. *
  10. * @package framework-base
  11. * @subpackage Skin
  12. * @copyright Alan Pinstein 2005
  13. * @author Alan Pinstein <apinstein@mac.com>
  14. * @version $Id: skin.php,v 1.37 2005/03/23 20:31:01 alanpinstein Exp $
  15. */
  16. /**
  17. * Skin Manifest abstract interface. Each skin will need to have a concrete subclass to provide the system with needed information about itself.
  18. *
  19. * For a full explanation on the Skin infrastructure, including how to set up Skin Types, Skins, and Themes, see {@link WFSkin}.
  20. *
  21. * @see WFSkin
  22. *
  23. */
  24. abstract class WFSkinManifestDelegate extends WFObject
  25. {
  26. /**
  27. * Get the DEFAULT theme of for skin.
  28. *
  29. * This method is REQUIRED.
  30. *
  31. * @return string - The DEFAULT theme for this skin.
  32. */
  33. abstract function defaultTheme();
  34. /**
  35. * Get a list of themes for the skin.
  36. *
  37. * This is an optional method.
  38. *
  39. * @return array A list of all themes supported for this skin.
  40. */
  41. function themes() { return array(); }
  42. /**
  43. * Load the theme information for this skin.
  44. *
  45. * The theme information is a simple associative array of variables used by the skin. Good uses for this include
  46. * colorscheme information.
  47. *
  48. * This is an optional method.
  49. *
  50. * @param string $theme Theme information to retrieve.
  51. * @return assoc_array Various name/value pairs to be used in the templates for the skin.
  52. */
  53. function loadTheme($theme) { return array(); }
  54. }
  55. /**
  56. * Delegate interface for the skin object.
  57. *
  58. * The skin delegate provides the skin system with a way of extending the skin's capabilities. Essentially, the WFSkin object is a framework for building "themed" pages.
  59. * The parts of each skin that are provided by the skin infrastructure can be easily customized using the skin delegate system.
  60. *
  61. * The main web application mechanism always uses the skin delegate provided by {@link WFApplicationDelegate}. However, an application may have multiple skin delegates
  62. * for multiple skinned usages. For instance, maybe you have a need to send skinned email, but the skins for email have a different setup than the normal web site.
  63. * In this case, you could create a skin object and provide a specialized skin delegate to handle the skinnable email function.
  64. *
  65. * You may also find that you need more template types besides "normal" and "raw". WFSkinDelegate allows you to manifest additional templateTypes(). Each skin
  66. * you create for that WFSkinDelegate will of course need to implement all of the templateTypes() that the skinDelegate supports.
  67. */
  68. class WFSkinDelegate
  69. {
  70. /**
  71. * Retreive the "named" content from the skin delegate.
  72. *
  73. * The "named content" mechanism is the way by which individual applications using this framework can add additional content sections
  74. * for use in their skins. By default, only a HEAD and BODY section exist within the skin.
  75. * Individual applications can use the named content mechanism to supply skin-specific information such as NAVIGATION LINKS, COPYRIGHT DISCLAIMERS, etc.
  76. *
  77. * @param string Name of the content to retrieve.
  78. * @param assoc_array Optional parameter list. Name/value pairs to pass on to content generator.
  79. * @return mixed The named content as provided byt he skin delegate.
  80. */
  81. function namedContent($name, $params = NULL) {}
  82. /**
  83. * Get a list of all named content for the skin delegate.
  84. *
  85. * @return array A list of all named content items in the catalog for this skin delegate.
  86. */
  87. function namedContentList() {}
  88. /**
  89. * A delegate method to allow the delegate object to load default values for certain skin properties such as:
  90. * skin, skinTheme, metaDescription, metaKeywords, title etc.
  91. * Example:
  92. *
  93. * $skin->setSkin('exampleskin2');
  94. * $skin->setTheme('red');
  95. * $skin->setMetaDescription('This is the default description.');
  96. * $skin->addMetaKeywords(array('more', 'keywords'));
  97. * $skin->setTitle('Page Title');
  98. *
  99. * @param object WFSkin The skin object to load defaults for.
  100. */
  101. function loadDefaults($skin) {}
  102. /**
  103. * Get a list of the additional template types (besides "normal" and "raw") that are supported by this skin.
  104. *
  105. * @return array An array of strings; each is a template type that is supported by this skin.
  106. * For each skin, there must be a template_<templateType>.tpl file for each manifested template type.
  107. */
  108. function templateTypes() { return array(); }
  109. /**
  110. * Callback method which is called just before the skin is rendered.
  111. *
  112. * This allows your skin delegate to calculate anything it might need to pass on to the skin for use in rendering.
  113. *
  114. * @param object WFSkin The skin object that will be rendered.
  115. */
  116. function willRender($skin) {}
  117. }
  118. /**
  119. * Main skin class for managing skin wrappers around the content.
  120. *
  121. * The Web Application's WFRequestController object always uses exactly one skin instance to render the page.
  122. * However, your application may choose to create other skin instances to use the infrastructure for things like HTML email, etc.
  123. *
  124. * The Skin mechanism is broken down into three layers. Each layer provides the ability to swap behaviors/looks at runtime.
  125. * For each request, one of each layer must be specified.
  126. *
  127. * 1. Skin Type -- i.e., which SkinDelegate is used. The Skin Delegate provides the skin with its catalog of behaviors, i.e., menus, footers, etc.
  128. * Each skin type is unique, and skins must be written specifically for each Skin Type.
  129. * Most web sites have just one skin type, that handles the elements appropriate for the skins of that application.
  130. * However, sometimes there is a need for a single site to have multiple skins. For instance, the public site may have different
  131. * navigational needs than the back-end admin interface.
  132. * A {@link WFSkinDelegate} is implemented for each skin type an tells the system what data is available for the skin type.
  133. * Skin Types, however, do NOT provide any layout or style.
  134. * By default, each Skin Type implements only the "normal" template type. Your Skin Type may need additional layouts. For instance, printer-friendly
  135. * or minimal layouts used for popups. Your skin can support additiona template types via {@link WFSkinDelegate::templateTypes() templateTypes()}.
  136. * Every Skin for a Skin Type must have a template file for all template types to ensure proper operation.
  137. * 2. Skin -- A skin provides basic layout for a given Skin Type. Skins are specific for Skin Types, since they necessarily know about the
  138. * data types offered by a particular skin type, via its Skin Delegate.
  139. * Each Skin resides in its own directory inside the Skin Type directory that it belongs to.
  140. * Each Skin thus provides a template file that implements a layout. Skins may also have multiple Skin Themes.
  141. * Each Skin has a {@link WFSkinManifestDelegate SkinManifestDelegate} which tells the system which themes are available, and which theme to use by default.
  142. * 3. Skin Themes -- It may be desirable for a skin to have multiple colorschemes or other minor "thematic" differences. Each skin must have at least one theme.
  143. * Infrastructure is provided so that the SkinManifestDelegate can easily supply different data to the skin based on the theme. This allows easy creation
  144. * of colorschemes or other thematic differences.
  145. *
  146. * <pre>
  147. * Skin Directory Structure:
  148. *
  149. * The skins have a specified, hierarchical directory structure, based in the "skins" directory.
  150. * skins/ - Contains only directories; each directory represents a Skin Type.
  151. * skins/&lt;skinType&gt;/ - For each skin type, pick a unique name and create a directory.
  152. * skins/&lt;skinType&gt;/www/ - For each skin type, css that is shared across all skins.
  153. * skins/&lt;skinType&gt;/&lt;skinType&gt;_SkinDelegate.php - A php file containing exactly one class, named &lt;skinType&gt;_SkinDelegate, that is the {@link WFSkinDelegate} for the Skin Type.
  154. * skins/&lt;skinType&gt;/&lt;skinName&gt;/ - Also in the skinType directory are other directories, one for each skin that can be used for the Skin Type.
  155. * skins/&lt;skinType&gt;/&lt;skinName&gt;/&lt;skinName&gt;_SkinManifestDelegate.php - The {@link WFSkinManifestDelegate} for the skin &lt;skinName&gt;.
  156. * skins/&lt;skinType&gt;/&lt;skinName&gt;/* - Other files in here are the various tpl and css files used for this skin.
  157. * skins/&lt;skinType&gt;/&lt;skinName&gt;/www/ - Web root of the skin. Nothing actually goes in this folder but other folders.
  158. * skins/&lt;skinType&gt;/&lt;skinName&gt;/www/shared/* - Files that need to be accesible to the WWW and are shared by multiple themes of this skin go here.
  159. * skins/&lt;skinType&gt;/&lt;skinName&gt;/www/&lt;themeName&gt;/* - Files that need to be accessible to the WWW and are specific to a theme go here. Each theme has its own folder to contain "themed" versions of resources. Typically every theme has the same set of resources, but of course customized for that theme.
  160. *
  161. * To use WWW visible items in your pages, simply use {$skinDir}/myImage.jpg and {$skinDirShared}/mySharedImage.jpg in your templates. The skin system automatically assigns these vars.
  162. * skinDir maps to skins/&lt;skinType&gt;/&lt;skinName&gt;/www/&lt;themeName&gt;/
  163. * skinDirShared maps to skins/&lt;skinType&gt;/&lt;skinName&gt;/www/shared/
  164. * </pre>
  165. *
  166. * @see WFSkinDelegate, WFSkinManifestDelegate
  167. */
  168. class WFSkin extends WFObject
  169. {
  170. /**
  171. * The "normal" templateType: template_normal.tpl
  172. */
  173. const SKIN_WRAPPER_TYPE_NORMAL = 'normal';
  174. /**
  175. * The "raw" templateType: the exact page contents will be displayed; equivalent to using no skin.
  176. */
  177. const SKIN_WRAPPER_TYPE_RAW = 'raw';
  178. /**
  179. * @var string The skin delegate name to use for this instance.
  180. */
  181. protected $delegateName;
  182. /**
  183. * @var string The skin to use for this instance.
  184. */
  185. protected $skinName;
  186. /**
  187. * @var string The theme of the skin to use.
  188. */
  189. protected $skinThemeName;
  190. /**
  191. * @var object The {@link WFSkinDelegate delegate object} for this skin.
  192. */
  193. protected $delegate;
  194. /**
  195. * @var object The SkinManifestDelegate for the current skin.
  196. */
  197. protected $skinManifestDelegate;
  198. /**
  199. * @var string The body content for the skin. This is the only "predefined" content element of the skin infrastructure.
  200. */
  201. protected $body;
  202. /**
  203. * @var string The TITLE of the skin. This will be used automatically as the HTML title.
  204. */
  205. protected $title;
  206. /**
  207. * @var array A list of META KEYWORDS for HTML skins.
  208. */
  209. protected $metaKeywords;
  210. /**
  211. * @var string The META DESCRIPTION for HTML skins.
  212. */
  213. protected $metaDescription;
  214. /**
  215. * @var integer Skin wrapper type. One of {@link WFSkin::SKIN_WRAPPER_TYPE_NORMAL}, {@link WFSkin::SKIN_WRAPPER_TYPE_RAW}, or a custom type.
  216. */
  217. protected $templateType;
  218. /**
  219. * @var string The absolute filesystem path to a tpl file that is automatically added to the "head" element of all skins of this skin type.
  220. */
  221. protected $headTemplate;
  222. /**
  223. * @var array An array of strings of things that needed to be added to the <head> section.
  224. */
  225. protected $headStrings;
  226. /**
  227. * @var arrary An associative array of "named" content chunks.
  228. */
  229. protected $namedContent;
  230. /**
  231. * @var string The character set used for encoding strings.
  232. */
  233. protected $charset;
  234. function __construct()
  235. {
  236. // determine which skin to use
  237. $wa = WFWebApplication::sharedWebApplication();
  238. $this->skinName = 'default';
  239. $this->delegate = NULL;
  240. $this->skinManifestDelegate = NULL;
  241. $this->body = NULL;
  242. $this->templateType = WFSkin::SKIN_WRAPPER_TYPE_NORMAL;
  243. $this->namedContent = array();
  244. $this->title = NULL;
  245. $this->metaKeywords = array();
  246. $this->metaDescription = NULL;
  247. $this->headStrings = array();
  248. $this->headTemplate = WFWebApplication::appDirPath(WFWebApplication::DIR_SMARTY) . '/head.tpl';
  249. $this->charset = 'UTF-8';
  250. }
  251. /**
  252. * Set the which template file of the current skin will be used to render the skin.
  253. *
  254. * - (default) {@link WFSkin::SKIN_WRAPPER_TYPE_NORMAL}, which maps to "template.tpl".
  255. * - {@link WFSkin::SKIN_WRAPPER_TYPE_RAW}, which will output the body contents only. This is logically equivalent to using no skin.
  256. * - Any other string you pass will use the file "template_<template_type>.tpl in the skin directory.
  257. *
  258. * Potential uses for this include:
  259. *
  260. * - Using {@link WFSkin::SKIN_WRAPPER_TYPE_RAW} to return HTML snippets that will be used in AJAX callback
  261. * - Using a custom "minimal" file that is used for popup windows where there is not enough real estate for the full skin.
  262. * - Using a custom "mobile" file that would be used for mobile devices.
  263. *
  264. * Any custom templates must be manifested by the skin delegate {@link WFSkinDelegate::tempateTypes() templateTypes()} method.
  265. *
  266. * @param string The name of the template to use. One of {@link WFSkin::SKIN_WRAPPER_TYPE_NORMAL}, {@link WFSkin::SKIN_WRAPPER_TYPE_RAW}, or a custom string.
  267. * @throws object WFException if the template of the given name does not exist for this skin
  268. */
  269. function setTemplateType($templateType)
  270. {
  271. $allowedTemplates = $this->templateTypes();
  272. if (!in_array($templateType, $allowedTemplates)) throw( new WFException("Template type: '{$templateType}' does not exist for skin '" . $this->skinName() . "'.") );
  273. $this->templateType = $templateType;
  274. }
  275. /**
  276. * Get a list of all template types available for this skin.
  277. *
  278. * This list will include WFSkin::SKIN_WRAPPER_TYPE_NORMAL, WFSkin::SKIN_WRAPPER_TYPE_RAW, and any custom template types manifested by the skin type delegate (skin manifest delegate).
  279. *
  280. * @return array An array of strings with the names of all valid template types.
  281. */
  282. function templateTypes()
  283. {
  284. $allowedTemplates = array(WFSkin::SKIN_WRAPPER_TYPE_NORMAL, WFSkin::SKIN_WRAPPER_TYPE_RAW);
  285. // call skin type delegate to get list of template types -- delegate implements application-specific logic.
  286. if (is_object($this->delegate) && method_exists($this->delegate, 'templateTypes')) {
  287. $allowedTemplates = array_merge($allowedTemplates, $this->delegate->templateTypes());
  288. }
  289. return $allowedTemplates;
  290. }
  291. /**
  292. * Set the skin's delegate by passing the NAME of the skin delegate.
  293. *
  294. * This function will look for the skin delegate in the appropriate place, instantiate it, and set it up for this skin instance.
  295. *
  296. * NOTE: Calling this function may overwrite any existing skin settings, since the loadDefaults() function may overwrite title, meta tags, etc.
  297. * For best results, always call setDelegateName() BEFORE making adjustments to the WFSkin object.
  298. *
  299. * @param string The NAME of the Skin Type.
  300. * @throws object Exception if the skin delegate does not exist, or it does not contain the skin delegate class.
  301. */
  302. function setDelegateName($skinDelegateName)
  303. {
  304. $this->delegateName = $skinDelegateName;
  305. // change name to our convention
  306. $skinDelegateFileClassName = $skinDelegateName . '_SkinDelegate';
  307. // load skin class -- in lieu of require_once, do this
  308. if (!class_exists($skinDelegateFileClassName))
  309. {
  310. $skinsDir = WFWebApplication::appDirPath(WFWebApplication::DIR_SKINS);
  311. $skinDelegatePath = $skinsDir . '/' . $skinDelegateName . '/' . $skinDelegateFileClassName . '.php';
  312. if (!file_exists($skinDelegatePath)) throw( new Exception("Skin Delegate {$skinDelegateName} file {$skinDelegatePath} does not exist.") );
  313. require($skinDelegatePath);
  314. }
  315. if (!class_exists($skinDelegateFileClassName)) throw( new Exception("Skin Delegate class {$skinDelegateFileClassName} does not exist.") );
  316. $this->setDelegate(new $skinDelegateFileClassName());
  317. }
  318. /**
  319. * Get the name of the Skin Type for the current instance.
  320. *
  321. * @return string The name of the current skin type.
  322. */
  323. function delegateName()
  324. {
  325. return $this->delegateName;
  326. }
  327. /**
  328. * Get the delegate instance.
  329. *
  330. * @return object WFSkinDelegate A WFSkinDelegate instance.
  331. */
  332. function delegate()
  333. {
  334. return $this->delegate;
  335. }
  336. /**
  337. * Assign a skin delegate for this instance.
  338. * @param object The skin delegate.
  339. */
  340. function setDelegate($skinDelegate)
  341. {
  342. $this->delegate = $skinDelegate;
  343. $this->loadDefaults();
  344. }
  345. /**
  346. * Set the skin to the given name. Will automatically load the skin and its default theme.
  347. * @param string The name of the skin to use.
  348. */
  349. function setSkin($skinName)
  350. {
  351. $this->skinName = $skinName;
  352. $this->loadSkin();
  353. }
  354. /**
  355. * Set the theme to use.
  356. *
  357. * @param string The name of the theme of the skin to use.
  358. */
  359. function setTheme($skinThemeName)
  360. {
  361. $this->skinThemeName = $skinThemeName;
  362. }
  363. function getskinThemeName()
  364. {
  365. return $this->skinThemeName;
  366. }
  367. /**
  368. * Get the current skin name
  369. *
  370. * @return string The name of the current skin.
  371. */
  372. function skinName()
  373. {
  374. return $this->skinName;
  375. }
  376. /**
  377. * Load the current skin.
  378. * @internal
  379. */
  380. function loadSkin()
  381. {
  382. // load the current skin
  383. $skinsDir = WFWebApplication::appDirPath(WFWebApplication::DIR_SKINS);
  384. $skinManifestDelegateFileClassName = $this->skinName . '_SkinManifestDelegate';
  385. // in lieu of require_once
  386. if (!class_exists($skinManifestDelegateFileClassName))
  387. {
  388. $skinManifestDelegatePath = $skinsDir . '/' . $this->delegateName . '/' . $this->skinName . '/' . $skinManifestDelegateFileClassName . '.php';
  389. if (!file_exists($skinManifestDelegatePath)) throw( new Exception("Skin manifest delegate file does not exist: $skinManifestDelegatePath.") );
  390. require($skinManifestDelegatePath);
  391. }
  392. // instantiate the skin manifest delegate
  393. if (!class_exists($skinManifestDelegateFileClassName)) throw( new Exception("Skin manifest delegate class does not exist: {$skinManifestDelegateFileClassName}."));
  394. $this->skinManifestDelegate = new $skinManifestDelegateFileClassName();
  395. // make sure a theme is selected
  396. if (empty($this->skinThemeName)) $this->skinThemeName = $this->skinManifestDelegate->defaultTheme();
  397. }
  398. /**
  399. * Add a string that needs to go in the page's head section.
  400. *
  401. * @param string The string to go in the head section.
  402. */
  403. function addHeadString($string)
  404. {
  405. // de-duplicate
  406. $this->headStrings[$string] = $string;
  407. }
  408. /**
  409. * Set the content for the skin to wrap. Typically this is HTML but could be anything.
  410. * @param string The content of the skin.
  411. */
  412. function setBody($html)
  413. {
  414. $this->body = $html;
  415. }
  416. /**
  417. * Set the title of the page. This is the HTML title if you are building an HTML skin.
  418. * @param string The title of the page.
  419. */
  420. function setTitle($title)
  421. {
  422. $this->title = htmlentities($title, ENT_COMPAT, $this->charset);
  423. }
  424. /**
  425. * Set the template file to be added to the "head" element of every page. Defaults to the built-in template file that sets up various PHOCOA things.
  426. *
  427. * If you want to include the default head content, use {$skinPhocoaHeadTpl} in your custom head template file.
  428. *
  429. * Typically this function would be called from your SkinDelegate's loadDefaults() function.
  430. *
  431. * @param string Absolute path to new head template file.
  432. */
  433. function setHeadTemplate($path)
  434. {
  435. $this->headTemplate = $path;
  436. }
  437. /**
  438. * Add meta keywords to the skin.
  439. * @param array A list of keywords to add.
  440. */
  441. function addMetaKeywords($keywords)
  442. {
  443. $this->metaKeywords = array_merge($keywords, $this->metaKeywords);
  444. }
  445. /**
  446. * Set the META DESCRIPTION of the page.
  447. * @param string The description of the page.
  448. */
  449. function setMetaDescription($description)
  450. {
  451. $this->metaDescription = $description;
  452. }
  453. /**
  454. * @deprecated
  455. * @see getSkinThemeAssetsDir()
  456. */
  457. function getSkinDir()
  458. {
  459. return $this->getSkinThemeAssetsDir();
  460. }
  461. /**
  462. * @deprecated
  463. * @see getSkinSharedAssetsDir
  464. */
  465. function getSkinDirShared()
  466. {
  467. return $this->getSkinSharedAssetsDir();
  468. }
  469. /**
  470. * @return string www-accessible path to the skin type assets dir (<skintype>/www)
  471. */
  472. function getSkinTypeAssetsDir()
  473. {
  474. return WWW_ROOT . '/skins/' . $this->delegateName . '/www';
  475. }
  476. /**
  477. * @return string www-accessible path to the skin shared assets dir (<skintype>/<skin>/www/<shared>)
  478. */
  479. function getSkinSharedAssetsDir()
  480. {
  481. return WWW_ROOT . '/skins/' . $this->delegateName . '/' . $this->skinName . '/shared';
  482. }
  483. /**
  484. * @return string www-accessible path to the skin theme assets dir (<skintype>/<skin>/www/<theme>)
  485. */
  486. function getSkinThemeAssetsDir()
  487. {
  488. return WWW_ROOT . '/skins/' . $this->delegateName . '/' . $this->skinName . '/' . $this->skinThemeName;
  489. }
  490. /**
  491. * @return string filesystem-accessible path to the skin directory. This is useful as a base dir for factoring out tpl code that's shared among different templateTypes.
  492. */
  493. function getSkinTemplatesDir()
  494. {
  495. return "{$this->getSkinTypeDir()}/{$this->skinName}";
  496. }
  497. /**
  498. * @return string filesystem-accessible path to the skin type directory. This is useful for shared components *across* skins.
  499. */
  500. function getSkinTypeDir()
  501. {
  502. return WFWebApplication::appDirPath(WFWebApplication::DIR_SKINS) . '/' . $this->delegateName;
  503. }
  504. /**
  505. * Set the charset string;
  506. *
  507. *
  508. * @param charaset The character set string.
  509. * @return object WFSkin (fluent interface).
  510. */
  511. function setCharset($charset)
  512. {
  513. $this->charset = $charset;
  514. return $this;
  515. }
  516. /**
  517. * Render the skin.
  518. * @param boolean TRUE to display the results to the output buffer, FALSE to return them in a variable. DEFAULT: TRUE.
  519. * @return string The rendered view. NULL if displaying.
  520. * @todo convert the DIR_SMARTY calls to use a new WFWebApplication::getResource($path) infrastructure that will allow for userland overloads of these templates
  521. */
  522. function render($display = true)
  523. {
  524. $this->loadSkin();
  525. $skinTemplatesDir = $this->getSkinTemplatesDir();
  526. $smarty = new WFSmarty();
  527. $smarty->assign('skin', $this);
  528. // add variables to smarty
  529. $themeVars = $this->skinManifestDelegate->loadTheme($this->skinThemeName);
  530. $smarty->assign('skinThemeVars', $themeVars);
  531. $smarty->assign('skinTitle', $this->title);
  532. $smarty->assign('skinMetaKeywords', join(',', $this->metaKeywords));
  533. $smarty->assign('skinMetaDescription', $this->metaDescription);
  534. $smarty->assign('skinCharset', $this->charset);
  535. $smarty->assign('skinBody', $this->body);
  536. $smarty->assign('skinHeadStrings', join("\n", array_values($this->headStrings)));
  537. $smarty->assign('phocoaDebug', WFWebApplication::sharedWebApplication()->debug());
  538. // set up shared directory URLs
  539. // deprecated
  540. $smarty->assign('skinDir', $this->getSkinDir() );
  541. $smarty->assign('skinDirShared', $this->getSkinDirShared() );
  542. // new names
  543. $smarty->assign('skinTypeAssetsDir', $this->getSkinTypeAssetsDir() );
  544. $smarty->assign('skinSharedAssetsDir', $this->getSkinSharedAssetsDir() );
  545. $smarty->assign('skinThemeAssetsDir', $this->getSkinThemeAssetsDir() );
  546. // FS paths of things
  547. $smarty->assign('skinTemplatesDir', $skinTemplatesDir);
  548. $smarty->assign('skinTypeDir', $this->getSkinTypeDir());
  549. // build the <head> section
  550. $smarty->assign('skinPhocoaHeadTpl', WFWebApplication::appDirPath(WFWebApplication::DIR_SMARTY) . '/head.tpl');
  551. $smarty->assign('skinHead', $smarty->fetch($this->headTemplate));
  552. // set the template
  553. if ($this->templateType == WFSkin::SKIN_WRAPPER_TYPE_RAW)
  554. {
  555. $smarty->setTemplate(WFWebApplication::appDirPath(WFWebApplication::DIR_SMARTY) . '/template_raw.tpl');
  556. }
  557. else
  558. {
  559. $smarty->setTemplate($skinTemplatesDir . '/template_' . $this->templateType . '.tpl');
  560. }
  561. // pre-render callback
  562. $this->willRender();
  563. // render smarty
  564. if ($display) {
  565. $smarty->render();
  566. } else {
  567. return $smarty->render(false);
  568. }
  569. }
  570. /**
  571. * Get a list of all installed skin types.
  572. * @static
  573. * @return array Skin Types are installed.
  574. */
  575. function installedSkinTypes()
  576. {
  577. $skinTypes = array();
  578. $skinsDir = WFWebApplication::appDirPath(WFWebApplication::DIR_SKINS);
  579. $dh = opendir($skinsDir);
  580. if ($dh) {
  581. while ( ($file = readdir($dh)) !== false ) {
  582. if (is_dir($skinsDir . '/' . $file) and !in_array($file, array('.','..'))) {
  583. array_push($skinTypes, $file);
  584. }
  585. }
  586. closedir($dh);
  587. }
  588. return $skinTypes;
  589. }
  590. /**
  591. * Get a list of all installed skins for the current Skin Type.
  592. *
  593. * @return array Skins that are installed.
  594. */
  595. function installedSkins()
  596. {
  597. $skins = array();
  598. $skinsDir = WFWebApplication::appDirPath(WFWebApplication::DIR_SKINS);
  599. $skinDirPath = $skinsDir . '/' . $this->delegateName;
  600. $dh = opendir($skinDirPath);
  601. if ($dh) {
  602. while ( ($file = readdir($dh)) !== false ) {
  603. if (is_dir($skinDirPath . '/' . $file) and !in_array($file, array('.','..'))) {
  604. array_push($skins, $file);
  605. }
  606. }
  607. closedir($dh);
  608. }
  609. return $skins;
  610. }
  611. /**
  612. * Allow the skin delegate to load the default values for this skin.
  613. * @see WFSkinDelegate::loadDefaults
  614. */
  615. function loadDefaults()
  616. {
  617. // call skin delegate to get skin to use -- delegate implements application-specific logic.
  618. if (is_object($this->delegate) && method_exists($this->delegate, 'loadDefaults')) {
  619. $this->delegate->loadDefaults($this);
  620. }
  621. }
  622. /**
  623. * Get the catalog (ie list) of named content for this skin.
  624. *
  625. * This is a merge of all names from the delegate and any existing content that's already been added programmatically to WFSkin.
  626. *
  627. * If the skin delegate supports additional content for the skin, the catalog of content is provided here. Mostly this is for documentation purposes.
  628. * @see WFSkinDelegate::namedContentList
  629. * @return array Array of strings; each entry is a name of a content driver for this skin delegate.
  630. */
  631. function namedContentList()
  632. {
  633. $keys = array_keys($this->namedContent);
  634. if (is_object($this->delegate) && method_exists($this->delegate, 'namedContentList')) {
  635. $keys = array_merge($keys, $this->delegate->namedContentList());
  636. }
  637. return $keys;
  638. }
  639. /**
  640. * Get the named content.
  641. *
  642. * This will use the value from the delegate *first*, and if one is not found (ie NULL is returned) then it will also
  643. * look for a value in the local namedContent list.
  644. *
  645. * @see WFSkinDelegate::namedContent
  646. * @param string The name of the content to retrieve.
  647. * @param assoc_array A list of additional parameters.
  648. * @return mixed The content for the named content for this skin instance. Provided by the delegate.
  649. */
  650. function namedContent($name, $options = NULL)
  651. {
  652. $val = NULL;
  653. if (is_object($this->delegate) && method_exists($this->delegate, 'namedContent')) {
  654. $val = $this->delegate->namedContent($name, $options);
  655. }
  656. if ($val === NULL) {
  657. if (isset($this->namedContent[$name])) {
  658. $val = $this->namedContent[$name];
  659. }
  660. }
  661. return $val;
  662. }
  663. /**
  664. * Set a value for a "namedContent" entry.
  665. *
  666. * If the namedContent is an array, the entry will be appended.
  667. *
  668. * To "set up" a namedContent as an array, the skin delegate should call {@link WFSkin::initializeNamedContentAsArray()}.
  669. *
  670. * @param mixed The "content" of the namedContent you are setting.
  671. * @param string The "name" of the namedContent you are setting.
  672. * @return object WFSkin (fluent interface).
  673. */
  674. function setContentForName($content, $name)
  675. {
  676. $curVal = $this->namedContent($name);
  677. if (is_array($curVal)) {
  678. $this->namedContent[$name][] = $content;
  679. } else {
  680. $this->namedContent[$name] = $content;
  681. }
  682. return $this;
  683. }
  684. /**
  685. * Test whether there is a value set for the namedContent passed.
  686. *
  687. * NOTE: at present this only looks *locally* in the WFSkin. It does not call through
  688. * to the delegate.
  689. *
  690. * The idea behind this is that it's much more efficient that testing namedContent('name').
  691. *
  692. * @param string The "name" of the namedContent you are inquiring about.
  693. * @return boolean
  694. * @todo add support for hasNamedContent to WFSkinDelegate.
  695. */
  696. function hasNamedContent($name)
  697. {
  698. return isset($this->namedContent[$name]);
  699. }
  700. /**
  701. * Mark a "namedContent" chunk as an array so that when used by pages the values will be concatentated rather than last-one-wins.
  702. *
  703. * @param string The "name" of the "namedContent".
  704. * @return object WFSkin (fluent interface).
  705. */
  706. function initializeNamedContentAsArray($name)
  707. {
  708. $this->namedContent[$name] = array();
  709. return $this;
  710. }
  711. /**
  712. * Pre-render callback.
  713. *
  714. * Calls the skin delegate's willRender() method if it exists.
  715. * This method is called just before the template for the skin is rendered.
  716. * @todo Do I need to pass in the WFSmarty instance here so that you can actually change the TPL file from this callback? If so, also update the willRender() delegate docs/prototype
  717. */
  718. function willRender()
  719. {
  720. if (is_object($this->delegate) && method_exists($this->delegate, 'willRender')) {
  721. $this->delegate->willRender($this);
  722. }
  723. }
  724. }
  725. ?>