dc254caf8cf48be9a549bc951a5cae2a51c246b5
[civicrm-core.git] / Civi / Angular / Manager.php
1 <?php
2 namespace Civi\Angular;
3
4 /**
5 * Manage Angular resources.
6 *
7 * @package Civi\Angular
8 */
9 class 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
20 * The Civi extension which defines the Angular module.
21 * - js: array(string $relativeFilePath)
22 * List of JS files (relative to the extension).
23 * - css: array(string $relativeFilePath)
24 * List of CSS files (relative to the extension).
25 * - partials: array(string $relativeFilePath)
26 * A list of partial-HTML folders (relative to the extension).
27 * This will be mapped to "~/moduleName" by crmResource.
28 * - settings: array(string $key => mixed $value)
29 * List of settings to preload.
30 */
31 protected $modules = NULL;
32
33 /**
34 * @param \CRM_Core_Resources $res
35 * The resource manager.
36 */
37 public function __construct($res) {
38 $this->res = $res;
39 }
40
41 /**
42 * Get a list of AngularJS modules which should be autoloaded.
43 *
44 * @return array
45 * Each item has some combination of these keys:
46 * - ext: string
47 * The Civi extension which defines the Angular module.
48 * - js: array(string $relativeFilePath)
49 * List of JS files (relative to the extension).
50 * - css: array(string $relativeFilePath)
51 * List of CSS files (relative to the extension).
52 * - partials: array(string $relativeFilePath)
53 * A list of partial-HTML folders (relative to the extension).
54 * This will be mapped to "~/moduleName" by crmResource.
55 * - settings: array(string $key => mixed $value)
56 * List of settings to preload.
57 */
58 public function getModules() {
59 if ($this->modules === NULL) {
60 $config = \CRM_Core_Config::singleton();
61
62 $angularModules = array();
63 $angularModules['angularFileUpload'] = array(
64 'ext' => 'civicrm',
65 'js' => array('bower_components/angular-file-upload/angular-file-upload.min.js'),
66 );
67 $angularModules['crmApp'] = array(
68 'ext' => 'civicrm',
69 'js' => array('ang/crmApp.js'),
70 );
71 $angularModules['crmAttachment'] = array(
72 'ext' => 'civicrm',
73 'js' => array('ang/crmAttachment.js'),
74 'css' => array('ang/crmAttachment.css'),
75 'partials' => array('ang/crmAttachment'),
76 'settings' => array(
77 'token' => \CRM_Core_Page_AJAX_Attachment::createToken(),
78 ),
79 );
80 $angularModules['crmAutosave'] = array(
81 'ext' => 'civicrm',
82 'js' => array('ang/crmAutosave.js'),
83 );
84 $angularModules['crmCxn'] = array(
85 'ext' => 'civicrm',
86 'js' => array('ang/crmCxn.js', 'ang/crmCxn/*.js'),
87 'css' => array('ang/crmCxn.css'),
88 'partials' => array('ang/crmCxn'),
89 );
90 //$angularModules['crmExample'] = array(
91 // 'ext' => 'civicrm',
92 // 'js' => array('ang/crmExample.js'),
93 // 'partials' => array('ang/crmExample'),
94 //);
95 $angularModules['crmResource'] = array(
96 'ext' => 'civicrm',
97 // 'js' => array('js/angular-crmResource/byModule.js'), // One HTTP request per module.
98 'js' => array('js/angular-crmResource/all.js'), // One HTTP request for all modules.
99 );
100 $angularModules['crmUi'] = array(
101 'ext' => 'civicrm',
102 'js' => array('ang/crmUi.js'),
103 'partials' => array('ang/crmUi'),
104 'settings' => array(
105 'browseUrl' => $config->userFrameworkResourceURL . 'packages/kcfinder/browse.php',
106 'uploadUrl' => $config->userFrameworkResourceURL . 'packages/kcfinder/upload.php',
107 ),
108 );
109 $angularModules['crmUtil'] = array(
110 'ext' => 'civicrm',
111 'js' => array('ang/crmUtil.js'),
112 );
113 // https://github.com/jwstadler/angular-jquery-dialog-service
114 $angularModules['dialogService'] = array(
115 'ext' => 'civicrm',
116 'js' => array('bower_components/angular-jquery-dialog-service/dialog-service.js'),
117 );
118 $angularModules['ngRoute'] = array(
119 'ext' => 'civicrm',
120 'js' => array('bower_components/angular-route/angular-route.min.js'),
121 );
122 $angularModules['ngSanitize'] = array(
123 'ext' => 'civicrm',
124 'js' => array('bower_components/angular-sanitize/angular-sanitize.min.js'),
125 );
126 $angularModules['ui.utils'] = array(
127 'ext' => 'civicrm',
128 'js' => array('bower_components/angular-ui-utils/ui-utils.min.js'),
129 );
130 $angularModules['ui.sortable'] = array(
131 'ext' => 'civicrm',
132 'js' => array('bower_components/angular-ui-sortable/sortable.min.js'),
133 );
134 $angularModules['unsavedChanges'] = array(
135 'ext' => 'civicrm',
136 'js' => array('bower_components/angular-unsavedChanges/dist/unsavedChanges.min.js'),
137 );
138
139 $angularModules['statuspage'] = array(
140 'ext' => 'civicrm',
141 'js' => array('ang/crmStatusPage.js', 'ang/crmStatusPage/*.js'),
142 'css' => array('ang/crmStatusPage.css'),
143 'partials' => array('ang/crmStatusPage/*.html'),
144 'settings' => array(),
145 );
146
147 foreach (\CRM_Core_Component::getEnabledComponents() as $component) {
148 $angularModules = array_merge($angularModules, $component->getAngularModules());
149 }
150 \CRM_Utils_Hook::angularModules($angularModules);
151 $this->modules = $this->resolvePatterns($angularModules);
152 }
153
154 return $this->modules;
155 }
156
157 /**
158 * Get the descriptor for an Angular module.
159 *
160 * @param string $name
161 * Module name.
162 * @return array
163 * Details about the module:
164 * - ext: string, the name of the Civi extension which defines the module
165 * - js: array(string $relativeFilePath).
166 * - css: array(string $relativeFilePath).
167 * - partials: array(string $relativeFilePath).
168 * @throws \Exception
169 */
170 public function getModule($name) {
171 $modules = $this->getModules();
172 if (!isset($modules[$name])) {
173 throw new \Exception("Unrecognized Angular module");
174 }
175 return $modules[$name];
176 }
177
178 /**
179 * Convert any globs in an Angular module to file names.
180 *
181 * @param array $modules
182 * List of Angular modules.
183 * @return array
184 * Updated list of Angular modules
185 */
186 protected function resolvePatterns($modules) {
187 $newModules = array();
188
189 foreach ($modules as $moduleKey => $module) {
190 foreach (array('js', 'css', 'partials') as $fileset) {
191 if (!isset($module[$fileset])) {
192 continue;
193 }
194 $module[$fileset] = $this->res->glob($module['ext'], $module[$fileset]);
195 }
196 $newModules[$moduleKey] = $module;
197 }
198
199 return $newModules;
200 }
201
202 /**
203 * Get the partial HTML documents for a module.
204 *
205 * @param string $name
206 * Angular module name.
207 * @return array
208 * Array(string $extFilePath => string $html)
209 * @throws \Exception
210 * Invalid partials configuration.
211 */
212 public function getPartials($name) {
213 $module = $this->getModule($name);
214 $result = array();
215 if (isset($module['partials'])) {
216 foreach ($module['partials'] as $partialDir) {
217 $partialDir = $this->res->getPath($module['ext']) . '/' . $partialDir;
218 $files = \CRM_Utils_File::findFiles($partialDir, '*.html', TRUE);
219 foreach ($files as $file) {
220 $filename = '~/' . $name . '/' . $file;
221 $result[$filename] = file_get_contents($partialDir . '/' . $file);
222 }
223 }
224 }
225 return $result;
226 }
227
228 /**
229 * Get list of translated strings for a module.
230 *
231 * @param string $name
232 * Angular module name.
233 * @return array
234 * Translated strings: array(string $orig => string $translated).
235 */
236 public function getTranslatedStrings($name) {
237 $module = $this->getModule($name);
238 $result = array();
239 $strings = $this->getStrings($name);
240 foreach ($strings as $string) {
241 // TODO: should we pass translation domain based on $module[ext] or $module[tsDomain]?
242 // It doesn't look like client side really supports the domain right now...
243 $translated = ts($string, array(
244 'domain' => array($module['ext'], NULL),
245 ));
246 if ($translated != $string) {
247 $result[$string] = $translated;
248 }
249 }
250 return $result;
251 }
252
253 /**
254 * Get list of translatable strings for a module.
255 *
256 * @param string $name
257 * Angular module name.
258 * @return array
259 * Translatable strings.
260 */
261 public function getStrings($name) {
262 $module = $this->getModule($name);
263 $result = array();
264 if (isset($module['js'])) {
265 foreach ($module['js'] as $file) {
266 $strings = $this->res->getStrings()->get(
267 $module['ext'],
268 $this->res->getPath($module['ext'], $file),
269 'text/javascript'
270 );
271 $result = array_unique(array_merge($result, $strings));
272 }
273 }
274 if (isset($module['partials'])) {
275 foreach ($module['partials'] as $partialDir) {
276 $partialDir = $this->res->getPath($module['ext']) . '/' . $partialDir;
277 $files = \CRM_Utils_File::findFiles($partialDir, '*.html');
278 foreach ($files as $file) {
279 $strings = $this->res->getStrings()->get(
280 $module['ext'],
281 $file,
282 'text/html'
283 );
284 $result = array_unique(array_merge($result, $strings));
285 }
286 }
287 }
288 return $result;
289 }
290
291 /**
292 * Get resources for one or more modules.
293 *
294 * @param string|array $moduleNames
295 * List of module names.
296 * @param string $resType
297 * Type of resource ('js', 'css', 'settings').
298 * @param string $refType
299 * Type of reference to the resource ('cacheUrl', 'rawUrl', 'path', 'settings').
300 * @return array
301 * List of URLs or paths.
302 * @throws \CRM_Core_Exception
303 */
304 public function getResources($moduleNames, $resType, $refType) {
305 $result = array();
306 $moduleNames = (array) $moduleNames;
307 foreach ($moduleNames as $moduleName) {
308 $module = $this->getModule($moduleName);
309 if (isset($module[$resType])) {
310 foreach ($module[$resType] as $file) {
311 switch ($refType) {
312 case 'path':
313 $result[] = $this->res->getPath($module['ext'], $file);
314 break;
315
316 case 'rawUrl':
317 $result[] = $this->res->getUrl($module['ext'], $file);
318 break;
319
320 case 'cacheUrl':
321 $result[] = $this->res->getUrl($module['ext'], $file, TRUE);
322 break;
323
324 case 'settings':
325 if (!empty($module[$resType])) {
326 $result[$moduleName] = $module[$resType];
327 }
328 break;
329
330 default:
331 throw new \CRM_Core_Exception("Unrecognized resource format");
332 }
333 }
334 }
335 }
336 return $result;
337 }
338
339 }