CRM-16145 - Add CRM_Utils_File::concat()
[civicrm-core.git] / Civi / Angular / Manager.php
CommitLineData
16072ce1
TO
1<?php
2namespace Civi\Angular;
3
4/**
5 * Manage Angular resources.
6 *
7 * @package Civi\Angular
8 */
9class Manager {
10
11 /**
12 * @var \CRM_Core_Resources
13 */
14 protected $res = NULL;
15
16 /**
17 * @var array|NULL
18 * Each item has some combination of these keys:
19 * - ext: string
8671b4f2 20 * The Civi extension which defines the Angular module.
16072ce1 21 * - js: array(string $relativeFilePath)
8671b4f2 22 * List of JS files (relative to the extension).
16072ce1 23 * - css: array(string $relativeFilePath)
8671b4f2 24 * List of CSS files (relative to the extension).
16072ce1 25 * - partials: array(string $relativeFilePath)
8671b4f2
TO
26 * A list of partial-HTML folders (relative to the extension).
27 * This will be mapped to "~/moduleName" by crmResource.
16072ce1
TO
28 */
29 protected $modules = NULL;
30
31 /**
32 * @param \CRM_Core_Resources $res
33 * The resource manager.
34 */
35 public function __construct($res) {
36 $this->res = $res;
37 }
38
39 /**
fe482240 40 * Get a list of AngularJS modules which should be autoloaded.
16072ce1
TO
41 *
42 * @return array
8671b4f2
TO
43 * Each item has some combination of these keys:
44 * - ext: string
45 * The Civi extension which defines the Angular module.
46 * - js: array(string $relativeFilePath)
47 * List of JS files (relative to the extension).
48 * - css: array(string $relativeFilePath)
49 * List of CSS files (relative to the extension).
50 * - partials: array(string $relativeFilePath)
51 * A list of partial-HTML folders (relative to the extension).
52 * This will be mapped to "~/moduleName" by crmResource.
16072ce1
TO
53 */
54 public function getModules() {
55 if ($this->modules === NULL) {
56
57 $angularModules = array();
58 $angularModules['angularFileUpload'] = array(
59 'ext' => 'civicrm',
60 'js' => array('bower_components/angular-file-upload/angular-file-upload.min.js'),
61 );
62 $angularModules['crmApp'] = array(
63 'ext' => 'civicrm',
64 'js' => array('js/angular-crmApp.js'),
65 );
66 $angularModules['crmAttachment'] = array(
67 'ext' => 'civicrm',
68 'js' => array('js/angular-crmAttachment.js'),
69 'css' => array('css/angular-crmAttachment.css'),
ad7abea2 70 'partials' => array('partials/crmAttachment'),
16072ce1 71 );
2386ec88
TO
72 $angularModules['crmAutosave'] = array(
73 'ext' => 'civicrm',
74 'js' => array('js/angular-crmAutosave.js'),
75 );
56f158de
TO
76 //$angularModules['crmExample'] = array(
77 // 'ext' => 'civicrm',
78 // 'js' => array('js/angular-crmExample.js'),
79 // 'partials' => array('partials/crmExample'),
80 //);
a2dc0f82
TO
81 $angularModules['crmResource'] = array(
82 'ext' => 'civicrm',
83 // 'js' => array('js/angular-crmResource/byModule.js'), // One HTTP request per module.
84 'js' => array('js/angular-crmResource/all.js'), // One HTTP request for all modules.
85 );
16072ce1
TO
86 $angularModules['crmUi'] = array(
87 'ext' => 'civicrm',
88 'js' => array('js/angular-crm-ui.js', 'packages/ckeditor/ckeditor.js'),
ad7abea2 89 'partials' => array('partials/crmUi'),
16072ce1
TO
90 );
91 $angularModules['crmUtil'] = array(
92 'ext' => 'civicrm',
93 'js' => array('js/angular-crm-util.js'),
94 );
95 // https://github.com/jwstadler/angular-jquery-dialog-service
96 $angularModules['dialogService'] = array(
97 'ext' => 'civicrm',
98 'js' => array('bower_components/angular-jquery-dialog-service/dialog-service.js'),
99 );
16072ce1
TO
100 $angularModules['ui.utils'] = array(
101 'ext' => 'civicrm',
102 'js' => array('bower_components/angular-ui-utils/ui-utils.min.js'),
103 );
104 $angularModules['ui.sortable'] = array(
105 'ext' => 'civicrm',
106 'js' => array('bower_components/angular-ui-sortable/sortable.min.js'),
107 );
108 $angularModules['unsavedChanges'] = array(
109 'ext' => 'civicrm',
110 'js' => array('bower_components/angular-unsavedChanges/dist/unsavedChanges.min.js'),
111 );
112
113 foreach (\CRM_Core_Component::getEnabledComponents() as $component) {
114 $angularModules = array_merge($angularModules, $component->getAngularModules());
115 }
116 \CRM_Utils_Hook::angularModules($angularModules);
117 $this->modules = $this->resolvePatterns($angularModules);
118 }
119
120 return $this->modules;
121 }
122
123 /**
124 * Get the descriptor for an Angular module.
125 *
126 * @param string $name
127 * Module name.
128 * @return array
129 * Details about the module:
130 * - ext: string, the name of the Civi extension which defines the module
131 * - js: array(string $relativeFilePath).
132 * - css: array(string $relativeFilePath).
133 * - partials: array(string $relativeFilePath).
134 * @throws \Exception
135 */
136 public function getModule($name) {
137 $modules = $this->getModules();
138 if (!isset($modules[$name])) {
139 throw new \Exception("Unrecognized Angular module");
140 }
141 return $modules[$name];
142 }
143
144 /**
145 * Convert any globs in an Angular module to file names.
146 *
147 * @param array $modules
148 * List of Angular modules.
149 * @return array
150 * Updated list of Angular modules
151 */
152 protected function resolvePatterns($modules) {
153 $newModules = array();
154
155 foreach ($modules as $moduleKey => $module) {
156 foreach (array('js', 'css', 'partials') as $fileset) {
157 if (!isset($module[$fileset])) {
158 continue;
159 }
160 $module[$fileset] = $this->res->glob($module['ext'], $module[$fileset]);
161 }
162 $newModules[$moduleKey] = $module;
163 }
164
165 return $newModules;
166 }
167
168 /**
169 * Get the partial HTML documents for a module.
170 *
171 * @param string $name
172 * Angular module name.
173 * @return array
174 * Array(string $extFilePath => string $html)
a2dc0f82
TO
175 * @throws \Exception
176 * Invalid partials configuration.
16072ce1
TO
177 */
178 public function getPartials($name) {
179 $module = $this->getModule($name);
180 $result = array();
181 if (isset($module['partials'])) {
a2dc0f82
TO
182 foreach ($module['partials'] as $partialDir) {
183 $partialDir = $this->res->getPath($module['ext']) . '/' . $partialDir;
184 $files = \CRM_Utils_File::findFiles($partialDir, '*.html', TRUE);
185 foreach ($files as $file) {
186 $filename = '~/' . $name . '/' . $file;
187 $result[$filename] = file_get_contents($partialDir . '/' . $file);
188 }
16072ce1
TO
189 }
190 }
191 return $result;
192 }
193
16072ce1
TO
194 /**
195 * Get list of translated strings for a module.
196 *
197 * @param string $name
198 * Angular module name.
199 * @return array
200 * Translated strings: array(string $orig => string $translated).
201 */
202 public function getTranslatedStrings($name) {
e3d90d6c 203 $module = $this->getModule($name);
16072ce1
TO
204 $result = array();
205 $strings = $this->getStrings($name);
206 foreach ($strings as $string) {
207 // TODO: should we pass translation domain based on $module[ext] or $module[tsDomain]?
208 // It doesn't look like client side really supports the domain right now...
e3d90d6c
TO
209 $translated = ts($string, array(
210 'domain' => array($module['ext'], NULL),
211 ));
16072ce1
TO
212 if ($translated != $string) {
213 $result[$string] = $translated;
214 }
215 }
216 return $result;
217 }
218
219 /**
220 * Get list of translatable strings for a module.
221 *
222 * @param string $name
223 * Angular module name.
224 * @return array
225 * Translatable strings.
226 */
227 public function getStrings($name) {
228 $module = $this->getModule($name);
229 $result = array();
230 if (isset($module['js'])) {
231 foreach ($module['js'] as $file) {
232 $strings = $this->res->getStrings()->get(
233 $module['ext'],
234 $this->res->getPath($module['ext'], $file),
235 'text/javascript'
236 );
237 $result = array_unique(array_merge($result, $strings));
238 }
239 }
240 if (isset($module['partials'])) {
a2dc0f82
TO
241 foreach ($module['partials'] as $partialDir) {
242 $partialDir = $this->res->getPath($module['ext']) . '/' . $partialDir;
243 $files = \CRM_Utils_File::findFiles($partialDir, '*.html');
244 foreach ($files as $file) {
245 $strings = $this->res->getStrings()->get(
246 $module['ext'],
247 $file,
248 'text/html'
249 );
250 $result = array_unique(array_merge($result, $strings));
251 }
16072ce1
TO
252 }
253 }
254 return $result;
255 }
256
257 /**
258 * @param string $name
259 * Module name.
260 * @return array
261 * List of URLs.
262 * @throws \Exception
263 */
264 public function getScriptUrls($name) {
265 $module = $this->getModule($name);
266 $result = array();
267 if (isset($module['js'])) {
268 foreach ($module['js'] as $file) {
269 $result[] = $this->res->getUrl($module['ext'], $file, TRUE);
270 }
271 }
272 return $result;
273 }
274
275 /**
276 * @param string $name
277 * Module name.
278 * @return array
279 * List of URLs.
280 * @throws \Exception
281 */
282 public function getStyleUrls($name) {
283 $module = $this->getModule($name);
284 $result = array();
285 if (isset($module['css'])) {
286 foreach ($module['css'] as $file) {
287 $result[] = $this->res->getUrl($module['ext'], $file, TRUE);
288 }
289 }
290 return $result;
291 }
8671b4f2 292
16072ce1 293}