4 * Maintain a set of markup/templates to inject inside various regions
6 class CRM_Core_Region
{
7 static private $_instances = NULL;
10 * Obtain the content for a given region
13 * @param bool $autocreate whether to automatically create an empty region
14 * @return CRM_Core_Region
16 static function &instance($name, $autocreate = TRUE) {
17 if ( $autocreate && ! isset( self
::$_instances[$name] ) ) {
18 self
::$_instances[$name] = new CRM_Core_Region($name);
20 return self
::$_instances[$name];
24 * Symbolic name of this region
31 * List of snippets to inject within region
33 * @var array; e.g. $this->_snippets[3]['type'] = 'template';
38 * Whether the snippets array has been sorted
44 public function __construct($name) {
45 // Templates injected into regions should normally be file names, but sometimes inline notation is handy.
46 require_once 'CRM/Core/Smarty/resources/String.php';
47 civicrm_smarty_register_string_resource( );
50 $this->_snippets
= array();
52 // Placeholder which represents any of the default content generated by the main Smarty template
59 $this->_isSorted
= TRUE;
63 * Add a snippet of content to a region
66 * CRM_Core_Region::instance('page-header')->add(array(
67 * 'markup' => '<div style="color:red">Hello!</div>',
69 * CRM_Core_Region::instance('page-header')->add(array(
70 * 'script' => 'alert("Hello");',
72 * CRM_Core_Region::instance('page-header')->add(array(
73 * 'template' => 'CRM/Myextension/Extra.tpl',
75 * CRM_Core_Region::instance('page-header')->add(array(
76 * 'callback' => 'myextension_callback_function',
80 * Note: This function does not perform any extra encoding of markup, script code, or etc. If
81 * you're passing in user-data, you must clean it yourself.
83 * @param $snippet array; keys:
84 * - type: string (auto-detected for markup, template, callback, script, scriptUrl, jquery, style, styleUrl)
85 * - name: string, optional
86 * - weight: int, optional; default=1
87 * - disabled: int, optional; default=0
88 * - markup: string, HTML; required (for type==markup)
89 * - template: string, path; required (for type==template)
90 * - callback: mixed; required (for type==callback)
91 * - arguments: array, optional (for type==callback)
92 * - script: string, Javascript code
93 * - scriptUrl: string, URL of a Javascript file
94 * - jquery: string, Javascript code which runs inside a jQuery(function($){...}); block
95 * - style: string, CSS code
96 * - styleUrl: string, URL of a CSS file
98 public function add($snippet) {
99 static $types = array('markup', 'template', 'callback', 'scriptUrl', 'script', 'jquery', 'style', 'styleUrl');
101 'region' => $this->_name
,
105 $snippet +
= $defaults;
106 if (!isset($snippet['type'])) {
107 foreach ($types as $type) {
109 if (isset($snippet[$type])) {
110 $snippet['type'] = $type;
115 if (!isset($snippet['name'])) {
116 $snippet['name'] = count($this->_snippets
);
118 $this->_snippets
[ $snippet['name'] ] = $snippet;
119 $this->_isSorted
= FALSE;
123 public function update($name, $snippet) {
124 $this->_snippets
[$name] = array_merge($this->_snippets
[$name], $snippet);
125 $this->_isSorted
= FALSE;
128 public function &get($name) {
129 return @$this->_snippets
[$name];
133 * Render all the snippets in a region
135 * @param string $default HTML, the initial content of the region
136 * @param bool $allowCmsOverride allow CMS to override rendering of region
137 * @return string, HTML
139 public function render($default, $allowCmsOverride = TRUE) {
140 // $default is just another part of the region
141 if (is_array($this->_snippets
['default'])) {
142 $this->_snippets
['default']['markup'] = $default;
144 // We hand as much of the work off to the CMS as possible
145 $cms = CRM_Core_Config
::singleton()->userSystem
;
147 if (!$this->_isSorted
) {
148 uasort($this->_snippets
, array('CRM_Core_Region', '_cmpSnippet'));
149 $this->_isSorted
= TRUE;
152 $smarty = CRM_Core_Smarty
::singleton();
154 foreach ($this->_snippets
as $snippet) {
155 if ($snippet['disabled']) {
158 switch($snippet['type']) {
160 $html .= $snippet['markup'];
163 $tmp = $smarty->get_template_vars('snippet');
164 $smarty->assign('snippet', $snippet);
165 $html .= $smarty->fetch($snippet['template']);
166 $smarty->assign('snippet', $tmp);
169 $args = isset($snippet['arguments']) ?
$snippet['arguments'] : array(&$snippet, &$html);
170 $html .= call_user_func_array($snippet['callback'], $args);
173 if (!$allowCmsOverride ||
!$cms->addScriptUrl($snippet['scriptUrl'], $this->_name
)) {
174 $html .= sprintf("<script type=\"text/javascript\" src=\"%s\">\n</script>\n", $snippet['scriptUrl']);
178 $snippet['script'] = sprintf("cj(function(\$){\n%s\n});", $snippet['jquery']);
179 // no break - continue processing as script
181 if (!$allowCmsOverride ||
!$cms->addScript($snippet['script'], $this->_name
)) {
182 $html .= sprintf("<script type=\"text/javascript\">\n%s\n</script>\n", $snippet['script']);
186 if (!$allowCmsOverride ||
!$cms->addStyleUrl($snippet['styleUrl'], $this->_name
)) {
187 $html .= sprintf("<link href=\"%s\" rel=\"stylesheet\" type=\"text/css\"/>\n", $snippet['styleUrl']);
191 if (!$allowCmsOverride ||
!$cms->addStyle($snippet['style'], $this->_name
)) {
192 $html .= sprintf("<style type=\"text/css\">\n%s\n</style>\n", $snippet['style']);
196 require_once 'CRM/Core/Error.php';
197 CRM_Core_Error
::fatal( ts( 'Snippet type %1 is unrecognized',
198 array( 1 => $snippet['type'] ) ) );
204 static function _cmpSnippet($a, $b) {
205 if ($a['weight'] < $b['weight']) return -1;
206 if ($a['weight'] > $b['weight']) return 1;
207 // fallback to name sort; don't really want to do this, but it makes results more stable
208 if ($a['name'] < $b['name']) return -1;
209 if ($a['name'] > $b['name']) return 1;
214 * Add block of static HTML to a region
216 * @param string $markup HTML
218 public function addMarkup($markup) {
219 return $this->add(array(
226 * Add a Smarty template file to a region
228 * Note: File is not evaluated until the page is rendered
230 * @param string $template path to the Smarty template file
232 public function addTemplate($template) {
233 return $this->add(array(
234 'type' => 'template',
235 'template' => $template,
240 * Use a callback function to extend a region
242 * @param mixed $callback
243 * @param array $arguments optional, array of parameters for callback; if omitted, the default arguments are ($snippetSpec, $html)
245 public function addCallback($callback, $arguments = FALSE) {
246 return $this->add(array(
247 'type' => 'callback',
248 'callback' => $callback,
249 'arguments' => $arguments,