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