CRM-15832 - Angular - Add page which aggregates partials+strings
[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'),
56 'partials' => array('partials/crmAttachment/*.html'),
57 );
58 $angularModules['crmUi'] = array(
59 'ext' => 'civicrm',
60 'js' => array('js/angular-crm-ui.js', 'packages/ckeditor/ckeditor.js'),
61 'partials' => array('partials/crmUi/*.html'),
62 );
63 $angularModules['crmUtil'] = array(
64 'ext' => 'civicrm',
65 'js' => array('js/angular-crm-util.js'),
66 );
67 // https://github.com/jwstadler/angular-jquery-dialog-service
68 $angularModules['dialogService'] = array(
69 'ext' => 'civicrm',
70 'js' => array('bower_components/angular-jquery-dialog-service/dialog-service.js'),
71 );
72 $angularModules['ngSanitize'] = array(
73 'ext' => 'civicrm',
74 'js' => array('js/angular-sanitize.js'),
75 );
76 $angularModules['ui.utils'] = array(
77 'ext' => 'civicrm',
78 'js' => array('bower_components/angular-ui-utils/ui-utils.min.js'),
79 );
80 $angularModules['ui.sortable'] = array(
81 'ext' => 'civicrm',
82 'js' => array('bower_components/angular-ui-sortable/sortable.min.js'),
83 );
84 $angularModules['unsavedChanges'] = array(
85 'ext' => 'civicrm',
86 'js' => array('bower_components/angular-unsavedChanges/dist/unsavedChanges.min.js'),
87 );
88
89 foreach (\CRM_Core_Component::getEnabledComponents() as $component) {
90 $angularModules = array_merge($angularModules, $component->getAngularModules());
91 }
92 \CRM_Utils_Hook::angularModules($angularModules);
93 $this->modules = $this->resolvePatterns($angularModules);
94 }
95
96 return $this->modules;
97 }
98
99 /**
100 * Get the descriptor for an Angular module.
101 *
102 * @param string $name
103 * Module name.
104 * @return array
105 * Details about the module:
106 * - ext: string, the name of the Civi extension which defines the module
107 * - js: array(string $relativeFilePath).
108 * - css: array(string $relativeFilePath).
109 * - partials: array(string $relativeFilePath).
110 * @throws \Exception
111 */
112 public function getModule($name) {
113 $modules = $this->getModules();
114 if (!isset($modules[$name])) {
115 throw new \Exception("Unrecognized Angular module");
116 }
117 return $modules[$name];
118 }
119
120 /**
121 * Convert any globs in an Angular module to file names.
122 *
123 * @param array $modules
124 * List of Angular modules.
125 * @return array
126 * Updated list of Angular modules
127 */
128 protected function resolvePatterns($modules) {
129 $newModules = array();
130
131 foreach ($modules as $moduleKey => $module) {
132 foreach (array('js', 'css', 'partials') as $fileset) {
133 if (!isset($module[$fileset])) {
134 continue;
135 }
136 $module[$fileset] = $this->res->glob($module['ext'], $module[$fileset]);
137 }
138 $newModules[$moduleKey] = $module;
139 }
140
141 return $newModules;
142 }
143
144 /**
145 * Get the partial HTML documents for a module.
146 *
147 * @param string $name
148 * Angular module name.
149 * @return array
150 * Array(string $extFilePath => string $html)
151 */
152 public function getPartials($name) {
153 $module = $this->getModule($name);
154 $result = array();
155 if (isset($module['partials'])) {
156 foreach ($module['partials'] as $file) {
157 $filename = $name . '/' . $file;
158 $result[$filename] = file_get_contents($this->res->getPath($module['ext'], $file));
159 }
160 }
161 return $result;
162 }
163
164
165 /**
166 * Get list of translated strings for a module.
167 *
168 * @param string $name
169 * Angular module name.
170 * @return array
171 * Translated strings: array(string $orig => string $translated).
172 */
173 public function getTranslatedStrings($name) {
174 $result = array();
175 $strings = $this->getStrings($name);
176 foreach ($strings as $string) {
177 // TODO: should we pass translation domain based on $module[ext] or $module[tsDomain]?
178 // It doesn't look like client side really supports the domain right now...
179 $translated = ts($string);
180 if ($translated != $string) {
181 $result[$string] = $translated;
182 }
183 }
184 return $result;
185 }
186
187 /**
188 * Get list of translatable strings for a module.
189 *
190 * @param string $name
191 * Angular module name.
192 * @return array
193 * Translatable strings.
194 */
195 public function getStrings($name) {
196 $module = $this->getModule($name);
197 $result = array();
198 if (isset($module['js'])) {
199 foreach ($module['js'] as $file) {
200 $strings = $this->res->getStrings()->get(
201 $module['ext'],
202 $this->res->getPath($module['ext'], $file),
203 'text/javascript'
204 );
205 $result = array_unique(array_merge($result, $strings));
206 }
207 }
208 if (isset($module['partials'])) {
209 foreach ($module['partials'] as $file) {
210 $strings = $this->res->getStrings()->get(
211 $module['ext'],
212 $this->res->getPath($module['ext'], $file),
213 'text/html'
214 );
215 $result = array_unique(array_merge($result, $strings));
216 }
217 }
218 return $result;
219 }
220
221 /**
222 * @param string $name
223 * Module name.
224 * @return array
225 * List of URLs.
226 * @throws \Exception
227 */
228 public function getScriptUrls($name) {
229 $module = $this->getModule($name);
230 $result = array();
231 if (isset($module['js'])) {
232 foreach ($module['js'] as $file) {
233 $result[] = $this->res->getUrl($module['ext'], $file, TRUE);
234 }
235 }
236 return $result;
237 }
238
239 /**
240 * @param string $name
241 * Module name.
242 * @return array
243 * List of URLs.
244 * @throws \Exception
245 */
246 public function getStyleUrls($name) {
247 $module = $this->getModule($name);
248 $result = array();
249 if (isset($module['css'])) {
250 foreach ($module['css'] as $file) {
251 $result[] = $this->res->getUrl($module['ext'], $file, TRUE);
252 }
253 }
254 return $result;
255 }
256}