1 <?php
2 /**
3 * @package Joomla.Libraries
4 * @subpackage Toolbar
5 *
6 * @copyright Copyright (C) 2005 - 2017 Open Source Matters, Inc. All rights reserved.
7 * @license GNU General Public License version 2 or later; see LICENSE.txt
8 */
9
10 defined('JPATH_PLATFORM') or die;
11
12 /**
13 * ToolBar handler
14 *
15 * @since 1.5
16 */
17 class JToolbar
18 {
19 /**
20 * Toolbar name
21 *
22 * @var string
23 */
24 protected $_name = array();
25
26 /**
27 * Toolbar array
28 *
29 * @var array
30 */
31 protected $_bar = array();
32
33 /**
34 * Loaded buttons
35 *
36 * @var array
37 */
38 protected $_buttons = array();
39
40 /**
41 * Directories, where button types can be stored.
42 *
43 * @var array
44 */
45 protected $_buttonPath = array();
46
47 /**
48 * Stores the singleton instances of various toolbar.
49 *
50 * @var JToolbar
51 * @since 2.5
52 */
53 protected static $instances = array();
54
55 /**
56 * Constructor
57 *
58 * @param string $name The toolbar name.
59 *
60 * @since 1.5
61 */
62 public function __construct($name = 'toolbar')
63 {
64 $this->_name = $name;
65
66 // Set base path to find buttons.
67 $this->_buttonPath[] = __DIR__ . '/button';
68 }
69
70 /**
71 * Returns the global JToolbar object, only creating it if it
72 * doesn't already exist.
73 *
74 * @param string $name The name of the toolbar.
75 *
76 * @return JToolbar The JToolbar object.
77 *
78 * @since 1.5
79 */
80 public static function getInstance($name = 'toolbar')
81 {
82 if (empty(self::$instances[$name]))
83 {
84 self::$instances[$name] = new JToolbar($name);
85 }
86
87 return self::$instances[$name];
88 }
89
90 /**
91 * Set a value
92 *
93 * @return string The set value.
94 *
95 * @since 1.5
96 */
97 public function appendButton()
98 {
99 // Push button onto the end of the toolbar array.
100 $btn = func_get_args();
101 $this->_bar[] = $btn;
102
103 return true;
104 }
105
106 /**
107 * Get the list of toolbar links.
108 *
109 * @return array
110 *
111 * @since 1.6
112 */
113 public function getItems()
114 {
115 return $this->_bar;
116 }
117
118 /**
119 * Get the name of the toolbar.
120 *
121 * @return string
122 *
123 * @since 1.6
124 */
125 public function getName()
126 {
127 return $this->_name;
128 }
129
130 /**
131 * Get a value.
132 *
133 * @return string
134 *
135 * @since 1.5
136 */
137 public function prependButton()
138 {
139 // Insert button into the front of the toolbar array.
140 $btn = func_get_args();
141 array_unshift($this->_bar, $btn);
142
143 return true;
144 }
145
146 /**
147 * Render a toolbar.
148 *
149 * @return string HTML for the toolbar.
150 *
151 * @since 1.5
152 */
153 public function render()
154 {
155 $html = array();
156
157 // Start toolbar div.
158 $layout = new JLayoutFile('joomla.toolbar.containeropen');
159
160 $html[] = $layout->render(array('id' => $this->_name));
161
162 // Render each button in the toolbar.
163 foreach ($this->_bar as $button)
164 {
165 $html[] = $this->renderButton($button);
166 }
167
168 // End toolbar div.
169 $layout = new JLayoutFile('joomla.toolbar.containerclose');
170
171 $html[] = $layout->render(array());
172
173 return implode('', $html);
174 }
175
176 /**
177 * Render a button.
178 *
179 * @param object &$node A toolbar node.
180 *
181 * @return string
182 *
183 * @since 1.5
184 */
185 public function renderButton(&$node)
186 {
187 // Get the button type.
188 $type = $node[0];
189
190 $button = $this->loadButtonType($type);
191
192 // Check for error.
193 if ($button === false)
194 {
195 return JText::sprintf('JLIB_HTML_BUTTON_NOT_DEFINED', $type);
196 }
197
198 return $button->render($node);
199 }
200
201 /**
202 * Loads a button type.
203 *
204 * @param string $type Button Type
205 * @param boolean $new False by default
206 *
207 * @return boolean
208 *
209 * @since 1.5
210 */
211 public function loadButtonType($type, $new = false)
212 {
213 $signature = md5($type);
214
215 if ($new === false && isset($this->_buttons[$signature]))
216 {
217 return $this->_buttons[$signature];
218 }
219
220 if (!class_exists('JToolbarButton'))
221 {
222 JLog::add(JText::_('JLIB_HTML_BUTTON_BASE_CLASS'), JLog::WARNING, 'jerror');
223
224 return false;
225 }
226
227 $buttonClass = 'JToolbarButton' . ucfirst($type);
228
229 // @deprecated 12.3 Remove the acceptance of legacy classes starting with JButton.
230 $buttonClassOld = 'JButton' . ucfirst($type);
231
232 if (!class_exists($buttonClass))
233 {
234 if (!class_exists($buttonClassOld))
235 {
236 if (isset($this->_buttonPath))
237 {
238 $dirs = $this->_buttonPath;
239 }
240 else
241 {
242 $dirs = array();
243 }
244
245 $file = JFilterInput::getInstance()->clean(str_replace('_', DIRECTORY_SEPARATOR, strtolower($type)) . '.php', 'path');
246
247 jimport('joomla.filesystem.path');
248
249 if ($buttonFile = JPath::find($dirs, $file))
250 {
251 include_once $buttonFile;
252 }
253 else
254 {
255 JLog::add(JText::sprintf('JLIB_HTML_BUTTON_NO_LOAD', $buttonClass, $buttonFile), JLog::WARNING, 'jerror');
256
257 return false;
258 }
259 }
260 }
261
262 if (!class_exists($buttonClass) && !class_exists($buttonClassOld))
263 {
264 // @todo remove code: return JError::raiseError('SOME_ERROR_CODE', "Module file $buttonFile does not contain class $buttonClass.");
265 return false;
266 }
267
268 $this->_buttons[$signature] = new $buttonClass($this);
269
270 return $this->_buttons[$signature];
271 }
272
273 /**
274 * Add a directory where JToolbar should search for button types in LIFO order.
275 *
276 * You may either pass a string or an array of directories.
277 *
278 * JToolbar will be searching for an element type in the same order you
279 * added them. If the parameter type cannot be found in the custom folders,
280 * it will look in libraries/joomla/html/toolbar/button.
281 *
282 * @param mixed $path Directory or directories to search.
283 *
284 * @return void
285 *
286 * @since boolean
287 * @see JToolbar
288 */
289 public function addButtonPath($path)
290 {
291 // Loop through the path directories.
292 foreach ((array) $path as $dir)
293 {
294 // No surrounding spaces allowed!
295 $dir = trim($dir);
296
297 // Add trailing separators as needed.
298 if (substr($dir, -1) !== DIRECTORY_SEPARATOR)
299 {
300 // Directory
301 $dir .= DIRECTORY_SEPARATOR;
302 }
303
304 // Add to the top of the search dirs.
305 array_unshift($this->_buttonPath, $dir);
306 }
307 }
308 }
309