1: <?php
2: /**
3: * The Horde_Script_Files:: class provides a coherent way to manage script
4: * files for inclusion in Horde output. This class is meant to be used
5: * internally by Horde:: only.
6: *
7: * Copyright 1999-2012 Horde LLC (http://www.horde.org/)
8: *
9: * See the enclosed file COPYING for license information (LGPL). If you
10: * did not receive this file, see http://www.horde.org/licenses/lgpl21.
11: *
12: * @author Michael Slusarz <slusarz@horde.org>
13: * @category Horde
14: * @package Core
15: */
16: class Horde_Script_Files
17: {
18: /**
19: * Automatically include prototypejs?
20: *
21: * @var boolean
22: */
23: public $prototypejs = true;
24:
25: /**
26: * The list of script files to add.
27: *
28: * @var array
29: */
30: protected $_files = array(
31: 'horde' => array()
32: );
33:
34: /**
35: * TODO
36: *
37: * @var boolean
38: */
39: protected $_full = false;
40:
41: /**
42: * The list of files we have already included.
43: *
44: * @var array
45: */
46: protected $_included = array();
47:
48: /**
49: * Adds the javascript code to the output (if output has already started)
50: * or to the list of script files to include.
51: *
52: * @param string $file The full javascript file name.
53: * @param string $app The application name. Defaults to the current
54: * application.
55: * @param boolean $full Output a full url?
56: */
57: public function add($file, $app = null, $full = false)
58: {
59: if ($file == 'prototype.js') {
60: $this->prototype = true;
61: return;
62: }
63: if ($full && !$this->_full) {
64: $this->_full = true;
65: }
66: if (($this->_add($file, $app, $full) === false) ||
67: !Horde::contentSent()) {
68: return;
69: }
70:
71: // If headers have already been sent, we need to output a <script>
72: // tag directly.
73: $this->includeFiles();
74: }
75:
76: /**
77: * Adds an external script file
78: *
79: * @param string $url The url to the external script file.
80: * @param string $app The app scope.
81: */
82: public function addExternal($url, $app = null)
83: {
84: // Force external scripts under Horde scope to better avoid
85: // duplicates, and to ensure they are loaded before other application
86: // specific files
87: $app = 'horde';
88:
89: // Don't include scripts multiple times.
90: if (!empty($this->_included[$app][$url])) {
91: return false;
92: }
93:
94: $this->_included[$app][$url] = true;
95:
96: $this->_files[$app][] = array(
97: 'f' => basename($url),
98: 'u' => $url,
99: 'd' => false,
100: 'e' => true
101: );
102: }
103:
104: /**
105: * Helper function to determine if given file needs to be output.
106: *
107: * @return boolean True if the file needs to be output.
108: */
109: public function _add($file, $app, $full)
110: {
111: global $registry;
112:
113: if (empty($app)) {
114: $app = $registry->getApp();
115: }
116:
117: // Don't include scripts multiple times.
118: if (!empty($this->_included[$app][$file])) {
119: return false;
120: }
121: $this->_included[$app][$file] = true;
122:
123: // Add localized string for popup.js
124: if (($file == 'popup.js') && ($app == 'horde')) {
125: Horde::addInlineJsVars(array(
126: 'Horde.popup_block_text' => Horde_Core_Translation::t("A popup window could not be opened. Your browser may be blocking popups.")
127: ), array('onload' => 'dom'));
128: }
129:
130: if ($file[0] == '/') {
131: $url = Horde::url($registry->get('webroot', $app) . $file, $full, -1);
132: $path = $registry->get('fileroot', $app);
133: } else {
134: $url = Horde::url($registry->get('jsuri', $app) . '/' . $file, $full, -1);
135: $path = $registry->get('jsfs', $app) . '/';
136: }
137:
138: $this->_files[$app][] = array(
139: 'd' => true,
140: 'f' => $file,
141: 'p' => $path,
142: 'u' => $url
143: );
144:
145: return true;
146: }
147:
148: /**
149: * Output the list of javascript files needed.
150: */
151: public function includeFiles()
152: {
153: foreach ($this->listFiles() as $files) {
154: foreach ($files as $file) {
155: $this->outputTag($file['u']);
156: }
157: }
158:
159: $this->clear();
160: }
161:
162: /**
163: * Clears the cached list of files to output.
164: */
165: public function clear()
166: {
167: $this->_files = array();
168: }
169:
170: /**
171: * Prepares the list of javascript files to include.
172: *
173: * @return array The list of javascript files.
174: */
175: public function listFiles()
176: {
177: /* If there is no javascript available, there's no point in including
178: * the rest of the files. */
179: if (!$GLOBALS['browser']->hasFeature('javascript')) {
180: return array();
181: }
182:
183: /* Add prototype.js? */
184: if ($this->prototypejs) {
185: if (!isset($this->_included['horde']['prototype.js'])) {
186: $old = $this->_files['horde'];
187: $this->_files['horde'] = array();
188: $this->_add('prototype.js', 'horde', $this->_full);
189: $this->_files['horde'] = array_merge($this->_files['horde'], $old);
190: }
191:
192: /* Add accesskeys.js if access keys are enabled. */
193: if ($GLOBALS['prefs']->getValue('widget_accesskey')) {
194: $this->_add('accesskeys.js', 'horde', false);
195: }
196: } elseif (empty($this->_files['horde'])) {
197: /* Remove horde entry if nothing in it (was added on creation to
198: * ensure that it gets loaded first. */
199: unset($this->_files['horde']);
200: }
201:
202: return $this->_files;
203: }
204:
205: /**
206: * Outputs a script tag.
207: *
208: * @param string $src The source URL.
209: */
210: public function outputTag($src)
211: {
212: echo '<script type="text/javascript" src="' . $src . "\"></script>\n";
213: }
214:
215: }
216: