Commit | Line | Data |
---|---|---|
b2d8361e TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
4 | | Copyright CiviCRM LLC. All rights reserved. | | |
5 | | | | |
6 | | This work is published under the GNU AGPLv3 license with some | | |
7 | | permitted exceptions and without any warranty. For full license | | |
8 | | and copyright information, see https://civicrm.org/licensing | | |
9 | +--------------------------------------------------------------------+ | |
10 | */ | |
11 | ||
12 | /** | |
13 | * Define some common, global lists of resources. | |
14 | */ | |
15 | class CRM_Core_Resources_Common { | |
16 | ||
17 | const REGION = 'html-header'; | |
18 | ||
6e7adedc TO |
19 | /** |
20 | * The 'bundle.bootstrap3' service is a collection of resources which are | |
21 | * loaded when a page needs to support Boostrap CSS v3. | |
22 | * | |
23 | * @param string $name | |
24 | * i.e. 'bootstrap3' | |
25 | * @return \CRM_Core_Resources_Bundle | |
26 | */ | |
27 | public static function createBootstrap3Bundle($name) { | |
d853edea TO |
28 | $bundle = new CRM_Core_Resources_Bundle($name, ['script', 'scriptFile', 'scriptUrl', 'settings', 'style', 'styleFile', 'styleUrl', 'markup']); |
29 | // Leave it to the theme/provider to register specific resources. | |
30 | // $bundle->addStyleFile('civicrm', 'css/bootstrap3.css'); | |
31 | // $bundle->addScriptFile('civicrm', 'js/bootstrap3.js', [ | |
32 | // 'translate' => FALSE, | |
33 | //]); | |
34 | ||
35 | // This warning will show if bootstrap is unavailable. Normally it will be hidden by the bootstrap .collapse class. | |
36 | $bundle->addMarkup(' | |
37 | <div id="bootstrap-theme"> | |
38 | <div class="messages warning no-popup collapse"> | |
39 | <p> | |
40 | <i class="crm-i fa-exclamation-triangle" aria-hidden="true"></i> | |
41 | <strong>' . ts('Bootstrap theme not found.') . '</strong> | |
42 | </p> | |
43 | <p>' . ts('This screen may not work correctly without a bootstrap-based theme such as Shoreditch installed.') . '</p> | |
44 | </div> | |
45 | </div>', | |
46 | ['region' => 'page-header'] | |
47 | ); | |
48 | ||
6e7adedc TO |
49 | CRM_Utils_Hook::alterBundle($bundle); |
50 | self::useRegion($bundle, self::REGION); | |
51 | return $bundle; | |
52 | } | |
53 | ||
b2d8361e TO |
54 | /** |
55 | * The 'bundle.coreStyles' service is a collection of resources used on some | |
56 | * non-Civi pages (wherein Civi may be mixed-in). | |
57 | * | |
58 | * @param string $name | |
59 | * i.e. 'coreStyles' | |
60 | * @return \CRM_Core_Resources_Bundle | |
950538ac | 61 | * @see \Civi\Core\Container::createContainer() |
b2d8361e TO |
62 | */ |
63 | public static function createStyleBundle($name) { | |
64 | $bundle = new CRM_Core_Resources_Bundle($name); | |
5526ab4d TO |
65 | |
66 | // Load custom or core css | |
67 | $config = CRM_Core_Config::singleton(); | |
68 | if (!empty($config->customCSSURL)) { | |
69 | $customCSSURL = Civi::resources()->addCacheCode($config->customCSSURL); | |
70 | $bundle->addStyleUrl($customCSSURL, 99); | |
71 | } | |
72 | if (!Civi::settings()->get('disable_core_css')) { | |
73 | $bundle->addStyleFile('civicrm', 'css/civicrm.css', -99); | |
74 | } | |
75 | // crm-i.css added ahead of other styles so it can be overridden by FA. | |
76 | $bundle->addStyleFile('civicrm', 'css/crm-i.css', -101); | |
77 | ||
b2d8361e TO |
78 | CRM_Utils_Hook::alterBundle($bundle); |
79 | self::useRegion($bundle, self::REGION); | |
80 | return $bundle; | |
81 | } | |
82 | ||
83 | /** | |
84 | * The 'bundle.coreResources' service is a collection of resources | |
85 | * shared by Civi pages (ie pages where Civi controls rendering). | |
86 | * | |
87 | * @param string $name | |
88 | * i.e. 'coreResources' | |
89 | * @return \CRM_Core_Resources_Bundle | |
950538ac | 90 | * @see \Civi\Core\Container::createContainer() |
b2d8361e TO |
91 | */ |
92 | public static function createFullBundle($name) { | |
93 | $bundle = new CRM_Core_Resources_Bundle($name); | |
8d469336 TO |
94 | $config = CRM_Core_Config::singleton(); |
95 | ||
96 | // Add resources from coreResourceList | |
97 | $jsWeight = -9999; | |
98 | foreach (self::coreResourceList(self::REGION) as $item) { | |
99 | if (is_array($item)) { | |
100 | $bundle->addSetting($item); | |
101 | } | |
102 | elseif (strpos($item, '.css')) { | |
103 | Civi::resources()->isFullyFormedUrl($item) ? $bundle->addStyleUrl($item, -100) : $bundle->addStyleFile('civicrm', $item, -100); | |
104 | } | |
105 | elseif (Civi::resources()->isFullyFormedUrl($item)) { | |
106 | $bundle->addScriptUrl($item, $jsWeight++); | |
107 | } | |
108 | else { | |
109 | // Don't bother looking for ts() calls in packages, there aren't any | |
110 | $translate = (substr($item, 0, 3) == 'js/'); | |
111 | $bundle->addScriptFile('civicrm', $item, [ | |
112 | 'weight' => $jsWeight++, | |
113 | 'translate' => $translate, | |
114 | ]); | |
115 | } | |
116 | } | |
117 | // Add global settings | |
118 | $settings = [ | |
119 | 'config' => [ | |
120 | 'isFrontend' => $config->userFrameworkFrontend, | |
121 | ], | |
122 | ]; | |
123 | // Disable profile creation if user lacks permission | |
124 | if (!CRM_Core_Permission::check('edit all contacts') && !CRM_Core_Permission::check('add contacts')) { | |
125 | $settings['config']['entityRef']['contactCreate'] = FALSE; | |
126 | } | |
127 | $bundle->addSetting($settings); | |
128 | ||
129 | // Give control of jQuery and _ back to the CMS - this loads last | |
130 | $bundle->addScriptFile('civicrm', 'js/noconflict.js', [ | |
131 | 'weight' => 9999, | |
132 | 'translate' => FALSE, | |
133 | ]); | |
134 | ||
b2d8361e TO |
135 | CRM_Utils_Hook::alterBundle($bundle); |
136 | self::useRegion($bundle, self::REGION); | |
137 | return $bundle; | |
138 | } | |
139 | ||
8d469336 TO |
140 | /** |
141 | * List of core resources we add to every CiviCRM page. | |
142 | * | |
143 | * Note: non-compressed versions of .min files will be used in debug mode | |
144 | * | |
145 | * @param string $region | |
146 | * @return array | |
147 | */ | |
148 | protected static function coreResourceList($region) { | |
149 | $config = CRM_Core_Config::singleton(); | |
150 | ||
151 | // Scripts needed by everyone, everywhere | |
152 | // FIXME: This is too long; list needs finer-grained segmentation | |
153 | $items = [ | |
154 | "bower_components/jquery/dist/jquery.min.js", | |
155 | "bower_components/jquery-ui/jquery-ui.min.js", | |
156 | "bower_components/jquery-ui/themes/smoothness/jquery-ui.min.css", | |
157 | "bower_components/lodash-compat/lodash.min.js", | |
158 | "packages/jquery/plugins/jquery.mousewheel.min.js", | |
159 | "bower_components/select2/select2.min.js", | |
160 | "bower_components/select2/select2.min.css", | |
161 | "bower_components/font-awesome/css/font-awesome.min.css", | |
162 | "packages/jquery/plugins/jquery.form.min.js", | |
163 | "packages/jquery/plugins/jquery.timeentry.min.js", | |
164 | "packages/jquery/plugins/jquery.blockUI.min.js", | |
165 | "bower_components/datatables/media/js/jquery.dataTables.min.js", | |
166 | "bower_components/datatables/media/css/jquery.dataTables.min.css", | |
167 | "bower_components/jquery-validation/dist/jquery.validate.min.js", | |
168 | "bower_components/jquery-validation/dist/additional-methods.min.js", | |
169 | "packages/jquery/plugins/jquery.ui.datepicker.validation.min.js", | |
170 | "js/Common.js", | |
171 | "js/crm.datepicker.js", | |
172 | "js/crm.ajax.js", | |
173 | "js/wysiwyg/crm.wysiwyg.js", | |
174 | ]; | |
175 | ||
176 | // Dynamic localization script | |
177 | $items[] = Civi::resources()->addCacheCode( | |
178 | CRM_Utils_System::url('civicrm/ajax/l10n-js/' . CRM_Core_I18n::getLocale(), | |
179 | ['cid' => CRM_Core_Session::getLoggedInContactID()], FALSE, NULL, FALSE) | |
180 | ); | |
181 | ||
182 | // add wysiwyg editor | |
183 | $editor = Civi::settings()->get('editor_id'); | |
184 | if ($editor == "CKEditor") { | |
185 | CRM_Admin_Form_CKEditorConfig::setConfigDefault(); | |
186 | $items[] = [ | |
187 | 'config' => [ | |
188 | 'wysisygScriptLocation' => Civi::paths()->getUrl("[civicrm.root]/js/wysiwyg/crm.ckeditor.js"), | |
189 | 'CKEditorCustomConfig' => CRM_Admin_Form_CKEditorConfig::getConfigUrl(), | |
190 | ], | |
191 | ]; | |
192 | } | |
193 | ||
194 | // These scripts are only needed by back-office users | |
195 | if (CRM_Core_Permission::check('access CiviCRM')) { | |
196 | $items[] = "packages/jquery/plugins/jquery.tableHeader.js"; | |
197 | $items[] = "packages/jquery/plugins/jquery.notify.min.js"; | |
198 | } | |
199 | ||
200 | $contactID = CRM_Core_Session::getLoggedInContactID(); | |
201 | ||
202 | // Menubar | |
203 | $position = 'none'; | |
204 | if ( | |
205 | $contactID && !$config->userFrameworkFrontend | |
206 | && CRM_Core_Permission::check('access CiviCRM') | |
207 | && !@constant('CIVICRM_DISABLE_DEFAULT_MENU') | |
208 | && !CRM_Core_Config::isUpgradeMode() | |
209 | ) { | |
210 | $position = Civi::settings()->get('menubar_position') ?: 'over-cms-menu'; | |
211 | } | |
212 | if ($position !== 'none') { | |
213 | $items[] = 'bower_components/smartmenus/dist/jquery.smartmenus.min.js'; | |
214 | $items[] = 'bower_components/smartmenus/dist/addons/keyboard/jquery.smartmenus.keyboard.min.js'; | |
215 | $items[] = 'js/crm.menubar.js'; | |
216 | // @see CRM_Core_Resources::renderMenubarStylesheet | |
217 | $items[] = Civi::service('asset_builder')->getUrl('crm-menubar.css', [ | |
218 | 'menubarColor' => Civi::settings()->get('menubar_color'), | |
219 | 'height' => 40, | |
220 | 'breakpoint' => 768, | |
221 | ]); | |
222 | // Variables for crm.menubar.js | |
223 | $items[] = [ | |
224 | 'menubar' => [ | |
225 | 'position' => $position, | |
226 | 'qfKey' => CRM_Core_Key::get('CRM_Contact_Controller_Search', TRUE), | |
227 | 'cacheCode' => CRM_Core_BAO_Navigation::getCacheKey($contactID), | |
228 | ], | |
229 | ]; | |
230 | } | |
231 | ||
232 | // JS for multilingual installations | |
233 | if (!empty($config->languageLimit) && count($config->languageLimit) > 1 && CRM_Core_Permission::check('translate CiviCRM')) { | |
234 | $items[] = "js/crm.multilingual.js"; | |
235 | } | |
236 | ||
237 | // Enable administrators to edit option lists in a dialog | |
238 | if (CRM_Core_Permission::check('administer CiviCRM') && Civi::settings()->get('ajaxPopupsEnabled')) { | |
239 | $items[] = "js/crm.optionEdit.js"; | |
240 | } | |
241 | ||
242 | $tsLocale = CRM_Core_I18n::getLocale(); | |
243 | // Add localized jQuery UI files | |
244 | if ($tsLocale && $tsLocale != 'en_US') { | |
245 | // Search for i18n file in order of specificity (try fr-CA, then fr) | |
246 | list($lang) = explode('_', $tsLocale); | |
247 | $path = "bower_components/jquery-ui/ui/i18n"; | |
248 | foreach ([str_replace('_', '-', $tsLocale), $lang] as $language) { | |
249 | $localizationFile = "$path/datepicker-{$language}.js"; | |
250 | if (Civi::resources()->getPath('civicrm', $localizationFile)) { | |
251 | $items[] = $localizationFile; | |
252 | break; | |
253 | } | |
254 | } | |
255 | } | |
256 | ||
257 | // Allow hooks to modify this list | |
258 | CRM_Utils_Hook::coreResourceList($items, $region); | |
259 | ||
260 | // Oof, existing listeners would expect $items to typically begin with 'bower_components/' or 'packages/' | |
261 | // (using an implicit base of `[civicrm.root]`). We preserve the hook contract and cleanup $items post-hook. | |
262 | $map = [ | |
263 | 'bower_components' => rtrim(Civi::paths()->getUrl('[civicrm.bower]/.', 'absolute'), '/'), | |
264 | 'packages' => rtrim(Civi::paths()->getUrl('[civicrm.packages]/.', 'absolute'), '/'), | |
265 | ]; | |
266 | $filter = function($m) use ($map) { | |
267 | return $map[$m[1]] . $m[2]; | |
268 | }; | |
269 | $items = array_map(function($item) use ($filter) { | |
270 | return is_array($item) ? $item : preg_replace_callback(';^(bower_components|packages)(/.*);', $filter, $item); | |
271 | }, $items); | |
272 | ||
273 | return $items; | |
274 | } | |
275 | ||
b2d8361e TO |
276 | /** |
277 | * Ensure that all elements of the bundle are in the same region. | |
278 | * | |
279 | * @param CRM_Core_Resources_Bundle $bundle | |
280 | * @param string $region | |
281 | * @return CRM_Core_Resources_Bundle | |
282 | */ | |
283 | protected static function useRegion($bundle, $region) { | |
284 | $bundle->filter(function ($s) use ($region) { | |
285 | if ($s['type'] !== 'settings' && !isset($s['region'])) { | |
286 | $s['region'] = $region; | |
287 | } | |
288 | return $s; | |
289 | }); | |
290 | return $bundle; | |
291 | } | |
292 | ||
293 | } |