-
Notifications
You must be signed in to change notification settings - Fork 1
/
PicoUICard.php
195 lines (187 loc) · 8.13 KB
/
PicoUICard.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
<?php
/**
* Pico UI - Card
*
* A UI plugin for displaying card-style boxes. Typically used on an index page,
* or other types of menu pages.
*
* Note: The Card module is meant to work with Bootstrap's CSS classes for proper
* positioning. By default, it assumes you are already loading Bootstrap CSS/JS
* in your theme. If you are not, set config 'PicoUICard.loadBootstrap' to true,
* and the plugin will load Bootstrap from the official CDN.
*
* @author Bigi Lui
* @link https://github.com/bigicoin/PicoUI
* @license http://opensource.org/licenses/MIT The MIT License
* @version 1.0
*/
final class PicoUICard extends AbstractPicoPlugin
{
/**
* This plugin is enabled by default?
*
* @see AbstractPicoPlugin::$enabled
* @var boolean
*/
protected $enabled = false;
/**
* This plugin depends on ...
*
* @see AbstractPicoPlugin::$dependsOn
* @var string[]
*/
protected $dependsOn = array();
/**
* Stored config
*/
protected $config = array();
/**
* Triggered after Pico has read its configuration
*
* @see Pico::getConfig()
* @param array &$config array of config variables
* @return void
*/
public function onConfigLoaded(array &$config)
{
$this->config['loadBootstrap'] = false;
$this->config['cardRatio'] = '16:9';
$this->config['cardPosition'] = 'col-md-4 col-sm-6 col-xs-6';
$this->config['cardTitle'] = '';
$this->config['cardText'] = '';
// load custom config if needed
if (isset($config['PicoUICard.loadBootstrap'])) {
$this->config['loadBootstrap'] = $config['PicoUICard.loadBootstrap'];
}
if (isset($config['PicoUICard.cardRatio'])) {
$this->config['cardRatio'] = $config['PicoUICard.cardRatio'];
}
if (isset($config['PicoUICard.cssClass.cardPosition'])) {
$this->config['cardPosition'] = $config['PicoUICard.cssClass.cardPosition'];
}
if (isset($config['PicoUICard.cssClass.cardTitle'])) {
$this->config['cardTitle'] = $config['PicoUICard.cssClass.cardTitle'];
}
if (isset($config['PicoUICard.cssClass.cardText'])) {
$this->config['cardText'] = $config['PicoUICard.cssClass.cardText'];
}
// some postprocessing of config
list($cardWidth, $cardHeight) = explode(':', $this->config['cardRatio']);
$this->config['cardHeightMultiplier'] = max(0.01, min(floatval($cardHeight) / floatval($cardWidth), 10)) * 100;
}
/**
* Triggered after Pico has prepared the raw file contents for parsing
*
* @see Pico::parseFileContent()
* @see DummyPlugin::onContentParsed()
* @param string &$content prepared file contents for parsing
* @return void
*/
public function onContentPrepared(&$content)
{
// we only do any processing at all if the page contains our tag, so we save time
if (strpos($content, '[ui.card') !== false) {
// below is our comprehensive regex to detect for the full [ui.card] tag,
// which includes the tag and its attributes, and the [title] and [text] subtags.
$config = $this->config;
$content = preg_replace_callback(
'/\[ui\.card((\s+[a-z]+\=[\'\"][^\'\"]*[\'\"])*)\s*\]\s*((\[[a-z]+\][^\[]*\[\/[a-z]+\]\s*)*)\[\/ui\.card\s*\]/',
function ($matches) use ($config) {
// $matches[1] contain the list of attributes
// $matches[3] contain the list of subtags
preg_match_all('/\s*([a-z]+)\=[\'\"]([^\'\"]*)[\'\"]/', $matches[1], $attributes);
preg_match_all('/\[([a-z]+)\]([^\[]*)\[\/([a-z]+)\]\s*/', $matches[3], $subtags);
// look for what we want from attributes and subtags
$uicard = array('href' => '', 'img' => '', 'ratio' => '', 'title' => '', 'text' => '');
for ($i = 0; $i < count($attributes[0]); $i++) {
$uicard[ $attributes[1][$i] ] = $attributes[2][$i];
}
for ($i = 0; $i < count($subtags[0]); $i++) {
if ($subtags[1][$i] != $subtags[3][$i]) {
continue; // closing subtag must match in order to be valid
}
$uicard[ $subtags[1][$i] ] = $subtags[2][$i];
}
if (!empty($uicard['ratio'])) {
list($cardWidth, $cardHeight) = explode(':', $uicard['ratio']);
$cardRatio = ' padding-bottom: '.(max(0.01, min(floatval($cardHeight) / floatval($cardWidth), 10)) * 100).'%;';
} else {
$cardRatio = ''; // default
}
$result = '<!--OPEN_PICO_UI_CARD--><div class="row">';
$result .= '<a class="pico-ui-card-container_internal '.$config['cardPosition'].'" href="'.$uicard['href'].'">';
$result .= '<div class="pico-ui-card-background_internal" style="background: transparent url(\''.$uicard['img'].'\') no-repeat scroll; background-size: cover;'.$cardRatio.'">';
$result .= '<div class="pico-ui-card-gradient_internal">';
$result .= '<div class="pico-ui-card-title_internal '.$config['cardTitle'].'">';
$result .= $uicard['title'];
$result .= '</div>';
$result .= '</div>';
$result .= '</div>';
$result .= '<span class="pico-ui-card-text_internal '.$config['cardText'].'">';
$result .= $uicard['text'];
$result .= '</span>';
$result .= '</a>';
$result .= '</div><!--CLOSE_PICO_UI_CARD-->';
return $result;
},
$content);
// now properly combine continous ui cards into same row div
$content = preg_replace('/\<\/div\>\<\!\-\-CLOSE_PICO_UI_CARD\-\-\>\s*\<\!\-\-OPEN_PICO_UI_CARD\-\-\>\<div class\=\"row\"\>/', "\n\n", $content);
// now remove the extra comment tags that acted as our search string
$content = preg_replace('/\<\!\-\-(OPEN|CLOSE)_PICO_UI_CARD\-\-\>/', '', $content);
}
}
/**
* Triggered after Pico has rendered the page
*
* @param string &$output contents which will be sent to the user
* @return void
*/
public function onPageRendered(&$output)
{
// regular pages
// add css to end of <head>
$output = str_replace('</head>', ($this->buildExtraHeaders() . '</head>'), $output);
// add js to end of <body>
$output = str_replace('</body>', ($this->buildExtraFooters() . '</body>'), $output);
}
/**
* Add some extra header tags for our styling.
*/
private function buildExtraHeaders() {
$headers = '';
// if set to true, load from bootstrap cdn
if ($this->config['loadBootstrap'] === true) {
$headers .= PHP_EOL.'<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous" />';
}
// now set up card css classes
$headers .= '
<style type="text/css">
a.pico-ui-card-container_internal { display: block; padding: 10px; }
@media (max-width: 768px) { a.pico-ui-card-container_internal.col-xs-6:nth-child(2n+1) { clear: both; } }
@media (min-width: 769px) and (max-width: 992px) { a.pico-ui-card-container_internal.col-sm-6:nth-child(2n+1) { clear: both; } }
@media (min-width: 993px) { a.pico-ui-card-container_internal.col-md-4:nth-child(3n+1) { clear: both; } }
.pico-ui-card-background_internal { width: 100%; padding-bottom: '.$this->config['cardHeightMultiplier'].'%; border-radius: 5px; box-shadow: 2px 2px 1px 0px rgba(0,0,0,0.2); position: relative; }
.pico-ui-card-gradient_internal { border-radius: 5px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; background: linear-gradient(to bottom, rgba(0,0,0,0) 75%,rgba(0,0,0,0.8) 100%); }
.pico-ui-card-title_internal { position: absolute; bottom: 5px; left: 10px; font-size: 24px; color: #fff; }
@media (max-width:320px) { .pico-ui-card-title_internal { font-size: 16px; } }
@media (min-width:321px) and (max-width:639px) { .pico-ui-card-title_internal { font-size: 20px; } }
.pico-ui-card-text_internal { display: block; line-height: 100%; padding: 10px; font-size: 18px; color: #000; text-decoration: none; }
@media (max-width:320px) { .pico-ui-card-text_internal { font-size: 14px; } }
@media (min-width:321px) and (max-width:639px) { .pico-ui-card-text_internal { font-size: 16px; } }
</style>
';
return $headers;
}
/**
* Add some extra footer tags we need.
*/
private function buildExtraFooters() {
$footers = '';
// if set to true, load from bootstrap cdn
if ($this->config['loadBootstrap'] === true) {
$footers .= PHP_EOL.'<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>'.PHP_EOL;
}
return $footers;
}
}