Version 1
[yaffs-website] / web / themes / contrib / bootstrap / src / Plugin / Provider / JsDelivr.php
1 <?php
2 /**
3  * @file
4  * Contains \Drupal\bootstrap\Plugin\Provider\JsDelivr.
5  */
6
7 namespace Drupal\bootstrap\Plugin\Provider;
8
9 use Drupal\bootstrap\Annotation\BootstrapProvider;
10 use Drupal\bootstrap\Bootstrap;
11 use Drupal\Component\Utility\NestedArray;
12 use Drupal\Core\Annotation\Translation;
13
14 /**
15  * The "jsdelivr" CDN provider plugin.
16  *
17  * @ingroup plugins_provider
18  *
19  * @BootstrapProvider(
20  *   id = "jsdelivr",
21  *   label = @Translation("jsDelivr"),
22  *   api = "http://api.jsdelivr.com/v1/bootstrap/libraries",
23  *   themes = { },
24  *   versions = { },
25  * )
26  */
27 class JsDelivr extends ProviderBase {
28
29   /**
30    * Extracts theme information from files provided by the jsDelivr API.
31    *
32    * This will place the raw files into proper "css", "js" and "min" arrays
33    * (if they exist) and prepends them with a base URL provided.
34    *
35    * @param array $files
36    *   An array of files to process.
37    * @param string $base_url
38    *   The base URL each one of the $files are relative to, this usually
39    *   should also include the version path prefix as well.
40    *
41    * @return array
42    *   An associative array containing the following keys, if there were
43    *   matching files found:
44    *   - css
45    *   - js
46    *   - min:
47    *     - css
48    *     - js
49    */
50   protected function extractThemes(array $files, $base_url = '') {
51     $themes = [];
52     foreach ($files as $file) {
53       preg_match('`([^/]*)/bootstrap(-theme)?(\.min)?\.(js|css)$`', $file, $matches);
54       if (!empty($matches[1]) && !empty($matches[4])) {
55         $path = $matches[1];
56         $min = $matches[3];
57         $filetype = $matches[4];
58
59         // Determine the "theme" name.
60         if ($path === 'css' || $path === 'js') {
61           $theme = 'bootstrap';
62           $title = (string) t('Bootstrap');
63         }
64         else {
65           $theme = $path;
66           $title = ucfirst($path);
67         }
68         if ($matches[2]) {
69           $theme = 'bootstrap_theme';
70           $title = (string) t('Bootstrap Theme');
71         }
72
73         $themes[$theme]['title'] = $title;
74         if ($min) {
75           $themes[$theme]['min'][$filetype][] = "$base_url/$path/bootstrap{$matches[2]}$min.$filetype";
76         }
77         else {
78           $themes[$theme][$filetype][] = "$base_url/$path/bootstrap{$matches[2]}$min.$filetype";
79         }
80       }
81     }
82     return $themes;
83   }
84
85   /**
86    * {@inheritdoc}
87    */
88   public function getAssets($types = NULL) {
89     $this->assets = [];
90     $error = !empty($provider['error']);
91     $version = $error ? Bootstrap::FRAMEWORK_VERSION : $this->theme->getSetting('cdn_jsdelivr_version');
92     $theme = $error ? 'bootstrap' : $this->theme->getSetting('cdn_jsdelivr_theme');
93     if (isset($this->pluginDefinition['themes'][$version][$theme])) {
94       $this->assets = $this->pluginDefinition['themes'][$version][$theme];
95     }
96     return parent::getAssets($types);
97   }
98
99   /**
100    * {@inheritdoc}
101    */
102   public function processApi(array $json, array &$definition) {
103     $definition['description'] = t('<p style="background:#EB4C36"><a href=":jsdelivr" target="_blank"><img src="http://www.jsdelivr.com/img/logo-34.png" alt="jsDelivr Logo"/></a></p><p><a href=":jsdelivr" target="_blank">jsDelivr</a> is a free multi-CDN infrastructure that uses <a href=":maxcdn" target="_blank">MaxCDN</a>, <a href=":cloudflare" target="_blank">Cloudflare</a> and many others to combine their powers for the good of the open source community... <a href=":jsdelivr_about" target="_blank">read more</a></p>', [
104       ':jsdelivr' => 'http://www.jsdelivr.com',
105       ':jsdelivr_about' => 'http://www.jsdelivr.com/about',
106       ':maxcdn' => 'http://www.maxcdn.com',
107       ':cloudflare' => 'http://www.cloudflare.com',
108     ]);
109
110     // Expected library names from jsDelivr API v1. Must use "twitter-bootstrap"
111     // instead of "bootstrap" (which is just a directory alias).
112     // @see https://www.drupal.org/node/2504343
113     // @see https://github.com/jsdelivr/api/issues/94
114     $bootstrap = 'twitter-bootstrap';
115     $bootswatch = 'bootswatch';
116
117     // Extract the raw asset files from the JSON data for each framework.
118     $libraries = [];
119     if ($json) {
120       foreach ($json as $data) {
121         if ($data['name'] === $bootstrap || $data['name'] === $bootswatch) {
122           foreach ($data['assets'] as $asset) {
123             if (preg_match('/^' . substr(Bootstrap::FRAMEWORK_VERSION, 0, 1) . '\.\d\.\d$/', $asset['version'])) {
124               $libraries[$data['name']][$asset['version']] = $asset['files'];
125             }
126           }
127         }
128       }
129     }
130
131     // If the main bootstrap library could not be found, then provide defaults.
132     if (!isset($libraries[$bootstrap])) {
133       $definition['error'] = TRUE;
134       $definition['versions'][Bootstrap::FRAMEWORK_VERSION] = Bootstrap::FRAMEWORK_VERSION;
135       $definition['themes'][Bootstrap::FRAMEWORK_VERSION] = [
136         'bootstrap' => [
137           'title' => (string) t('Bootstrap'),
138           'css' => ['//cdn.jsdelivr.net/bootstrap/' . Bootstrap::FRAMEWORK_VERSION . '/css/bootstrap.css'],
139           'js' => ['//cdn.jsdelivr.net/bootstrap/' . Bootstrap::FRAMEWORK_VERSION . '/js/bootstrap.js'],
140           'min' => [
141             'css' => ['//cdn.jsdelivr.net/bootstrap/' . Bootstrap::FRAMEWORK_VERSION . '/css/bootstrap.min.css'],
142             'js' => ['//cdn.jsdelivr.net/bootstrap/' . Bootstrap::FRAMEWORK_VERSION . '/js/bootstrap.min.js'],
143           ],
144         ],
145       ];
146       return;
147     }
148
149     // Populate the provider array with the versions and themes available.
150     foreach (array_keys($libraries[$bootstrap]) as $version) {
151       $definition['versions'][$version] = $version;
152
153       if (!isset($definition['themes'][$version])) {
154         $definition['themes'][$version] = [];
155       }
156
157       // Extract Bootstrap themes.
158       $definition['themes'][$version] = NestedArray::mergeDeep($definition['themes'][$version], $this->extractThemes($libraries[$bootstrap][$version], "//cdn.jsdelivr.net/bootstrap/$version"));
159
160       // Extract Bootswatch themes.
161       if (isset($libraries[$bootswatch][$version])) {
162         $definition['themes'][$version] = NestedArray::mergeDeep($definition['themes'][$version], $this->extractThemes($libraries[$bootswatch][$version], "//cdn.jsdelivr.net/bootswatch/$version"));
163       }
164     }
165
166     // Post process the themes to fill in any missing assets.
167     foreach (array_keys($definition['themes']) as $version) {
168       foreach (array_keys($definition['themes'][$version]) as $theme) {
169         // Some themes actually require Bootstrap framework assets to still
170         // function properly.
171         if ($theme !== 'bootstrap') {
172           foreach (['css', 'js'] as $type) {
173             // Bootswatch themes include the Bootstrap framework in their CSS.
174             // Skip the CSS portions.
175             if ($theme !== 'bootstrap_theme' && $type === 'css') {
176               continue;
177             }
178             if (!isset($definition['themes'][$version][$theme][$type]) && !empty($definition['themes'][$version]['bootstrap'][$type])) {
179               $definition['themes'][$version][$theme][$type] = [];
180             }
181             $definition['themes'][$version][$theme][$type] = NestedArray::mergeDeep($definition['themes'][$version]['bootstrap'][$type], $definition['themes'][$version][$theme][$type]);
182             if (!isset($definition['themes'][$version][$theme]['min'][$type]) && !empty($definition['themes'][$version]['bootstrap']['min'][$type])) {
183               $definition['themes'][$version][$theme]['min'][$type] = [];
184             }
185             $definition['themes'][$version][$theme]['min'][$type] = NestedArray::mergeDeep($definition['themes'][$version]['bootstrap']['min'][$type], $definition['themes'][$version][$theme]['min'][$type]);
186           }
187         }
188         // Some themes do not have a non-minified version, clone them to the
189         // "normal" css/js arrays to ensure that the theme still loads if
190         // aggregation (minification) is disabled.
191         foreach (['css', 'js'] as $type) {
192           if (!isset($definition['themes'][$version][$theme][$type]) && isset($definition['themes'][$version][$theme]['min'][$type])) {
193             $definition['themes'][$version][$theme][$type] = $definition['themes'][$version][$theme]['min'][$type];
194           }
195         }
196       }
197     }
198   }
199
200 }