Version Description
(06.04.2020) =
- RSS- .
- .
- 64k .
- ( ).
- "yturbo_before_ads" - .
- - WPCase: Turbo Ads.
Download this release
Release Info
Developer | Flector |
Plugin | RSS for Yandex Turbo |
Version | 1.27 |
Comparing to | |
See all releases |
Code changes from version 1.26 to 1.27
- inc/AdminNotice.php +609 -0
- inc/{class-Kama_Contents.php → Contents.php} +31 -28
- inc/animate.min.css +0 -11
- inc/dismiss-notice.js +18 -0
- inc/jquery.lettering.js +0 -72
- inc/jquery.textillate.js +0 -289
- inc/tagify.css +1 -0
- inc/tagify.js +2193 -0
- inc/yturbo-css.css +73 -0
- inc/yturbo-script.js +132 -32
- readme.txt +34 -3
- rss-for-yandex-turbo.php +311 -92
inc/AdminNotice.php
ADDED
@@ -0,0 +1,609 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace YTurboAdminNotices;
|
3 |
+
|
4 |
+
if (!class_exists(__NAMESPACE__ . '\\AdminNotice', false)) {
|
5 |
+
|
6 |
+
class AdminNotice {
|
7 |
+
const TYPE_SUCCESS = 'success';
|
8 |
+
const TYPE_INFO = 'info';
|
9 |
+
const TYPE_WARNING = 'warning';
|
10 |
+
const TYPE_ERROR = 'error';
|
11 |
+
|
12 |
+
const DISMISS_PER_USER = 'user';
|
13 |
+
const DISMISS_PER_SITE = 'site';
|
14 |
+
const DISMISS_PERMANENTLY = 3153600000; //100 years in seconds.
|
15 |
+
const DISMISS_ACTION_PREFIX = 'ye_v1_dismiss-';
|
16 |
+
|
17 |
+
const DISMISSED_OPTION_PREFIX = 'ye_is_dismissed-';
|
18 |
+
const DELAYED_NOTICE_OPTION = 'ye_delayed_notices';
|
19 |
+
|
20 |
+
protected $id = null;
|
21 |
+
protected $content = '';
|
22 |
+
protected $noticeType = 'success';
|
23 |
+
protected $customCssClasses = array();
|
24 |
+
|
25 |
+
protected $allowedScreens = array();
|
26 |
+
protected $requiredCapability = null;
|
27 |
+
|
28 |
+
protected $isDismissible = false;
|
29 |
+
protected $isPersistentlyDismissible = false;
|
30 |
+
protected $dismissionScope = self::DISMISS_PER_SITE;
|
31 |
+
protected $dismissalDuration = self::DISMISS_PERMANENTLY;
|
32 |
+
|
33 |
+
public function __construct($id = null) {
|
34 |
+
$this->id = $id;
|
35 |
+
}
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Create a new notice.
|
39 |
+
*
|
40 |
+
* @param string $id
|
41 |
+
* @return AdminNotice
|
42 |
+
*/
|
43 |
+
public static function create($id = null) {
|
44 |
+
return new static($id);
|
45 |
+
}
|
46 |
+
|
47 |
+
public function text($message) {
|
48 |
+
$this->content = '<p>' . esc_html($message) . '</p>';
|
49 |
+
return $this;
|
50 |
+
}
|
51 |
+
|
52 |
+
public function html($arbitraryHtml) {
|
53 |
+
$this->content = '<p>' . $arbitraryHtml . '</p>';
|
54 |
+
return $this;
|
55 |
+
}
|
56 |
+
|
57 |
+
public function rawHtml($arbitraryHtml) {
|
58 |
+
$this->content = $arbitraryHtml;
|
59 |
+
return $this;
|
60 |
+
}
|
61 |
+
|
62 |
+
public function getHtmlContent() {
|
63 |
+
return $this->content;
|
64 |
+
}
|
65 |
+
|
66 |
+
public function type($noticeType) {
|
67 |
+
$this->noticeType = $noticeType;
|
68 |
+
return $this;
|
69 |
+
}
|
70 |
+
|
71 |
+
public function success($messageHtml = null) {
|
72 |
+
return $this->setTypeAndMessage(self::TYPE_SUCCESS, $messageHtml);
|
73 |
+
}
|
74 |
+
|
75 |
+
public function info($messageHtml = null) {
|
76 |
+
return $this->setTypeAndMessage(self::TYPE_INFO, $messageHtml);
|
77 |
+
}
|
78 |
+
|
79 |
+
public function warning($messageHtml = null) {
|
80 |
+
return $this->setTypeAndMessage(self::TYPE_WARNING, $messageHtml);
|
81 |
+
}
|
82 |
+
|
83 |
+
public function error($messageHtml = null) {
|
84 |
+
return $this->setTypeAndMessage(self::TYPE_ERROR, $messageHtml);
|
85 |
+
}
|
86 |
+
|
87 |
+
protected function setTypeAndMessage($noticeType, $messageHtml = null) {
|
88 |
+
$this->noticeType = $noticeType;
|
89 |
+
if (isset($messageHtml)) {
|
90 |
+
$this->html($messageHtml);
|
91 |
+
}
|
92 |
+
return $this;
|
93 |
+
}
|
94 |
+
|
95 |
+
public function addClass($className) {
|
96 |
+
if (is_array($className)) {
|
97 |
+
$className = implode(' ', $className);
|
98 |
+
}
|
99 |
+
$this->customCssClasses[] = $className;
|
100 |
+
return $this;
|
101 |
+
}
|
102 |
+
|
103 |
+
/**
|
104 |
+
* Make the notice dismissible.
|
105 |
+
*
|
106 |
+
* @return $this
|
107 |
+
*/
|
108 |
+
public function dismissible() {
|
109 |
+
$this->isDismissible = true;
|
110 |
+
return $this;
|
111 |
+
}
|
112 |
+
|
113 |
+
/**
|
114 |
+
* When the user dismisses the notice, remember that and don't show it again.
|
115 |
+
*
|
116 |
+
* @param string $scope
|
117 |
+
* @param int $duration How long (in seconds) the notice should be considered dismissed for.
|
118 |
+
* @return $this
|
119 |
+
*/
|
120 |
+
public function persistentlyDismissible($scope = self::DISMISS_PER_SITE, $duration = self::DISMISS_PERMANENTLY) {
|
121 |
+
if (empty($this->id)) {
|
122 |
+
throw new \LogicException('Persistently dismissible notices must have a unique ID.');
|
123 |
+
}
|
124 |
+
|
125 |
+
$this->isDismissible = true;
|
126 |
+
$this->isPersistentlyDismissible = true;
|
127 |
+
$this->dismissionScope = $scope;
|
128 |
+
$this->dismissalDuration = $duration;
|
129 |
+
|
130 |
+
$ajaxCallback = array($this, 'ajaxDismiss');
|
131 |
+
if (has_action($this->getDismissActionName(), $ajaxCallback) === false) {
|
132 |
+
add_action('wp_ajax_' . $this->getDismissActionName(), $ajaxCallback);
|
133 |
+
}
|
134 |
+
|
135 |
+
return $this;
|
136 |
+
}
|
137 |
+
|
138 |
+
/**
|
139 |
+
* Only show the notice on the specified admin page(s).
|
140 |
+
*
|
141 |
+
* @link https://codex.wordpress.org/Plugin_API/Admin_Screen_Reference
|
142 |
+
*
|
143 |
+
* @param string|string[] $screenId
|
144 |
+
* @return $this
|
145 |
+
*/
|
146 |
+
public function onPage($screenId) {
|
147 |
+
$this->allowedScreens = array_merge($this->allowedScreens, (array)$screenId);
|
148 |
+
return $this;
|
149 |
+
}
|
150 |
+
|
151 |
+
/**
|
152 |
+
* Get the current screen ID.
|
153 |
+
*
|
154 |
+
* @return null|string
|
155 |
+
*/
|
156 |
+
private function getCurrentScreenId() {
|
157 |
+
if (!function_exists('get_current_screen')) {
|
158 |
+
return null;
|
159 |
+
}
|
160 |
+
|
161 |
+
$screen = \get_current_screen();
|
162 |
+
if ($screen === null) {
|
163 |
+
return null;
|
164 |
+
}
|
165 |
+
return $screen->id;
|
166 |
+
}
|
167 |
+
|
168 |
+
/**
|
169 |
+
* Only show this notice to users that have the specified capability.
|
170 |
+
*
|
171 |
+
* @param string|null $capability
|
172 |
+
* @return $this
|
173 |
+
*/
|
174 |
+
public function requiredCap($capability) {
|
175 |
+
$this->requiredCapability = $capability;
|
176 |
+
return $this;
|
177 |
+
}
|
178 |
+
|
179 |
+
/**
|
180 |
+
* Show the notice on the current page when all preconditions are met.
|
181 |
+
*/
|
182 |
+
public function show() {
|
183 |
+
if (did_action('admin_notices')) {
|
184 |
+
$this->maybeOutputNotice();
|
185 |
+
} else {
|
186 |
+
add_action('admin_notices', array($this, 'maybeOutputNotice'));
|
187 |
+
}
|
188 |
+
return $this;
|
189 |
+
}
|
190 |
+
|
191 |
+
/**
|
192 |
+
* Immediately output the notice unless it has been dismissed.
|
193 |
+
*
|
194 |
+
* @internal
|
195 |
+
*/
|
196 |
+
public function maybeOutputNotice() {
|
197 |
+
if (isset($this->requiredCapability) && !current_user_can($this->requiredCapability)) {
|
198 |
+
return;
|
199 |
+
}
|
200 |
+
|
201 |
+
if (!empty($this->allowedScreens) && !in_array($this->getCurrentScreenId(), $this->allowedScreens)) {
|
202 |
+
return;
|
203 |
+
}
|
204 |
+
|
205 |
+
if ($this->isDismissed()) {
|
206 |
+
return;
|
207 |
+
}
|
208 |
+
$this->outputNotice();
|
209 |
+
}
|
210 |
+
|
211 |
+
/**
|
212 |
+
* Output the notice.
|
213 |
+
*/
|
214 |
+
public function outputNotice() {
|
215 |
+
$classes = array_merge(
|
216 |
+
array('notice', 'notice-' . $this->noticeType),
|
217 |
+
$this->customCssClasses
|
218 |
+
);
|
219 |
+
|
220 |
+
if ($this->isDismissible) {
|
221 |
+
$classes[] = 'is-dismissible';
|
222 |
+
}
|
223 |
+
|
224 |
+
$attributes = array(
|
225 |
+
'id' => $this->id,
|
226 |
+
'class' => implode(' ', $classes),
|
227 |
+
);
|
228 |
+
|
229 |
+
if ($this->isPersistentlyDismissible) {
|
230 |
+
$attributes['data-ye-dismiss-nonce'] = wp_create_nonce($this->getDismissActionName());
|
231 |
+
|
232 |
+
$attributes['data-ye-notice-data'] = $this->toJson();
|
233 |
+
$attributes['data-ye-signature'] = wp_create_nonce(
|
234 |
+
$this->id . '|' . $attributes['data-ye-dismiss-nonce'] . '|' . $attributes['data-ye-notice-data']
|
235 |
+
);
|
236 |
+
|
237 |
+
$this->enqueueScriptOnce();
|
238 |
+
}
|
239 |
+
|
240 |
+
/** @noinspection HtmlUnknownAttribute */
|
241 |
+
printf(
|
242 |
+
'<div %1$s>%2$s</div>',
|
243 |
+
$this->formatTagAttributes($attributes),
|
244 |
+
$this->content
|
245 |
+
);
|
246 |
+
}
|
247 |
+
|
248 |
+
protected function enqueueScriptOnce() {
|
249 |
+
if (!wp_script_is('ye-dismiss-notice', 'registered')) {
|
250 |
+
//Note: Queueing a script also registers it.
|
251 |
+
wp_enqueue_script(
|
252 |
+
'ye-dismiss-notice',
|
253 |
+
plugins_url('dismiss-notice.js', __FILE__),
|
254 |
+
array('jquery'),
|
255 |
+
'20170318',
|
256 |
+
true
|
257 |
+
);
|
258 |
+
}
|
259 |
+
}
|
260 |
+
|
261 |
+
protected function formatTagAttributes($attributes) {
|
262 |
+
$attributePairs = array();
|
263 |
+
foreach ($attributes as $name => $value) {
|
264 |
+
if (isset($value)) {
|
265 |
+
$attributePairs[] = $name . '="' . esc_attr($value) . '"';
|
266 |
+
}
|
267 |
+
}
|
268 |
+
return implode(' ', $attributePairs);
|
269 |
+
}
|
270 |
+
|
271 |
+
/**
|
272 |
+
* Show the notice on the next admin page that's visited by the current user.
|
273 |
+
* The notice will be shown only once.
|
274 |
+
*
|
275 |
+
* More accurately, this shows the notice the next time the admin_notices hook is called
|
276 |
+
* in the context of the current user, whether that happens during this page load or the next,
|
277 |
+
* or a week later. The intended use is for form handlers that redirect to another page, plugin
|
278 |
+
* activation hooks and other callbacks that can't display a notice in the usual way.
|
279 |
+
*
|
280 |
+
* @return self
|
281 |
+
*/
|
282 |
+
public function showOnNextPage() {
|
283 |
+
if (!is_user_logged_in()) {
|
284 |
+
return $this;
|
285 |
+
}
|
286 |
+
|
287 |
+
//Schedule the notice to appear on the next page.
|
288 |
+
add_user_meta(
|
289 |
+
get_current_user_id(),
|
290 |
+
static::DELAYED_NOTICE_OPTION,
|
291 |
+
wp_slash($this->toJson()),
|
292 |
+
false
|
293 |
+
);
|
294 |
+
|
295 |
+
return $this;
|
296 |
+
}
|
297 |
+
|
298 |
+
/**
|
299 |
+
* Display delayed notices stored by showOnNextPage.
|
300 |
+
*
|
301 |
+
* @internal
|
302 |
+
*/
|
303 |
+
public static function _showDelayedNotices() {
|
304 |
+
$userId = get_current_user_id();
|
305 |
+
$notices = get_user_meta($userId, static::DELAYED_NOTICE_OPTION, false);
|
306 |
+
if (empty($notices)) {
|
307 |
+
return;
|
308 |
+
}
|
309 |
+
|
310 |
+
foreach ($notices as $json) {
|
311 |
+
$notice = static::tryUnserializeNotice($json);
|
312 |
+
if (isset($notice)) {
|
313 |
+
$notice->show();
|
314 |
+
|
315 |
+
//Only show the notice once.
|
316 |
+
delete_user_meta($userId, static::DELAYED_NOTICE_OPTION, wp_slash($json));
|
317 |
+
}
|
318 |
+
}
|
319 |
+
}
|
320 |
+
|
321 |
+
/**
|
322 |
+
* Attempt to unserialize a notice from JSON.
|
323 |
+
*
|
324 |
+
* @internal
|
325 |
+
* @param string $json
|
326 |
+
* @return null|static
|
327 |
+
*/
|
328 |
+
protected static function tryUnserializeNotice($json) {
|
329 |
+
$properties = json_decode($json, true);
|
330 |
+
if (!is_array($properties)) {
|
331 |
+
return null;
|
332 |
+
}
|
333 |
+
|
334 |
+
//Ignore notices created by other versions of this class.
|
335 |
+
if (self::getKey($properties, '_className') !== get_called_class()) {
|
336 |
+
return null;
|
337 |
+
}
|
338 |
+
|
339 |
+
return static::fromJson($json);
|
340 |
+
}
|
341 |
+
|
342 |
+
/**
|
343 |
+
* Serialize the notice as JSON.
|
344 |
+
*
|
345 |
+
* @return string
|
346 |
+
*/
|
347 |
+
public function toJson() {
|
348 |
+
$data = array(
|
349 |
+
'id' => $this->id,
|
350 |
+
'content' => $this->content,
|
351 |
+
'noticeType' => $this->noticeType,
|
352 |
+
'isDismissible' => $this->isDismissible,
|
353 |
+
'isPersistentlyDismissible' => $this->isPersistentlyDismissible,
|
354 |
+
'dismissionScope' => $this->dismissionScope,
|
355 |
+
'dismissalDuration' => $this->dismissalDuration,
|
356 |
+
'customCssClasses' => $this->customCssClasses,
|
357 |
+
'allowedScreens' => $this->allowedScreens,
|
358 |
+
'requiredCapability' => $this->requiredCapability,
|
359 |
+
'_className' => get_class($this),
|
360 |
+
);
|
361 |
+
|
362 |
+
return json_encode($data);
|
363 |
+
}
|
364 |
+
|
365 |
+
/**
|
366 |
+
* Load a notice from JSON.
|
367 |
+
*
|
368 |
+
* @param string $json
|
369 |
+
* @return AdminNotice
|
370 |
+
*/
|
371 |
+
public static function fromJson($json) {
|
372 |
+
$properties = json_decode($json, true);
|
373 |
+
|
374 |
+
$notice = new static($properties['id']);
|
375 |
+
$notice->rawHtml($properties['content']);
|
376 |
+
$notice->type($properties['noticeType']);
|
377 |
+
$notice->addClass($properties['customCssClasses']);
|
378 |
+
$notice->onPage(self::getKey($properties, 'allowedScreens', array()));
|
379 |
+
$notice->requiredCap(self::getKey($properties, 'requiredCapability'));
|
380 |
+
|
381 |
+
if ($properties['isDismissible']) {
|
382 |
+
$notice->dismissible();
|
383 |
+
}
|
384 |
+
if ($properties['isPersistentlyDismissible']) {
|
385 |
+
$notice->persistentlyDismissible(
|
386 |
+
self::getKey($properties, 'dismissionScope', self::DISMISS_PER_SITE),
|
387 |
+
self::getKey($properties, 'dismissalDuration', self::DISMISS_PERMANENTLY)
|
388 |
+
);
|
389 |
+
}
|
390 |
+
|
391 |
+
return $notice;
|
392 |
+
}
|
393 |
+
|
394 |
+
/**
|
395 |
+
* @param array $array
|
396 |
+
* @param string $key
|
397 |
+
* @param mixed $defaultValue
|
398 |
+
* @return mixed
|
399 |
+
*/
|
400 |
+
protected static function getKey($array, $key, $defaultValue = null) {
|
401 |
+
if (array_key_exists($key, $array)) {
|
402 |
+
return $array[$key];
|
403 |
+
}
|
404 |
+
return $defaultValue;
|
405 |
+
}
|
406 |
+
|
407 |
+
/**
|
408 |
+
* Process an AJAX request to dismiss this notice.
|
409 |
+
*
|
410 |
+
* @internal
|
411 |
+
*/
|
412 |
+
public function ajaxDismiss() {
|
413 |
+
check_ajax_referer($this->getDismissActionName());
|
414 |
+
|
415 |
+
if (!is_user_logged_in()) {
|
416 |
+
wp_die('Access denied. You need to be logged in to dismiss notices.');
|
417 |
+
return;
|
418 |
+
}
|
419 |
+
|
420 |
+
if (isset($this->requiredCapability) && !current_user_can($this->requiredCapability)) {
|
421 |
+
wp_die('Access denied. You don\'t have the required capability to dismiss this notice.');
|
422 |
+
return;
|
423 |
+
}
|
424 |
+
|
425 |
+
$this->dismiss();
|
426 |
+
exit('Notice dismissed');
|
427 |
+
}
|
428 |
+
|
429 |
+
/**
|
430 |
+
* Dismiss a notice.
|
431 |
+
*
|
432 |
+
* @param int $duration How long (in seconds) the notice should be considered dismissed for.
|
433 |
+
* By default, the duration is the same as the duration
|
434 |
+
* passed to {@see self::persistentlyDismissible()}.
|
435 |
+
* You can also pass {@see self::DISMISS_PERMANENTLY}.
|
436 |
+
* @return self
|
437 |
+
*/
|
438 |
+
public function dismiss($duration = null) {
|
439 |
+
if (!$this->isPersistentlyDismissible) {
|
440 |
+
return $this;
|
441 |
+
}
|
442 |
+
|
443 |
+
$dismissal = json_encode(array(
|
444 |
+
'dismissalTime' => time(),
|
445 |
+
'dismissalDuration' => $duration,
|
446 |
+
));
|
447 |
+
|
448 |
+
if ($this->dismissionScope === self::DISMISS_PER_SITE) {
|
449 |
+
update_option($this->getDismissOptionName(), $dismissal);
|
450 |
+
} else {
|
451 |
+
update_user_meta(get_current_user_id(), $this->getDismissOptionName(), $dismissal);
|
452 |
+
}
|
453 |
+
|
454 |
+
return $this;
|
455 |
+
}
|
456 |
+
|
457 |
+
public function undismiss($scope = self::DISMISS_PER_SITE) {
|
458 |
+
if (!$this->isPersistentlyDismissible) {
|
459 |
+
return $this;
|
460 |
+
}
|
461 |
+
|
462 |
+
if ($this->dismissionScope === self::DISMISS_PER_SITE) {
|
463 |
+
delete_option($this->getDismissOptionName());
|
464 |
+
} else {
|
465 |
+
if ($scope === self::DISMISS_PER_SITE) {
|
466 |
+
//Un-dismiss it for all users.
|
467 |
+
delete_metadata('user', 0, $this->getDismissOptionName(), '', true);
|
468 |
+
} else {
|
469 |
+
//Un-dismiss just for the current user.
|
470 |
+
delete_user_meta(get_current_user_id(), $this->getDismissOptionName());
|
471 |
+
}
|
472 |
+
}
|
473 |
+
|
474 |
+
return $this;
|
475 |
+
}
|
476 |
+
|
477 |
+
/**
|
478 |
+
* Delete all "dismissed" flags that have the specified prefix.
|
479 |
+
*
|
480 |
+
* @param string $prefix
|
481 |
+
*/
|
482 |
+
public static function cleanUpDatabase($prefix) {
|
483 |
+
global $wpdb;
|
484 |
+
/** @var \wpdb $wpdb */
|
485 |
+
$escapedPrefix = esc_sql($wpdb->esc_like(static::DISMISSED_OPTION_PREFIX . $prefix) . '%');
|
486 |
+
|
487 |
+
if (!is_string($escapedPrefix) || (strlen($escapedPrefix) < 2)) {
|
488 |
+
throw new \LogicException('Prefix must not be empty.'); //This should never happen.
|
489 |
+
}
|
490 |
+
|
491 |
+
$wpdb->query(sprintf(
|
492 |
+
'DELETE FROM %s WHERE option_name LIKE "%s"',
|
493 |
+
$wpdb->options,
|
494 |
+
$escapedPrefix
|
495 |
+
));
|
496 |
+
$wpdb->query(sprintf(
|
497 |
+
'DELETE FROM %s WHERE meta_key LIKE "%s"',
|
498 |
+
$wpdb->usermeta,
|
499 |
+
$escapedPrefix
|
500 |
+
));
|
501 |
+
}
|
502 |
+
|
503 |
+
public function isDismissed() {
|
504 |
+
if (!$this->isPersistentlyDismissible) {
|
505 |
+
return false;
|
506 |
+
}
|
507 |
+
|
508 |
+
if ($this->dismissionScope === self::DISMISS_PER_SITE) {
|
509 |
+
$dismissal = get_option($this->getDismissOptionName());
|
510 |
+
} else {
|
511 |
+
$dismissal = get_user_meta(get_current_user_id(), $this->getDismissOptionName(), true);
|
512 |
+
}
|
513 |
+
|
514 |
+
$dismissal = is_string($dismissal) ? json_decode($dismissal, true) : false;
|
515 |
+
|
516 |
+
if (!$dismissal) {
|
517 |
+
return false;
|
518 |
+
}
|
519 |
+
|
520 |
+
// If the library has been updated from version 1.0, then the dismiss option
|
521 |
+
// will contain '1' instead of the dismissal time. The best we can do
|
522 |
+
// in this case is set the dismissal time to the current time so that
|
523 |
+
// the notice can at least eventually be undismissed.
|
524 |
+
if ($dismissal === 1) {
|
525 |
+
$this->dismiss();
|
526 |
+
|
527 |
+
return true;
|
528 |
+
}
|
529 |
+
|
530 |
+
return time() < $dismissal['dismissalTime'] + ($dismissal['dismissalDuration'] ?: $this->dismissalDuration);
|
531 |
+
}
|
532 |
+
|
533 |
+
protected function getDismissActionName() {
|
534 |
+
return self::DISMISS_ACTION_PREFIX . $this->id;
|
535 |
+
}
|
536 |
+
|
537 |
+
protected function getDismissOptionName() {
|
538 |
+
return static::DISMISSED_OPTION_PREFIX . $this->id;
|
539 |
+
}
|
540 |
+
|
541 |
+
/**
|
542 |
+
* @internal
|
543 |
+
*/
|
544 |
+
public static function _ajaxAddDismissalHandler() {
|
545 |
+
if (!self::isUnhandledAjaxAction()) {
|
546 |
+
return;
|
547 |
+
}
|
548 |
+
|
549 |
+
$id = substr($_POST['action'], strlen(self::DISMISS_ACTION_PREFIX));
|
550 |
+
$ajaxNonce = strval($_POST['_ajax_nonce']);
|
551 |
+
$json = strval(wp_unslash($_POST['notice-data']));
|
552 |
+
if (!wp_verify_nonce($_POST['signature'], $id . '|' . $ajaxNonce . '|' . $json)) {
|
553 |
+
return;
|
554 |
+
}
|
555 |
+
|
556 |
+
//The notice will automatically set an AJAX hook when it gets unserialized.
|
557 |
+
self::tryUnserializeNotice($json);
|
558 |
+
}
|
559 |
+
|
560 |
+
/**
|
561 |
+
* Is this a "dismiss notice" AJAX request without a registered action callback?
|
562 |
+
*
|
563 |
+
* @internal
|
564 |
+
* @return bool
|
565 |
+
*/
|
566 |
+
protected static function isUnhandledAjaxAction() {
|
567 |
+
$doingAjax = defined('DOING_AJAX') && constant('DOING_AJAX');
|
568 |
+
if (!$doingAjax) {
|
569 |
+
return false;
|
570 |
+
}
|
571 |
+
|
572 |
+
$requiredParams = array('action', 'notice-data', 'signature', '_ajax_nonce');
|
573 |
+
foreach($requiredParams as $param) {
|
574 |
+
if (empty($_POST[$param]) || !is_string($_POST[$param])) {
|
575 |
+
return false;
|
576 |
+
}
|
577 |
+
}
|
578 |
+
|
579 |
+
$action = $_POST['action'];
|
580 |
+
if (has_action('wp_ajax_' . $action) === true) {
|
581 |
+
return false;
|
582 |
+
}
|
583 |
+
|
584 |
+
$isDismissAction = self::stringStartsWith($action, self::DISMISS_ACTION_PREFIX)
|
585 |
+
&& (strlen($action) > strlen(self::DISMISS_ACTION_PREFIX));
|
586 |
+
return $isDismissAction;
|
587 |
+
}
|
588 |
+
|
589 |
+
protected static function stringStartsWith($input, $prefix) {
|
590 |
+
return substr($input, 0, strlen($prefix)) === $prefix;
|
591 |
+
}
|
592 |
+
}
|
593 |
+
|
594 |
+
/**
|
595 |
+
* Create an admin notice.
|
596 |
+
*
|
597 |
+
* @param string $id
|
598 |
+
* @return AdminNotice
|
599 |
+
*/
|
600 |
+
function easyAdminNotice($id = null) {
|
601 |
+
return new AdminNotice($id);
|
602 |
+
}
|
603 |
+
|
604 |
+
if (function_exists('add_action')) {
|
605 |
+
add_action('admin_notices', array(__NAMESPACE__ . '\\AdminNotice', '_showDelayedNotices'));
|
606 |
+
add_action('admin_init', array(__NAMESPACE__ . '\\AdminNotice', '_ajaxAddDismissalHandler'), 300);
|
607 |
+
}
|
608 |
+
|
609 |
+
} //class_exists
|
inc/{class-Kama_Contents.php → Contents.php}
RENAMED
@@ -1,15 +1,17 @@
|
|
1 |
<?php
|
2 |
|
|
|
3 |
/**
|
4 |
* Содержание (оглавление) для больших постов.
|
5 |
*
|
|
|
6 |
* @author: Kama
|
7 |
* @info: http://wp-kama.ru/?p=1513
|
8 |
-
* @version: 3.
|
9 |
*
|
10 |
* @changelog: https://github.com/doiftrue/Kama_Contents/blob/master/CHANGELOG.md
|
11 |
*/
|
12 |
-
class
|
13 |
|
14 |
public $opt = [
|
15 |
// Отступ слева у подразделов в px.
|
@@ -230,12 +232,10 @@ class Kama_Contents {
|
|
230 |
}
|
231 |
else {
|
232 |
$contents =
|
233 |
-
( $_is_tit ? '<
|
234 |
-
|
235 |
-
'<ul class="contents"'. ( (! $_tit || $embed) ? ' id="kcmenu"' : '' ) . ( ($ItemList && ! $_is_tit ) ? $ItemList : '' ) .'>'. "\n".
|
236 |
implode('', $this->contents ) .
|
237 |
-
'</
|
238 |
-
( $_is_tit ? '</div>' : '' );
|
239 |
}
|
240 |
|
241 |
$contents =
|
@@ -300,7 +300,7 @@ class Kama_Contents {
|
|
300 |
if( $level > 0 )
|
301 |
$sub = ( $opt->margin ? ' style="margin-left:'. ($level*$opt->margin) .'px;"' : '') . ' class="sub sub_'. $level .'"';
|
302 |
else
|
303 |
-
$sub = '
|
304 |
|
305 |
// collect contents
|
306 |
// markup
|
@@ -317,7 +317,7 @@ class Kama_Contents {
|
|
317 |
$this->contents[] = "\t".'
|
318 |
<tr>
|
319 |
<td '. ($_is_mark?' itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"':'') .'>
|
320 |
-
<a
|
321 |
'.( $_is_mark ? '<span itemprop="name">'. $cont_elem_txt .'</span>' : $cont_elem_txt ).'
|
322 |
</a>
|
323 |
'.( $_is_mark ? ' <meta itemprop="position" content="'. $temp->counter .'" />':'' ).'
|
@@ -328,7 +328,7 @@ class Kama_Contents {
|
|
328 |
else {
|
329 |
$this->contents[] = "\t".'
|
330 |
<li'. $sub . ($_is_mark?' itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"':'') .'>
|
331 |
-
<a
|
332 |
'.( $_is_mark ? '<span itemprop="name">'. $cont_elem_txt .'</span>' : $cont_elem_txt ).'
|
333 |
</a>
|
334 |
'.( $_is_mark ? ' <meta itemprop="position" content="'. $temp->counter .'" />':'' ).'
|
@@ -336,18 +336,18 @@ class Kama_Contents {
|
|
336 |
}
|
337 |
|
338 |
if( $opt->anchor_link )
|
339 |
-
$tag_txt = '<a
|
340 |
|
341 |
// anchor type: 'a' or 'id'
|
342 |
if( $opt->anchor_type === 'a' )
|
343 |
-
$new_el = '<a
|
344 |
else
|
345 |
-
$new_el = "\n<$tag id=\"$anchor\"
|
346 |
|
347 |
$to_menu = '';
|
348 |
if( $opt->to_menu ){
|
349 |
// go to contents
|
350 |
-
$to_menu = '<a
|
351 |
|
352 |
// remove '$to_menu' if simbols beatween $to_menu too small (< 300)
|
353 |
$pos = strpos( $temp->content, $match[0] ); // mb_strpos( $temp->content, $match[0] ) - в 150 раз медленнее!
|
@@ -370,7 +370,9 @@ class Kama_Contents {
|
|
370 |
function _sanitaze_anchor( $anch ){
|
371 |
$anch = strip_tags( $anch );
|
372 |
|
373 |
-
$
|
|
|
|
|
374 |
'А'=>'A', 'Б'=>'B', 'В'=>'V', 'Г'=>'G', 'Д'=>'D', 'Е'=>'E', 'Ё'=>'YO', 'Ж'=>'ZH',
|
375 |
'З'=>'Z', 'И'=>'I', 'Й'=>'J', 'К'=>'K', 'Л'=>'L', 'М'=>'M', 'Н'=>'N', 'О'=>'O',
|
376 |
'П'=>'P', 'Р'=>'R', 'С'=>'S', 'Т'=>'T', 'У'=>'U', 'Ф'=>'F', 'Х'=>'H', 'Ц'=>'TS',
|
@@ -383,35 +385,36 @@ class Kama_Contents {
|
|
383 |
// other
|
384 |
'Ѓ'=>'G', 'Ґ'=>'G', 'Є'=>'YE', 'Ѕ'=>'Z', 'Ј'=>'J', 'І'=>'I', 'Ї'=>'YI', 'Ќ'=>'K', 'Љ'=>'L', 'Њ'=>'N', 'Ў'=>'U', 'Џ'=>'DH',
|
385 |
'ѓ'=>'g', 'ґ'=>'g', 'є'=>'ye', 'ѕ'=>'z', 'ј'=>'j', 'і'=>'i', 'ї'=>'yi', 'ќ'=>'k', 'љ'=>'l', 'њ'=>'n', 'ў'=>'u', 'џ'=>'dh'
|
386 |
-
|
387 |
|
388 |
$anch = strtr( $anch, $iso9 );
|
389 |
|
390 |
$spec = preg_quote( $this->opt->spec );
|
391 |
-
$anch = preg_replace("/[^a-zA-Z0-9_$spec\-]+/", '-', $anch ); // все ненужное на '-'
|
392 |
$anch = strtolower( trim( $anch, '-') );
|
393 |
$anch = substr( $anch, 0, 70 ); // shorten
|
394 |
-
|
|
|
|
|
|
|
395 |
|
396 |
return $anch;
|
397 |
}
|
398 |
|
399 |
## adds number at the end if this anchor already exists
|
400 |
-
function _unique_anchor( $anch ){
|
401 |
-
$
|
402 |
|
403 |
// check and unique anchor
|
404 |
-
if(
|
405 |
-
|
406 |
-
}
|
407 |
-
elseif( isset($temp->anchors[ $anch ]) ){
|
408 |
$lastnum = substr( $anch, -1 );
|
409 |
$lastnum = is_numeric($lastnum) ? $lastnum + 1 : 2;
|
410 |
-
|
411 |
-
|
412 |
-
else {
|
413 |
-
$temp->anchors[ $anch ] = 1;
|
414 |
}
|
|
|
|
|
415 |
|
416 |
return $anch;
|
417 |
}
|
1 |
<?php
|
2 |
|
3 |
+
|
4 |
/**
|
5 |
* Содержание (оглавление) для больших постов.
|
6 |
*
|
7 |
+
* оригинал от камы, переименовано так как изменена разметка
|
8 |
* @author: Kama
|
9 |
* @info: http://wp-kama.ru/?p=1513
|
10 |
+
* @version: 3.18
|
11 |
*
|
12 |
* @changelog: https://github.com/doiftrue/Kama_Contents/blob/master/CHANGELOG.md
|
13 |
*/
|
14 |
+
class YTurbo_Contents {
|
15 |
|
16 |
public $opt = [
|
17 |
// Отступ слева у подразделов в px.
|
232 |
}
|
233 |
else {
|
234 |
$contents =
|
235 |
+
( $_is_tit ? '<h3>'. $_tit .'</h3>'. "\n" : '' ) .
|
236 |
+
'<ol>'. "\n".
|
|
|
237 |
implode('', $this->contents ) .
|
238 |
+
'</ol>'."\n";
|
|
|
239 |
}
|
240 |
|
241 |
$contents =
|
300 |
if( $level > 0 )
|
301 |
$sub = ( $opt->margin ? ' style="margin-left:'. ($level*$opt->margin) .'px;"' : '') . ' class="sub sub_'. $level .'"';
|
302 |
else
|
303 |
+
$sub = '';
|
304 |
|
305 |
// collect contents
|
306 |
// markup
|
317 |
$this->contents[] = "\t".'
|
318 |
<tr>
|
319 |
<td '. ($_is_mark?' itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"':'') .'>
|
320 |
+
<a '. ($_is_mark?' itemprop="url"':'') .' href="'. $opt->page_url .'#'. $anchor .'">
|
321 |
'.( $_is_mark ? '<span itemprop="name">'. $cont_elem_txt .'</span>' : $cont_elem_txt ).'
|
322 |
</a>
|
323 |
'.( $_is_mark ? ' <meta itemprop="position" content="'. $temp->counter .'" />':'' ).'
|
328 |
else {
|
329 |
$this->contents[] = "\t".'
|
330 |
<li'. $sub . ($_is_mark?' itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"':'') .'>
|
331 |
+
<a'. ($_is_mark?' itemprop="url"':'') .' href="'. $opt->page_url .'#'. $anchor .'">
|
332 |
'.( $_is_mark ? '<span itemprop="name">'. $cont_elem_txt .'</span>' : $cont_elem_txt ).'
|
333 |
</a>
|
334 |
'.( $_is_mark ? ' <meta itemprop="position" content="'. $temp->counter .'" />':'' ).'
|
336 |
}
|
337 |
|
338 |
if( $opt->anchor_link )
|
339 |
+
$tag_txt = '<a href="#'. $anchor .'">'. $opt->anchor_link .'</a> ' . $tag_txt;
|
340 |
|
341 |
// anchor type: 'a' or 'id'
|
342 |
if( $opt->anchor_type === 'a' )
|
343 |
+
$new_el = '<a name="'. $anchor .'"></a>'."\n<$tag $attrs>$tag_txt</$tag>";
|
344 |
else
|
345 |
+
$new_el = "\n<$tag id=\"$anchor\"$attrs>$tag_txt</$tag>";
|
346 |
|
347 |
$to_menu = '';
|
348 |
if( $opt->to_menu ){
|
349 |
// go to contents
|
350 |
+
$to_menu = '<a href="'. $opt->page_url .'#kcmenu">'. $opt->to_menu .'</a>';
|
351 |
|
352 |
// remove '$to_menu' if simbols beatween $to_menu too small (< 300)
|
353 |
$pos = strpos( $temp->content, $match[0] ); // mb_strpos( $temp->content, $match[0] ) - в 150 раз медленнее!
|
370 |
function _sanitaze_anchor( $anch ){
|
371 |
$anch = strip_tags( $anch );
|
372 |
|
373 |
+
$anch = apply_filters( 'kama_cont::sanitaze_anchor_before', $anch, $this );
|
374 |
+
|
375 |
+
$iso9 = [
|
376 |
'А'=>'A', 'Б'=>'B', 'В'=>'V', 'Г'=>'G', 'Д'=>'D', 'Е'=>'E', 'Ё'=>'YO', 'Ж'=>'ZH',
|
377 |
'З'=>'Z', 'И'=>'I', 'Й'=>'J', 'К'=>'K', 'Л'=>'L', 'М'=>'M', 'Н'=>'N', 'О'=>'O',
|
378 |
'П'=>'P', 'Р'=>'R', 'С'=>'S', 'Т'=>'T', 'У'=>'U', 'Ф'=>'F', 'Х'=>'H', 'Ц'=>'TS',
|
385 |
// other
|
386 |
'Ѓ'=>'G', 'Ґ'=>'G', 'Є'=>'YE', 'Ѕ'=>'Z', 'Ј'=>'J', 'І'=>'I', 'Ї'=>'YI', 'Ќ'=>'K', 'Љ'=>'L', 'Њ'=>'N', 'Ў'=>'U', 'Џ'=>'DH',
|
387 |
'ѓ'=>'g', 'ґ'=>'g', 'є'=>'ye', 'ѕ'=>'z', 'ј'=>'j', 'і'=>'i', 'ї'=>'yi', 'ќ'=>'k', 'љ'=>'l', 'њ'=>'n', 'ў'=>'u', 'џ'=>'dh'
|
388 |
+
];
|
389 |
|
390 |
$anch = strtr( $anch, $iso9 );
|
391 |
|
392 |
$spec = preg_quote( $this->opt->spec );
|
393 |
+
$anch = preg_replace( "/[^a-zA-Z0-9_$spec\-]+/", '-', $anch ); // все ненужное на '-'
|
394 |
$anch = strtolower( trim( $anch, '-') );
|
395 |
$anch = substr( $anch, 0, 70 ); // shorten
|
396 |
+
|
397 |
+
$anch = apply_filters( 'kama_cont::sanitaze_anchor', $anch, $this );
|
398 |
+
|
399 |
+
$anch = self::_unique_anchor( $anch );
|
400 |
|
401 |
return $anch;
|
402 |
}
|
403 |
|
404 |
## adds number at the end if this anchor already exists
|
405 |
+
static function _unique_anchor( $anch ){
|
406 |
+
static $anchors = [];
|
407 |
|
408 |
// check and unique anchor
|
409 |
+
if( isset($anchors[ $anch ]) ){
|
410 |
+
|
|
|
|
|
411 |
$lastnum = substr( $anch, -1 );
|
412 |
$lastnum = is_numeric($lastnum) ? $lastnum + 1 : 2;
|
413 |
+
|
414 |
+
return self::_unique_anchor( "$anch-$lastnum" );
|
|
|
|
|
415 |
}
|
416 |
+
else
|
417 |
+
$anchors[ $anch ] = 1;
|
418 |
|
419 |
return $anch;
|
420 |
}
|
inc/animate.min.css
DELETED
@@ -1,11 +0,0 @@
|
|
1 |
-
@charset "UTF-8";
|
2 |
-
|
3 |
-
/*!
|
4 |
-
* animate.css -http://daneden.me/animate
|
5 |
-
* Version - 3.7.0
|
6 |
-
* Licensed under the MIT license - http://opensource.org/licenses/MIT
|
7 |
-
*
|
8 |
-
* Copyright (c) 2018 Daniel Eden
|
9 |
-
*/
|
10 |
-
|
11 |
-
@-webkit-keyframes bounce{0%,20%,53%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);-webkit-transform:translateZ(0);animation-timing-function:cubic-bezier(.215,.61,.355,1);transform:translateZ(0)}40%,43%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);-webkit-transform:translate3d(0,-30px,0);animation-timing-function:cubic-bezier(.755,.05,.855,.06);transform:translate3d(0,-30px,0)}70%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);-webkit-transform:translate3d(0,-15px,0);animation-timing-function:cubic-bezier(.755,.05,.855,.06);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}@keyframes bounce{0%,20%,53%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);-webkit-transform:translateZ(0);animation-timing-function:cubic-bezier(.215,.61,.355,1);transform:translateZ(0)}40%,43%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);-webkit-transform:translate3d(0,-30px,0);animation-timing-function:cubic-bezier(.755,.05,.855,.06);transform:translate3d(0,-30px,0)}70%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);-webkit-transform:translate3d(0,-15px,0);animation-timing-function:cubic-bezier(.755,.05,.855,.06);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}.bounce{-webkit-animation-name:bounce;-webkit-transform-origin:center bottom;animation-name:bounce;transform-origin:center bottom}@-webkit-keyframes flash{0%,50%,to{opacity:1}25%,75%{opacity:0}}@keyframes flash{0%,50%,to{opacity:1}25%,75%{opacity:0}}.flash{-webkit-animation-name:flash;animation-name:flash}@-webkit-keyframes pulse{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes pulse{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}.pulse{-webkit-animation-name:pulse;animation-name:pulse}@-webkit-keyframes rubberBand{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}30%{-webkit-transform:scale3d(1.25,.75,1);transform:scale3d(1.25,.75,1)}40%{-webkit-transform:scale3d(.75,1.25,1);transform:scale3d(.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,.85,1);transform:scale3d(1.15,.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes rubberBand{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}30%{-webkit-transform:scale3d(1.25,.75,1);transform:scale3d(1.25,.75,1)}40%{-webkit-transform:scale3d(.75,1.25,1);transform:scale3d(.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,.85,1);transform:scale3d(1.15,.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}.rubberBand{-webkit-animation-name:rubberBand;animation-name:rubberBand}@-webkit-keyframes shake{0%,to{-webkit-transform:translateZ(0);transform:translateZ(0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}@keyframes shake{0%,to{-webkit-transform:translateZ(0);transform:translateZ(0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}.shake{-webkit-animation-name:shake;animation-name:shake}@-webkit-keyframes headShake{0%{-webkit-transform:translateX(0);transform:translateX(0)}6.5%{-webkit-transform:translateX(-6px) rotateY(-9deg);transform:translateX(-6px) rotateY(-9deg)}18.5%{-webkit-transform:translateX(5px) rotateY(7deg);transform:translateX(5px) rotateY(7deg)}31.5%{-webkit-transform:translateX(-3px) rotateY(-5deg);transform:translateX(-3px) rotateY(-5deg)}43.5%{-webkit-transform:translateX(2px) rotateY(3deg);transform:translateX(2px) rotateY(3deg)}50%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes headShake{0%{-webkit-transform:translateX(0);transform:translateX(0)}6.5%{-webkit-transform:translateX(-6px) rotateY(-9deg);transform:translateX(-6px) rotateY(-9deg)}18.5%{-webkit-transform:translateX(5px) rotateY(7deg);transform:translateX(5px) rotateY(7deg)}31.5%{-webkit-transform:translateX(-3px) rotateY(-5deg);transform:translateX(-3px) rotateY(-5deg)}43.5%{-webkit-transform:translateX(2px) rotateY(3deg);transform:translateX(2px) rotateY(3deg)}50%{-webkit-transform:translateX(0);transform:translateX(0)}}.headShake{-webkit-animation-name:headShake;-webkit-animation-timing-function:ease-in-out;animation-name:headShake;animation-timing-function:ease-in-out}@-webkit-keyframes swing{20%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}40%{-webkit-transform:rotate(-10deg);transform:rotate(-10deg)}60%{-webkit-transform:rotate(5deg);transform:rotate(5deg)}80%{-webkit-transform:rotate(-5deg);transform:rotate(-5deg)}to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@keyframes swing{20%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}40%{-webkit-transform:rotate(-10deg);transform:rotate(-10deg)}60%{-webkit-transform:rotate(5deg);transform:rotate(5deg)}80%{-webkit-transform:rotate(-5deg);transform:rotate(-5deg)}to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}.swing{-webkit-animation-name:swing;-webkit-transform-origin:top center;animation-name:swing;transform-origin:top center}@-webkit-keyframes tada{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate(-3deg);transform:scale3d(.9,.9,.9) rotate(-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(3deg);transform:scale3d(1.1,1.1,1.1) rotate(3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(-3deg);transform:scale3d(1.1,1.1,1.1) rotate(-3deg)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes tada{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate(-3deg);transform:scale3d(.9,.9,.9) rotate(-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(3deg);transform:scale3d(1.1,1.1,1.1) rotate(3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(-3deg);transform:scale3d(1.1,1.1,1.1) rotate(-3deg)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}.tada{-webkit-animation-name:tada;animation-name:tada}@-webkit-keyframes wobble{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}15%{-webkit-transform:translate3d(-25%,0,0) rotate(-5deg);transform:translate3d(-25%,0,0) rotate(-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate(3deg);transform:translate3d(20%,0,0) rotate(3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate(-3deg);transform:translate3d(-15%,0,0) rotate(-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate(2deg);transform:translate3d(10%,0,0) rotate(2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate(-1deg);transform:translate3d(-5%,0,0) rotate(-1deg)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes wobble{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}15%{-webkit-transform:translate3d(-25%,0,0) rotate(-5deg);transform:translate3d(-25%,0,0) rotate(-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate(3deg);transform:translate3d(20%,0,0) rotate(3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate(-3deg);transform:translate3d(-15%,0,0) rotate(-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate(2deg);transform:translate3d(10%,0,0) rotate(2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate(-1deg);transform:translate3d(-5%,0,0) rotate(-1deg)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.wobble{-webkit-animation-name:wobble;animation-name:wobble}@-webkit-keyframes jello{0%,11.1%,to{-webkit-transform:translateZ(0);transform:translateZ(0)}22.2%{-webkit-transform:skewX(-12.5deg) skewY(-12.5deg);transform:skewX(-12.5deg) skewY(-12.5deg)}33.3%{-webkit-transform:skewX(6.25deg) skewY(6.25deg);transform:skewX(6.25deg) skewY(6.25deg)}44.4%{-webkit-transform:skewX(-3.125deg) skewY(-3.125deg);transform:skewX(-3.125deg) skewY(-3.125deg)}55.5%{-webkit-transform:skewX(1.5625deg) skewY(1.5625deg);transform:skewX(1.5625deg) skewY(1.5625deg)}66.6%{-webkit-transform:skewX(-.78125deg) skewY(-.78125deg);transform:skewX(-.78125deg) skewY(-.78125deg)}77.7%{-webkit-transform:skewX(.390625deg) skewY(.390625deg);transform:skewX(.390625deg) skewY(.390625deg)}88.8%{-webkit-transform:skewX(-.1953125deg) skewY(-.1953125deg);transform:skewX(-.1953125deg) skewY(-.1953125deg)}}@keyframes jello{0%,11.1%,to{-webkit-transform:translateZ(0);transform:translateZ(0)}22.2%{-webkit-transform:skewX(-12.5deg) skewY(-12.5deg);transform:skewX(-12.5deg) skewY(-12.5deg)}33.3%{-webkit-transform:skewX(6.25deg) skewY(6.25deg);transform:skewX(6.25deg) skewY(6.25deg)}44.4%{-webkit-transform:skewX(-3.125deg) skewY(-3.125deg);transform:skewX(-3.125deg) skewY(-3.125deg)}55.5%{-webkit-transform:skewX(1.5625deg) skewY(1.5625deg);transform:skewX(1.5625deg) skewY(1.5625deg)}66.6%{-webkit-transform:skewX(-.78125deg) skewY(-.78125deg);transform:skewX(-.78125deg) skewY(-.78125deg)}77.7%{-webkit-transform:skewX(.390625deg) skewY(.390625deg);transform:skewX(.390625deg) skewY(.390625deg)}88.8%{-webkit-transform:skewX(-.1953125deg) skewY(-.1953125deg);transform:skewX(-.1953125deg) skewY(-.1953125deg)}}.jello{-webkit-animation-name:jello;-webkit-transform-origin:center;animation-name:jello;transform-origin:center}@-webkit-keyframes heartBeat{0%{-webkit-transform:scale(1);transform:scale(1)}14%{-webkit-transform:scale(1.3);transform:scale(1.3)}28%{-webkit-transform:scale(1);transform:scale(1)}42%{-webkit-transform:scale(1.3);transform:scale(1.3)}70%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes heartBeat{0%{-webkit-transform:scale(1);transform:scale(1)}14%{-webkit-transform:scale(1.3);transform:scale(1.3)}28%{-webkit-transform:scale(1);transform:scale(1)}42%{-webkit-transform:scale(1.3);transform:scale(1.3)}70%{-webkit-transform:scale(1);transform:scale(1)}}.heartBeat{-webkit-animation-duration:1.3s;-webkit-animation-name:heartBeat;-webkit-animation-timing-function:ease-in-out;animation-duration:1.3s;animation-name:heartBeat;animation-timing-function:ease-in-out}@-webkit-keyframes bounceIn{0%,20%,40%,60%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:scale3d(.3,.3,.3);opacity:0;transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{-webkit-transform:scale3d(1.03,1.03,1.03);opacity:1;transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}to{-webkit-transform:scaleX(1);opacity:1;transform:scaleX(1)}}@keyframes bounceIn{0%,20%,40%,60%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:scale3d(.3,.3,.3);opacity:0;transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{-webkit-transform:scale3d(1.03,1.03,1.03);opacity:1;transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}to{-webkit-transform:scaleX(1);opacity:1;transform:scaleX(1)}}.bounceIn{-webkit-animation-duration:.75s;-webkit-animation-name:bounceIn;animation-duration:.75s;animation-name:bounceIn}@-webkit-keyframes bounceInDown{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translate3d(0,-3000px,0);opacity:0;transform:translate3d(0,-3000px,0)}60%{-webkit-transform:translate3d(0,25px,0);opacity:1;transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes bounceInDown{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translate3d(0,-3000px,0);opacity:0;transform:translate3d(0,-3000px,0)}60%{-webkit-transform:translate3d(0,25px,0);opacity:1;transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.bounceInDown{-webkit-animation-name:bounceInDown;animation-name:bounceInDown}@-webkit-keyframes bounceInLeft{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translate3d(-3000px,0,0);opacity:0;transform:translate3d(-3000px,0,0)}60%{-webkit-transform:translate3d(25px,0,0);opacity:1;transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes bounceInLeft{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translate3d(-3000px,0,0);opacity:0;transform:translate3d(-3000px,0,0)}60%{-webkit-transform:translate3d(25px,0,0);opacity:1;transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.bounceInLeft{-webkit-animation-name:bounceInLeft;animation-name:bounceInLeft}@-webkit-keyframes bounceInRight{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translate3d(3000px,0,0);opacity:0;transform:translate3d(3000px,0,0)}60%{-webkit-transform:translate3d(-25px,0,0);opacity:1;transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes bounceInRight{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translate3d(3000px,0,0);opacity:0;transform:translate3d(3000px,0,0)}60%{-webkit-transform:translate3d(-25px,0,0);opacity:1;transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.bounceInRight{-webkit-animation-name:bounceInRight;animation-name:bounceInRight}@-webkit-keyframes bounceInUp{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translate3d(0,3000px,0);opacity:0;transform:translate3d(0,3000px,0)}60%{-webkit-transform:translate3d(0,-20px,0);opacity:1;transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes bounceInUp{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translate3d(0,3000px,0);opacity:0;transform:translate3d(0,3000px,0)}60%{-webkit-transform:translate3d(0,-20px,0);opacity:1;transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.bounceInUp{-webkit-animation-name:bounceInUp;animation-name:bounceInUp}@-webkit-keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{-webkit-transform:scale3d(1.1,1.1,1.1);opacity:1;transform:scale3d(1.1,1.1,1.1)}to{-webkit-transform:scale3d(.3,.3,.3);opacity:0;transform:scale3d(.3,.3,.3)}}@keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{-webkit-transform:scale3d(1.1,1.1,1.1);opacity:1;transform:scale3d(1.1,1.1,1.1)}to{-webkit-transform:scale3d(.3,.3,.3);opacity:0;transform:scale3d(.3,.3,.3)}}.bounceOut{-webkit-animation-duration:.75s;-webkit-animation-name:bounceOut;animation-duration:.75s;animation-name:bounceOut}@-webkit-keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{-webkit-transform:translate3d(0,-20px,0);opacity:1;transform:translate3d(0,-20px,0)}to{-webkit-transform:translate3d(0,2000px,0);opacity:0;transform:translate3d(0,2000px,0)}}@keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{-webkit-transform:translate3d(0,-20px,0);opacity:1;transform:translate3d(0,-20px,0)}to{-webkit-transform:translate3d(0,2000px,0);opacity:0;transform:translate3d(0,2000px,0)}}.bounceOutDown{-webkit-animation-name:bounceOutDown;animation-name:bounceOutDown}@-webkit-keyframes bounceOutLeft{20%{-webkit-transform:translate3d(20px,0,0);opacity:1;transform:translate3d(20px,0,0)}to{-webkit-transform:translate3d(-2000px,0,0);opacity:0;transform:translate3d(-2000px,0,0)}}@keyframes bounceOutLeft{20%{-webkit-transform:translate3d(20px,0,0);opacity:1;transform:translate3d(20px,0,0)}to{-webkit-transform:translate3d(-2000px,0,0);opacity:0;transform:translate3d(-2000px,0,0)}}.bounceOutLeft{-webkit-animation-name:bounceOutLeft;animation-name:bounceOutLeft}@-webkit-keyframes bounceOutRight{20%{-webkit-transform:translate3d(-20px,0,0);opacity:1;transform:translate3d(-20px,0,0)}to{-webkit-transform:translate3d(2000px,0,0);opacity:0;transform:translate3d(2000px,0,0)}}@keyframes bounceOutRight{20%{-webkit-transform:translate3d(-20px,0,0);opacity:1;transform:translate3d(-20px,0,0)}to{-webkit-transform:translate3d(2000px,0,0);opacity:0;transform:translate3d(2000px,0,0)}}.bounceOutRight{-webkit-animation-name:bounceOutRight;animation-name:bounceOutRight}@-webkit-keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{-webkit-transform:translate3d(0,20px,0);opacity:1;transform:translate3d(0,20px,0)}to{-webkit-transform:translate3d(0,-2000px,0);opacity:0;transform:translate3d(0,-2000px,0)}}@keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{-webkit-transform:translate3d(0,20px,0);opacity:1;transform:translate3d(0,20px,0)}to{-webkit-transform:translate3d(0,-2000px,0);opacity:0;transform:translate3d(0,-2000px,0)}}.bounceOutUp{-webkit-animation-name:bounceOutUp;animation-name:bounceOutUp}@-webkit-keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.fadeIn{-webkit-animation-name:fadeIn;animation-name:fadeIn}@-webkit-keyframes fadeInDown{0%{-webkit-transform:translate3d(0,-100%,0);opacity:0;transform:translate3d(0,-100%,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}@keyframes fadeInDown{0%{-webkit-transform:translate3d(0,-100%,0);opacity:0;transform:translate3d(0,-100%,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}.fadeInDown{-webkit-animation-name:fadeInDown;animation-name:fadeInDown}@-webkit-keyframes fadeInDownBig{0%{-webkit-transform:translate3d(0,-2000px,0);opacity:0;transform:translate3d(0,-2000px,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}@keyframes fadeInDownBig{0%{-webkit-transform:translate3d(0,-2000px,0);opacity:0;transform:translate3d(0,-2000px,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}.fadeInDownBig{-webkit-animation-name:fadeInDownBig;animation-name:fadeInDownBig}@-webkit-keyframes fadeInLeft{0%{-webkit-transform:translate3d(-100%,0,0);opacity:0;transform:translate3d(-100%,0,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}@keyframes fadeInLeft{0%{-webkit-transform:translate3d(-100%,0,0);opacity:0;transform:translate3d(-100%,0,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}.fadeInLeft{-webkit-animation-name:fadeInLeft;animation-name:fadeInLeft}@-webkit-keyframes fadeInLeftBig{0%{-webkit-transform:translate3d(-2000px,0,0);opacity:0;transform:translate3d(-2000px,0,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}@keyframes fadeInLeftBig{0%{-webkit-transform:translate3d(-2000px,0,0);opacity:0;transform:translate3d(-2000px,0,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}.fadeInLeftBig{-webkit-animation-name:fadeInLeftBig;animation-name:fadeInLeftBig}@-webkit-keyframes fadeInRight{0%{-webkit-transform:translate3d(100%,0,0);opacity:0;transform:translate3d(100%,0,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}@keyframes fadeInRight{0%{-webkit-transform:translate3d(100%,0,0);opacity:0;transform:translate3d(100%,0,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}.fadeInRight{-webkit-animation-name:fadeInRight;animation-name:fadeInRight}@-webkit-keyframes fadeInRightBig{0%{-webkit-transform:translate3d(2000px,0,0);opacity:0;transform:translate3d(2000px,0,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}@keyframes fadeInRightBig{0%{-webkit-transform:translate3d(2000px,0,0);opacity:0;transform:translate3d(2000px,0,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}.fadeInRightBig{-webkit-animation-name:fadeInRightBig;animation-name:fadeInRightBig}@-webkit-keyframes fadeInUp{0%{-webkit-transform:translate3d(0,100%,0);opacity:0;transform:translate3d(0,100%,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}@keyframes fadeInUp{0%{-webkit-transform:translate3d(0,100%,0);opacity:0;transform:translate3d(0,100%,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}.fadeInUp{-webkit-animation-name:fadeInUp;animation-name:fadeInUp}@-webkit-keyframes fadeInUpBig{0%{-webkit-transform:translate3d(0,2000px,0);opacity:0;transform:translate3d(0,2000px,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}@keyframes fadeInUpBig{0%{-webkit-transform:translate3d(0,2000px,0);opacity:0;transform:translate3d(0,2000px,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}.fadeInUpBig{-webkit-animation-name:fadeInUpBig;animation-name:fadeInUpBig}@-webkit-keyframes fadeOut{0%{opacity:1}to{opacity:0}}@keyframes fadeOut{0%{opacity:1}to{opacity:0}}.fadeOut{-webkit-animation-name:fadeOut;animation-name:fadeOut}@-webkit-keyframes fadeOutDown{0%{opacity:1}to{-webkit-transform:translate3d(0,100%,0);opacity:0;transform:translate3d(0,100%,0)}}@keyframes fadeOutDown{0%{opacity:1}to{-webkit-transform:translate3d(0,100%,0);opacity:0;transform:translate3d(0,100%,0)}}.fadeOutDown{-webkit-animation-name:fadeOutDown;animation-name:fadeOutDown}@-webkit-keyframes fadeOutDownBig{0%{opacity:1}to{-webkit-transform:translate3d(0,2000px,0);opacity:0;transform:translate3d(0,2000px,0)}}@keyframes fadeOutDownBig{0%{opacity:1}to{-webkit-transform:translate3d(0,2000px,0);opacity:0;transform:translate3d(0,2000px,0)}}.fadeOutDownBig{-webkit-animation-name:fadeOutDownBig;animation-name:fadeOutDownBig}@-webkit-keyframes fadeOutLeft{0%{opacity:1}to{-webkit-transform:translate3d(-100%,0,0);opacity:0;transform:translate3d(-100%,0,0)}}@keyframes fadeOutLeft{0%{opacity:1}to{-webkit-transform:translate3d(-100%,0,0);opacity:0;transform:translate3d(-100%,0,0)}}.fadeOutLeft{-webkit-animation-name:fadeOutLeft;animation-name:fadeOutLeft}@-webkit-keyframes fadeOutLeftBig{0%{opacity:1}to{-webkit-transform:translate3d(-2000px,0,0);opacity:0;transform:translate3d(-2000px,0,0)}}@keyframes fadeOutLeftBig{0%{opacity:1}to{-webkit-transform:translate3d(-2000px,0,0);opacity:0;transform:translate3d(-2000px,0,0)}}.fadeOutLeftBig{-webkit-animation-name:fadeOutLeftBig;animation-name:fadeOutLeftBig}@-webkit-keyframes fadeOutRight{0%{opacity:1}to{-webkit-transform:translate3d(100%,0,0);opacity:0;transform:translate3d(100%,0,0)}}@keyframes fadeOutRight{0%{opacity:1}to{-webkit-transform:translate3d(100%,0,0);opacity:0;transform:translate3d(100%,0,0)}}.fadeOutRight{-webkit-animation-name:fadeOutRight;animation-name:fadeOutRight}@-webkit-keyframes fadeOutRightBig{0%{opacity:1}to{-webkit-transform:translate3d(2000px,0,0);opacity:0;transform:translate3d(2000px,0,0)}}@keyframes fadeOutRightBig{0%{opacity:1}to{-webkit-transform:translate3d(2000px,0,0);opacity:0;transform:translate3d(2000px,0,0)}}.fadeOutRightBig{-webkit-animation-name:fadeOutRightBig;animation-name:fadeOutRightBig}@-webkit-keyframes fadeOutUp{0%{opacity:1}to{-webkit-transform:translate3d(0,-100%,0);opacity:0;transform:translate3d(0,-100%,0)}}@keyframes fadeOutUp{0%{opacity:1}to{-webkit-transform:translate3d(0,-100%,0);opacity:0;transform:translate3d(0,-100%,0)}}.fadeOutUp{-webkit-animation-name:fadeOutUp;animation-name:fadeOutUp}@-webkit-keyframes fadeOutUpBig{0%{opacity:1}to{-webkit-transform:translate3d(0,-2000px,0);opacity:0;transform:translate3d(0,-2000px,0)}}@keyframes fadeOutUpBig{0%{opacity:1}to{-webkit-transform:translate3d(0,-2000px,0);opacity:0;transform:translate3d(0,-2000px,0)}}.fadeOutUpBig{-webkit-animation-name:fadeOutUpBig;animation-name:fadeOutUpBig}@-webkit-keyframes flip{0%{-webkit-animation-timing-function:ease-out;-webkit-transform:perspective(400px) scaleX(1) translateZ(0) rotateY(-1turn);animation-timing-function:ease-out;transform:perspective(400px) scaleX(1) translateZ(0) rotateY(-1turn)}40%{-webkit-animation-timing-function:ease-out;-webkit-transform:perspective(400px) scaleX(1) translateZ(150px) rotateY(-190deg);animation-timing-function:ease-out;transform:perspective(400px) scaleX(1) translateZ(150px) rotateY(-190deg)}50%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) scaleX(1) translateZ(150px) rotateY(-170deg);animation-timing-function:ease-in;transform:perspective(400px) scaleX(1) translateZ(150px) rotateY(-170deg)}80%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) scale3d(.95,.95,.95) translateZ(0) rotateY(0deg);animation-timing-function:ease-in;transform:perspective(400px) scale3d(.95,.95,.95) translateZ(0) rotateY(0deg)}to{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) scaleX(1) translateZ(0) rotateY(0deg);animation-timing-function:ease-in;transform:perspective(400px) scaleX(1) translateZ(0) rotateY(0deg)}}@keyframes flip{0%{-webkit-animation-timing-function:ease-out;-webkit-transform:perspective(400px) scaleX(1) translateZ(0) rotateY(-1turn);animation-timing-function:ease-out;transform:perspective(400px) scaleX(1) translateZ(0) rotateY(-1turn)}40%{-webkit-animation-timing-function:ease-out;-webkit-transform:perspective(400px) scaleX(1) translateZ(150px) rotateY(-190deg);animation-timing-function:ease-out;transform:perspective(400px) scaleX(1) translateZ(150px) rotateY(-190deg)}50%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) scaleX(1) translateZ(150px) rotateY(-170deg);animation-timing-function:ease-in;transform:perspective(400px) scaleX(1) translateZ(150px) rotateY(-170deg)}80%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) scale3d(.95,.95,.95) translateZ(0) rotateY(0deg);animation-timing-function:ease-in;transform:perspective(400px) scale3d(.95,.95,.95) translateZ(0) rotateY(0deg)}to{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) scaleX(1) translateZ(0) rotateY(0deg);animation-timing-function:ease-in;transform:perspective(400px) scaleX(1) translateZ(0) rotateY(0deg)}}.animated.flip{-webkit-animation-name:flip;-webkit-backface-visibility:visible;animation-name:flip;backface-visibility:visible}@-webkit-keyframes flipInX{0%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) rotateX(90deg);animation-timing-function:ease-in;opacity:0;transform:perspective(400px) rotateX(90deg)}40%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) rotateX(-20deg);animation-timing-function:ease-in;transform:perspective(400px) rotateX(-20deg)}60%{-webkit-transform:perspective(400px) rotateX(10deg);opacity:1;transform:perspective(400px) rotateX(10deg)}80%{-webkit-transform:perspective(400px) rotateX(-5deg);transform:perspective(400px) rotateX(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInX{0%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) rotateX(90deg);animation-timing-function:ease-in;opacity:0;transform:perspective(400px) rotateX(90deg)}40%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) rotateX(-20deg);animation-timing-function:ease-in;transform:perspective(400px) rotateX(-20deg)}60%{-webkit-transform:perspective(400px) rotateX(10deg);opacity:1;transform:perspective(400px) rotateX(10deg)}80%{-webkit-transform:perspective(400px) rotateX(-5deg);transform:perspective(400px) rotateX(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}.flipInX{-webkit-animation-name:flipInX;-webkit-backface-visibility:visible!important;animation-name:flipInX;backface-visibility:visible!important}@-webkit-keyframes flipInY{0%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) rotateY(90deg);animation-timing-function:ease-in;opacity:0;transform:perspective(400px) rotateY(90deg)}40%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) rotateY(-20deg);animation-timing-function:ease-in;transform:perspective(400px) rotateY(-20deg)}60%{-webkit-transform:perspective(400px) rotateY(10deg);opacity:1;transform:perspective(400px) rotateY(10deg)}80%{-webkit-transform:perspective(400px) rotateY(-5deg);transform:perspective(400px) rotateY(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInY{0%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) rotateY(90deg);animation-timing-function:ease-in;opacity:0;transform:perspective(400px) rotateY(90deg)}40%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) rotateY(-20deg);animation-timing-function:ease-in;transform:perspective(400px) rotateY(-20deg)}60%{-webkit-transform:perspective(400px) rotateY(10deg);opacity:1;transform:perspective(400px) rotateY(10deg)}80%{-webkit-transform:perspective(400px) rotateY(-5deg);transform:perspective(400px) rotateY(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}.flipInY{-webkit-animation-name:flipInY;-webkit-backface-visibility:visible!important;animation-name:flipInY;backface-visibility:visible!important}@-webkit-keyframes flipOutX{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateX(-20deg);opacity:1;transform:perspective(400px) rotateX(-20deg)}to{-webkit-transform:perspective(400px) rotateX(90deg);opacity:0;transform:perspective(400px) rotateX(90deg)}}@keyframes flipOutX{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateX(-20deg);opacity:1;transform:perspective(400px) rotateX(-20deg)}to{-webkit-transform:perspective(400px) rotateX(90deg);opacity:0;transform:perspective(400px) rotateX(90deg)}}.flipOutX{-webkit-animation-duration:.75s;-webkit-animation-name:flipOutX;-webkit-backface-visibility:visible!important;animation-duration:.75s;animation-name:flipOutX;backface-visibility:visible!important}@-webkit-keyframes flipOutY{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateY(-15deg);opacity:1;transform:perspective(400px) rotateY(-15deg)}to{-webkit-transform:perspective(400px) rotateY(90deg);opacity:0;transform:perspective(400px) rotateY(90deg)}}@keyframes flipOutY{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateY(-15deg);opacity:1;transform:perspective(400px) rotateY(-15deg)}to{-webkit-transform:perspective(400px) rotateY(90deg);opacity:0;transform:perspective(400px) rotateY(90deg)}}.flipOutY{-webkit-animation-duration:.75s;-webkit-animation-name:flipOutY;-webkit-backface-visibility:visible!important;animation-duration:.75s;animation-name:flipOutY;backface-visibility:visible!important}@-webkit-keyframes lightSpeedIn{0%{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);opacity:0;transform:translate3d(100%,0,0) skewX(-30deg)}60%{-webkit-transform:skewX(20deg);opacity:1;transform:skewX(20deg)}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes lightSpeedIn{0%{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);opacity:0;transform:translate3d(100%,0,0) skewX(-30deg)}60%{-webkit-transform:skewX(20deg);opacity:1;transform:skewX(20deg)}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.lightSpeedIn{-webkit-animation-name:lightSpeedIn;-webkit-animation-timing-function:ease-out;animation-name:lightSpeedIn;animation-timing-function:ease-out}@-webkit-keyframes lightSpeedOut{0%{opacity:1}to{-webkit-transform:translate3d(100%,0,0) skewX(30deg);opacity:0;transform:translate3d(100%,0,0) skewX(30deg)}}@keyframes lightSpeedOut{0%{opacity:1}to{-webkit-transform:translate3d(100%,0,0) skewX(30deg);opacity:0;transform:translate3d(100%,0,0) skewX(30deg)}}.lightSpeedOut{-webkit-animation-name:lightSpeedOut;-webkit-animation-timing-function:ease-in;animation-name:lightSpeedOut;animation-timing-function:ease-in}@-webkit-keyframes rotateIn{0%{-webkit-transform:rotate(-200deg);-webkit-transform-origin:center;opacity:0;transform:rotate(-200deg);transform-origin:center}to{-webkit-transform:translateZ(0);-webkit-transform-origin:center;opacity:1;transform:translateZ(0);transform-origin:center}}@keyframes rotateIn{0%{-webkit-transform:rotate(-200deg);-webkit-transform-origin:center;opacity:0;transform:rotate(-200deg);transform-origin:center}to{-webkit-transform:translateZ(0);-webkit-transform-origin:center;opacity:1;transform:translateZ(0);transform-origin:center}}.rotateIn{-webkit-animation-name:rotateIn;animation-name:rotateIn}@-webkit-keyframes rotateInDownLeft{0%{-webkit-transform:rotate(-45deg);-webkit-transform-origin:left bottom;opacity:0;transform:rotate(-45deg);transform-origin:left bottom}to{-webkit-transform:translateZ(0);-webkit-transform-origin:left bottom;opacity:1;transform:translateZ(0);transform-origin:left bottom}}@keyframes rotateInDownLeft{0%{-webkit-transform:rotate(-45deg);-webkit-transform-origin:left bottom;opacity:0;transform:rotate(-45deg);transform-origin:left bottom}to{-webkit-transform:translateZ(0);-webkit-transform-origin:left bottom;opacity:1;transform:translateZ(0);transform-origin:left bottom}}.rotateInDownLeft{-webkit-animation-name:rotateInDownLeft;animation-name:rotateInDownLeft}@-webkit-keyframes rotateInDownRight{0%{-webkit-transform:rotate(45deg);-webkit-transform-origin:right bottom;opacity:0;transform:rotate(45deg);transform-origin:right bottom}to{-webkit-transform:translateZ(0);-webkit-transform-origin:right bottom;opacity:1;transform:translateZ(0);transform-origin:right bottom}}@keyframes rotateInDownRight{0%{-webkit-transform:rotate(45deg);-webkit-transform-origin:right bottom;opacity:0;transform:rotate(45deg);transform-origin:right bottom}to{-webkit-transform:translateZ(0);-webkit-transform-origin:right bottom;opacity:1;transform:translateZ(0);transform-origin:right bottom}}.rotateInDownRight{-webkit-animation-name:rotateInDownRight;animation-name:rotateInDownRight}@-webkit-keyframes rotateInUpLeft{0%{-webkit-transform:rotate(45deg);-webkit-transform-origin:left bottom;opacity:0;transform:rotate(45deg);transform-origin:left bottom}to{-webkit-transform:translateZ(0);-webkit-transform-origin:left bottom;opacity:1;transform:translateZ(0);transform-origin:left bottom}}@keyframes rotateInUpLeft{0%{-webkit-transform:rotate(45deg);-webkit-transform-origin:left bottom;opacity:0;transform:rotate(45deg);transform-origin:left bottom}to{-webkit-transform:translateZ(0);-webkit-transform-origin:left bottom;opacity:1;transform:translateZ(0);transform-origin:left bottom}}.rotateInUpLeft{-webkit-animation-name:rotateInUpLeft;animation-name:rotateInUpLeft}@-webkit-keyframes rotateInUpRight{0%{-webkit-transform:rotate(-90deg);-webkit-transform-origin:right bottom;opacity:0;transform:rotate(-90deg);transform-origin:right bottom}to{-webkit-transform:translateZ(0);-webkit-transform-origin:right bottom;opacity:1;transform:translateZ(0);transform-origin:right bottom}}@keyframes rotateInUpRight{0%{-webkit-transform:rotate(-90deg);-webkit-transform-origin:right bottom;opacity:0;transform:rotate(-90deg);transform-origin:right bottom}to{-webkit-transform:translateZ(0);-webkit-transform-origin:right bottom;opacity:1;transform:translateZ(0);transform-origin:right bottom}}.rotateInUpRight{-webkit-animation-name:rotateInUpRight;animation-name:rotateInUpRight}@-webkit-keyframes rotateOut{0%{-webkit-transform-origin:center;opacity:1;transform-origin:center}to{-webkit-transform:rotate(200deg);-webkit-transform-origin:center;opacity:0;transform:rotate(200deg);transform-origin:center}}@keyframes rotateOut{0%{-webkit-transform-origin:center;opacity:1;transform-origin:center}to{-webkit-transform:rotate(200deg);-webkit-transform-origin:center;opacity:0;transform:rotate(200deg);transform-origin:center}}.rotateOut{-webkit-animation-name:rotateOut;animation-name:rotateOut}@-webkit-keyframes rotateOutDownLeft{0%{-webkit-transform-origin:left bottom;opacity:1;transform-origin:left bottom}to{-webkit-transform:rotate(45deg);-webkit-transform-origin:left bottom;opacity:0;transform:rotate(45deg);transform-origin:left bottom}}@keyframes rotateOutDownLeft{0%{-webkit-transform-origin:left bottom;opacity:1;transform-origin:left bottom}to{-webkit-transform:rotate(45deg);-webkit-transform-origin:left bottom;opacity:0;transform:rotate(45deg);transform-origin:left bottom}}.rotateOutDownLeft{-webkit-animation-name:rotateOutDownLeft;animation-name:rotateOutDownLeft}@-webkit-keyframes rotateOutDownRight{0%{-webkit-transform-origin:right bottom;opacity:1;transform-origin:right bottom}to{-webkit-transform:rotate(-45deg);-webkit-transform-origin:right bottom;opacity:0;transform:rotate(-45deg);transform-origin:right bottom}}@keyframes rotateOutDownRight{0%{-webkit-transform-origin:right bottom;opacity:1;transform-origin:right bottom}to{-webkit-transform:rotate(-45deg);-webkit-transform-origin:right bottom;opacity:0;transform:rotate(-45deg);transform-origin:right bottom}}.rotateOutDownRight{-webkit-animation-name:rotateOutDownRight;animation-name:rotateOutDownRight}@-webkit-keyframes rotateOutUpLeft{0%{-webkit-transform-origin:left bottom;opacity:1;transform-origin:left bottom}to{-webkit-transform:rotate(-45deg);-webkit-transform-origin:left bottom;opacity:0;transform:rotate(-45deg);transform-origin:left bottom}}@keyframes rotateOutUpLeft{0%{-webkit-transform-origin:left bottom;opacity:1;transform-origin:left bottom}to{-webkit-transform:rotate(-45deg);-webkit-transform-origin:left bottom;opacity:0;transform:rotate(-45deg);transform-origin:left bottom}}.rotateOutUpLeft{-webkit-animation-name:rotateOutUpLeft;animation-name:rotateOutUpLeft}@-webkit-keyframes rotateOutUpRight{0%{-webkit-transform-origin:right bottom;opacity:1;transform-origin:right bottom}to{-webkit-transform:rotate(90deg);-webkit-transform-origin:right bottom;opacity:0;transform:rotate(90deg);transform-origin:right bottom}}@keyframes rotateOutUpRight{0%{-webkit-transform-origin:right bottom;opacity:1;transform-origin:right bottom}to{-webkit-transform:rotate(90deg);-webkit-transform-origin:right bottom;opacity:0;transform:rotate(90deg);transform-origin:right bottom}}.rotateOutUpRight{-webkit-animation-name:rotateOutUpRight;animation-name:rotateOutUpRight}@-webkit-keyframes hinge{0%{-webkit-animation-timing-function:ease-in-out;-webkit-transform-origin:top left;animation-timing-function:ease-in-out;transform-origin:top left}20%,60%{-webkit-animation-timing-function:ease-in-out;-webkit-transform:rotate(80deg);-webkit-transform-origin:top left;animation-timing-function:ease-in-out;transform:rotate(80deg);transform-origin:top left}40%,80%{-webkit-animation-timing-function:ease-in-out;-webkit-transform:rotate(60deg);-webkit-transform-origin:top left;animation-timing-function:ease-in-out;opacity:1;transform:rotate(60deg);transform-origin:top left}to{-webkit-transform:translate3d(0,700px,0);opacity:0;transform:translate3d(0,700px,0)}}@keyframes hinge{0%{-webkit-animation-timing-function:ease-in-out;-webkit-transform-origin:top left;animation-timing-function:ease-in-out;transform-origin:top left}20%,60%{-webkit-animation-timing-function:ease-in-out;-webkit-transform:rotate(80deg);-webkit-transform-origin:top left;animation-timing-function:ease-in-out;transform:rotate(80deg);transform-origin:top left}40%,80%{-webkit-animation-timing-function:ease-in-out;-webkit-transform:rotate(60deg);-webkit-transform-origin:top left;animation-timing-function:ease-in-out;opacity:1;transform:rotate(60deg);transform-origin:top left}to{-webkit-transform:translate3d(0,700px,0);opacity:0;transform:translate3d(0,700px,0)}}.hinge{-webkit-animation-duration:2s;-webkit-animation-name:hinge;animation-duration:2s;animation-name:hinge}@-webkit-keyframes jackInTheBox{0%{-webkit-transform:scale(.1) rotate(30deg);-webkit-transform-origin:center bottom;opacity:0;transform:scale(.1) rotate(30deg);transform-origin:center bottom}50%{-webkit-transform:rotate(-10deg);transform:rotate(-10deg)}70%{-webkit-transform:rotate(3deg);transform:rotate(3deg)}to{-webkit-transform:scale(1);opacity:1;transform:scale(1)}}@keyframes jackInTheBox{0%{-webkit-transform:scale(.1) rotate(30deg);-webkit-transform-origin:center bottom;opacity:0;transform:scale(.1) rotate(30deg);transform-origin:center bottom}50%{-webkit-transform:rotate(-10deg);transform:rotate(-10deg)}70%{-webkit-transform:rotate(3deg);transform:rotate(3deg)}to{-webkit-transform:scale(1);opacity:1;transform:scale(1)}}.jackInTheBox{-webkit-animation-name:jackInTheBox;animation-name:jackInTheBox}@-webkit-keyframes rollIn{0%{-webkit-transform:translate3d(-100%,0,0) rotate(-120deg);opacity:0;transform:translate3d(-100%,0,0) rotate(-120deg)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}@keyframes rollIn{0%{-webkit-transform:translate3d(-100%,0,0) rotate(-120deg);opacity:0;transform:translate3d(-100%,0,0) rotate(-120deg)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}.rollIn{-webkit-animation-name:rollIn;animation-name:rollIn}@-webkit-keyframes rollOut{0%{opacity:1}to{-webkit-transform:translate3d(100%,0,0) rotate(120deg);opacity:0;transform:translate3d(100%,0,0) rotate(120deg)}}@keyframes rollOut{0%{opacity:1}to{-webkit-transform:translate3d(100%,0,0) rotate(120deg);opacity:0;transform:translate3d(100%,0,0) rotate(120deg)}}.rollOut{-webkit-animation-name:rollOut;animation-name:rollOut}@-webkit-keyframes zoomIn{0%{-webkit-transform:scale3d(.3,.3,.3);opacity:0;transform:scale3d(.3,.3,.3)}50%{opacity:1}}@keyframes zoomIn{0%{-webkit-transform:scale3d(.3,.3,.3);opacity:0;transform:scale3d(.3,.3,.3)}50%{opacity:1}}.zoomIn{-webkit-animation-name:zoomIn;animation-name:zoomIn}@-webkit-keyframes zoomInDown{0%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0)}60%{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,60px,0)}}@keyframes zoomInDown{0%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0)}60%{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,60px,0)}}.zoomInDown{-webkit-animation-name:zoomInDown;animation-name:zoomInDown}@-webkit-keyframes zoomInLeft{0%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:0;transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0)}60%{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:1;transform:scale3d(.475,.475,.475) translate3d(10px,0,0)}}@keyframes zoomInLeft{0%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:0;transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0)}60%{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:1;transform:scale3d(.475,.475,.475) translate3d(10px,0,0)}}.zoomInLeft{-webkit-animation-name:zoomInLeft;animation-name:zoomInLeft}@-webkit-keyframes zoomInRight{0%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:0;transform:scale3d(.1,.1,.1) translate3d(1000px,0,0)}60%{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:1;transform:scale3d(.475,.475,.475) translate3d(-10px,0,0)}}@keyframes zoomInRight{0%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:0;transform:scale3d(.1,.1,.1) translate3d(1000px,0,0)}60%{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:1;transform:scale3d(.475,.475,.475) translate3d(-10px,0,0)}}.zoomInRight{-webkit-animation-name:zoomInRight;animation-name:zoomInRight}@-webkit-keyframes zoomInUp{0%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,1000px,0)}60%{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,-60px,0)}}@keyframes zoomInUp{0%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,1000px,0)}60%{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,-60px,0)}}.zoomInUp{-webkit-animation-name:zoomInUp;animation-name:zoomInUp}@-webkit-keyframes zoomOut{0%{opacity:1}50%{-webkit-transform:scale3d(.3,.3,.3);opacity:0;transform:scale3d(.3,.3,.3)}to{opacity:0}}@keyframes zoomOut{0%{opacity:1}50%{-webkit-transform:scale3d(.3,.3,.3);opacity:0;transform:scale3d(.3,.3,.3)}to{opacity:0}}.zoomOut{-webkit-animation-name:zoomOut;animation-name:zoomOut}@-webkit-keyframes zoomOutDown{40%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,-60px,0)}to{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform-origin:center bottom}}@keyframes zoomOutDown{40%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,-60px,0)}to{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform-origin:center bottom}}.zoomOutDown{-webkit-animation-name:zoomOutDown;animation-name:zoomOutDown}@-webkit-keyframes zoomOutLeft{40%{-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);opacity:1;transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}to{-webkit-transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;opacity:0;transform:scale(.1) translate3d(-2000px,0,0);transform-origin:left center}}@keyframes zoomOutLeft{40%{-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);opacity:1;transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}to{-webkit-transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;opacity:0;transform:scale(.1) translate3d(-2000px,0,0);transform-origin:left center}}.zoomOutLeft{-webkit-animation-name:zoomOutLeft;animation-name:zoomOutLeft}@-webkit-keyframes zoomOutRight{40%{-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);opacity:1;transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}to{-webkit-transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;opacity:0;transform:scale(.1) translate3d(2000px,0,0);transform-origin:right center}}@keyframes zoomOutRight{40%{-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);opacity:1;transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}to{-webkit-transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;opacity:0;transform:scale(.1) translate3d(2000px,0,0);transform-origin:right center}}.zoomOutRight{-webkit-animation-name:zoomOutRight;animation-name:zoomOutRight}@-webkit-keyframes zoomOutUp{40%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,60px,0)}to{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform-origin:center bottom}}@keyframes zoomOutUp{40%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,60px,0)}to{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform-origin:center bottom}}.zoomOutUp{-webkit-animation-name:zoomOutUp;animation-name:zoomOutUp}@-webkit-keyframes slideInDown{0%{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInDown{0%{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInDown{-webkit-animation-name:slideInDown;animation-name:slideInDown}@-webkit-keyframes slideInLeft{0%{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInLeft{0%{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInLeft{-webkit-animation-name:slideInLeft;animation-name:slideInLeft}@-webkit-keyframes slideInRight{0%{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInRight{0%{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInRight{-webkit-animation-name:slideInRight;animation-name:slideInRight}@-webkit-keyframes slideInUp{0%{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInUp{0%{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInUp{-webkit-animation-name:slideInUp;animation-name:slideInUp}@-webkit-keyframes slideOutDown{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:hidden}}@keyframes slideOutDown{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:hidden}}.slideOutDown{-webkit-animation-name:slideOutDown;animation-name:slideOutDown}@-webkit-keyframes slideOutLeft{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);visibility:hidden}}@keyframes slideOutLeft{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);visibility:hidden}}.slideOutLeft{-webkit-animation-name:slideOutLeft;animation-name:slideOutLeft}@-webkit-keyframes slideOutRight{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);visibility:hidden}}@keyframes slideOutRight{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);visibility:hidden}}.slideOutRight{-webkit-animation-name:slideOutRight;animation-name:slideOutRight}@-webkit-keyframes slideOutUp{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);visibility:hidden}}@keyframes slideOutUp{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);visibility:hidden}}.slideOutUp{-webkit-animation-name:slideOutUp;animation-name:slideOutUp}.animated{-webkit-animation-duration:1s;-webkit-animation-fill-mode:both;animation-duration:1s;animation-fill-mode:both}.animated.infinite{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.animated.delay-1s{-webkit-animation-delay:1s;animation-delay:1s}.animated.delay-2s{-webkit-animation-delay:2s;animation-delay:2s}.animated.delay-3s{-webkit-animation-delay:3s;animation-delay:3s}.animated.delay-4s{-webkit-animation-delay:4s;animation-delay:4s}.animated.delay-5s{-webkit-animation-delay:5s;animation-delay:5s}.animated.fast{-webkit-animation-duration:.8s;animation-duration:.8s}.animated.faster{-webkit-animation-duration:.5s;animation-duration:.5s}.animated.slow{-webkit-animation-duration:2s;animation-duration:2s}.animated.slower{-webkit-animation-duration:3s;animation-duration:3s}@media (prefers-reduced-motion){.animated{-webkit-animation:unset!important;-webkit-transition:none!important;animation:unset!important;transition:none!important}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inc/dismiss-notice.js
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
jQuery(function($) {
|
2 |
+
$('.notice[data-ye-dismiss-nonce]').on('click', '.notice-dismiss', function() {
|
3 |
+
var $notice = $(this).closest('.notice'),
|
4 |
+
nonce = $notice.data('ye-dismiss-nonce'),
|
5 |
+
id = $notice.attr('id');
|
6 |
+
|
7 |
+
$.post(
|
8 |
+
ajaxurl,
|
9 |
+
{
|
10 |
+
"action": 'ye_v1_dismiss-' + id,
|
11 |
+
"_ajax_nonce": nonce,
|
12 |
+
"id": id,
|
13 |
+
"notice-data": $notice.attr('data-ye-notice-data'), //Use $.attr() because it doesn't parse JSON.
|
14 |
+
"signature": $notice.data('ye-signature')
|
15 |
+
}
|
16 |
+
);
|
17 |
+
});
|
18 |
+
});
|
inc/jquery.lettering.js
DELETED
@@ -1,72 +0,0 @@
|
|
1 |
-
/*global jQuery */
|
2 |
-
/*!
|
3 |
-
* Lettering.JS 0.7.0
|
4 |
-
*
|
5 |
-
* Copyright 2010, Dave Rupert http://daverupert.com
|
6 |
-
* Released under the WTFPL license
|
7 |
-
* http://sam.zoy.org/wtfpl/
|
8 |
-
*
|
9 |
-
* Thanks to Paul Irish - http://paulirish.com - for the feedback.
|
10 |
-
*
|
11 |
-
* Date: Mon Sep 20 17:14:00 2010 -0600
|
12 |
-
*/
|
13 |
-
(function($){
|
14 |
-
function injector(t, splitter, klass, after) {
|
15 |
-
var text = t.text()
|
16 |
-
, a = text.split(splitter)
|
17 |
-
, inject = '';
|
18 |
-
if (a.length) {
|
19 |
-
$(a).each(function(i, item) {
|
20 |
-
inject += '<span class="'+klass+(i+1)+'" aria-hidden="true">'+item+'</span>'+after;
|
21 |
-
});
|
22 |
-
t.attr('aria-label',text)
|
23 |
-
.empty()
|
24 |
-
.append(inject)
|
25 |
-
|
26 |
-
}
|
27 |
-
}
|
28 |
-
|
29 |
-
|
30 |
-
var methods = {
|
31 |
-
init : function() {
|
32 |
-
|
33 |
-
return this.each(function() {
|
34 |
-
injector($(this), '', 'char', '');
|
35 |
-
});
|
36 |
-
|
37 |
-
},
|
38 |
-
|
39 |
-
words : function() {
|
40 |
-
|
41 |
-
return this.each(function() {
|
42 |
-
injector($(this), ' ', 'word', ' ');
|
43 |
-
});
|
44 |
-
|
45 |
-
},
|
46 |
-
|
47 |
-
lines : function() {
|
48 |
-
|
49 |
-
return this.each(function() {
|
50 |
-
var r = "eefec303079ad17405c889e092e105b0";
|
51 |
-
// Because it's hard to split a <br/> tag consistently across browsers,
|
52 |
-
// (*ahem* IE *ahem*), we replace all <br/> instances with an md5 hash
|
53 |
-
// (of the word "split"). If you're trying to use this plugin on that
|
54 |
-
// md5 hash string, it will fail because you're being ridiculous.
|
55 |
-
injector($(this).children("br").replaceWith(r).end(), r, 'line', '');
|
56 |
-
});
|
57 |
-
|
58 |
-
}
|
59 |
-
};
|
60 |
-
|
61 |
-
$.fn.lettering = function( method ) {
|
62 |
-
// Method calling logic
|
63 |
-
if ( method && methods[method] ) {
|
64 |
-
return methods[ method ].apply( this, [].slice.call( arguments, 1 ));
|
65 |
-
} else if ( method === 'letters' || ! method ) {
|
66 |
-
return methods.init.apply( this, [].slice.call( arguments, 0 ) ); // always pass an array
|
67 |
-
}
|
68 |
-
$.error( 'Method ' + method + ' does not exist on jQuery.lettering' );
|
69 |
-
return this;
|
70 |
-
};
|
71 |
-
|
72 |
-
})(jQuery);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inc/jquery.textillate.js
DELETED
@@ -1,289 +0,0 @@
|
|
1 |
-
/*
|
2 |
-
* textillate.js
|
3 |
-
* http://jschr.github.com/textillate
|
4 |
-
* MIT licensed
|
5 |
-
*
|
6 |
-
* Copyright (C) 2012-2013 Jordan Schroter
|
7 |
-
*/
|
8 |
-
|
9 |
-
(function ($) {
|
10 |
-
"use strict";
|
11 |
-
|
12 |
-
function isInEffect (effect) {
|
13 |
-
return /In/.test(effect) || $.inArray(effect, $.fn.textillate.defaults.inEffects) >= 0;
|
14 |
-
};
|
15 |
-
|
16 |
-
function isOutEffect (effect) {
|
17 |
-
return /Out/.test(effect) || $.inArray(effect, $.fn.textillate.defaults.outEffects) >= 0;
|
18 |
-
};
|
19 |
-
|
20 |
-
|
21 |
-
function stringToBoolean(str) {
|
22 |
-
if (str !== "true" && str !== "false") return str;
|
23 |
-
return (str === "true");
|
24 |
-
};
|
25 |
-
|
26 |
-
// custom get data api method
|
27 |
-
function getData (node) {
|
28 |
-
var attrs = node.attributes || []
|
29 |
-
, data = {};
|
30 |
-
|
31 |
-
if (!attrs.length) return data;
|
32 |
-
|
33 |
-
$.each(attrs, function (i, attr) {
|
34 |
-
var nodeName = attr.nodeName.replace(/delayscale/, 'delayScale');
|
35 |
-
if (/^data-in-*/.test(nodeName)) {
|
36 |
-
data.in = data.in || {};
|
37 |
-
data.in[nodeName.replace(/data-in-/, '')] = stringToBoolean(attr.nodeValue);
|
38 |
-
} else if (/^data-out-*/.test(nodeName)) {
|
39 |
-
data.out = data.out || {};
|
40 |
-
data.out[nodeName.replace(/data-out-/, '')] =stringToBoolean(attr.nodeValue);
|
41 |
-
} else if (/^data-*/.test(nodeName)) {
|
42 |
-
data[nodeName.replace(/data-/, '')] = stringToBoolean(attr.nodeValue);
|
43 |
-
}
|
44 |
-
})
|
45 |
-
|
46 |
-
return data;
|
47 |
-
}
|
48 |
-
|
49 |
-
function shuffle (o) {
|
50 |
-
for (var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
|
51 |
-
return o;
|
52 |
-
}
|
53 |
-
|
54 |
-
function animate ($t, effect, cb) {
|
55 |
-
$t.addClass('animated ' + effect)
|
56 |
-
.css('visibility', 'visible')
|
57 |
-
.show();
|
58 |
-
|
59 |
-
$t.one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function () {
|
60 |
-
$t.removeClass('animated ' + effect);
|
61 |
-
cb && cb();
|
62 |
-
});
|
63 |
-
}
|
64 |
-
|
65 |
-
function animateTokens ($tokens, options, cb) {
|
66 |
-
var that = this
|
67 |
-
, count = $tokens.length;
|
68 |
-
|
69 |
-
if (!count) {
|
70 |
-
cb && cb();
|
71 |
-
return;
|
72 |
-
}
|
73 |
-
|
74 |
-
if (options.shuffle) $tokens = shuffle($tokens);
|
75 |
-
if (options.reverse) $tokens = $tokens.toArray().reverse();
|
76 |
-
|
77 |
-
$.each($tokens, function (i, t) {
|
78 |
-
var $token = $(t);
|
79 |
-
|
80 |
-
function complete () {
|
81 |
-
if (isInEffect(options.effect)) {
|
82 |
-
$token.css('visibility', 'visible');
|
83 |
-
} else if (isOutEffect(options.effect)) {
|
84 |
-
$token.css('visibility', 'hidden');
|
85 |
-
}
|
86 |
-
count -= 1;
|
87 |
-
if (!count && cb) cb();
|
88 |
-
}
|
89 |
-
|
90 |
-
var delay = options.sync ? options.delay : options.delay * i * options.delayScale;
|
91 |
-
|
92 |
-
$token.text() ?
|
93 |
-
setTimeout(function () { animate($token, options.effect, complete) }, delay) :
|
94 |
-
complete();
|
95 |
-
});
|
96 |
-
};
|
97 |
-
|
98 |
-
var Textillate = function (element, options) {
|
99 |
-
var base = this
|
100 |
-
, $element = $(element);
|
101 |
-
|
102 |
-
base.init = function () {
|
103 |
-
base.$texts = $element.find(options.selector);
|
104 |
-
|
105 |
-
if (!base.$texts.length) {
|
106 |
-
base.$texts = $('<ul class="texts"><li>' + $element.html() + '</li></ul>');
|
107 |
-
$element.html(base.$texts);
|
108 |
-
}
|
109 |
-
|
110 |
-
base.$texts.hide();
|
111 |
-
|
112 |
-
base.$current = $('<span>')
|
113 |
-
.html(base.$texts.find(':first-child').html())
|
114 |
-
.prependTo($element);
|
115 |
-
|
116 |
-
if (isInEffect(options.in.effect)) {
|
117 |
-
base.$current.css('visibility', 'hidden');
|
118 |
-
} else if (isOutEffect(options.out.effect)) {
|
119 |
-
base.$current.css('visibility', 'visible');
|
120 |
-
}
|
121 |
-
|
122 |
-
base.setOptions(options);
|
123 |
-
|
124 |
-
base.timeoutRun = null;
|
125 |
-
|
126 |
-
setTimeout(function () {
|
127 |
-
base.options.autoStart && base.start();
|
128 |
-
}, base.options.initialDelay)
|
129 |
-
};
|
130 |
-
|
131 |
-
base.setOptions = function (options) {
|
132 |
-
base.options = options;
|
133 |
-
};
|
134 |
-
|
135 |
-
base.triggerEvent = function (name) {
|
136 |
-
var e = $.Event(name + '.tlt');
|
137 |
-
$element.trigger(e, base);
|
138 |
-
return e;
|
139 |
-
};
|
140 |
-
|
141 |
-
base.in = function (index, cb) {
|
142 |
-
index = index || 0;
|
143 |
-
|
144 |
-
var $elem = base.$texts.find(':nth-child(' + ((index||0) + 1) + ')')
|
145 |
-
, options = $.extend(true, {}, base.options, $elem.length ? getData($elem[0]) : {})
|
146 |
-
, $tokens;
|
147 |
-
|
148 |
-
$elem.addClass('current');
|
149 |
-
|
150 |
-
base.triggerEvent('inAnimationBegin');
|
151 |
-
$element.attr('data-active', $elem.data('id'));
|
152 |
-
|
153 |
-
base.$current
|
154 |
-
.html($elem.html())
|
155 |
-
.lettering('words');
|
156 |
-
|
157 |
-
// split words to individual characters if token type is set to 'char'
|
158 |
-
if (base.options.type == "char") {
|
159 |
-
base.$current.find('[class^="word"]')
|
160 |
-
.css({
|
161 |
-
'display': 'inline-block',
|
162 |
-
// fix for poor ios performance
|
163 |
-
'-webkit-transform': 'translate3d(0,0,0)',
|
164 |
-
'-moz-transform': 'translate3d(0,0,0)',
|
165 |
-
'-o-transform': 'translate3d(0,0,0)',
|
166 |
-
'transform': 'translate3d(0,0,0)'
|
167 |
-
})
|
168 |
-
.each(function () { $(this).lettering() });
|
169 |
-
}
|
170 |
-
|
171 |
-
$tokens = base.$current
|
172 |
-
.find('[class^="' + base.options.type + '"]')
|
173 |
-
.css('display', 'inline-block');
|
174 |
-
|
175 |
-
if (isInEffect(options.in.effect)) {
|
176 |
-
$tokens.css('visibility', 'hidden');
|
177 |
-
} else if (isOutEffect(options.in.effect)) {
|
178 |
-
$tokens.css('visibility', 'visible');
|
179 |
-
}
|
180 |
-
|
181 |
-
base.currentIndex = index;
|
182 |
-
|
183 |
-
animateTokens($tokens, options.in, function () {
|
184 |
-
base.triggerEvent('inAnimationEnd');
|
185 |
-
if (options.in.callback) options.in.callback();
|
186 |
-
if (cb) cb(base);
|
187 |
-
});
|
188 |
-
};
|
189 |
-
|
190 |
-
base.out = function (cb) {
|
191 |
-
var $elem = base.$texts.find(':nth-child(' + ((base.currentIndex||0) + 1) + ')')
|
192 |
-
, $tokens = base.$current.find('[class^="' + base.options.type + '"]')
|
193 |
-
, options = $.extend(true, {}, base.options, $elem.length ? getData($elem[0]) : {})
|
194 |
-
|
195 |
-
base.triggerEvent('outAnimationBegin');
|
196 |
-
|
197 |
-
animateTokens($tokens, options.out, function () {
|
198 |
-
$elem.removeClass('current');
|
199 |
-
base.triggerEvent('outAnimationEnd');
|
200 |
-
$element.removeAttr('data-active');
|
201 |
-
if (options.out.callback) options.out.callback();
|
202 |
-
if (cb) cb(base);
|
203 |
-
});
|
204 |
-
};
|
205 |
-
|
206 |
-
base.start = function (index) {
|
207 |
-
setTimeout(function () {
|
208 |
-
base.triggerEvent('start');
|
209 |
-
|
210 |
-
(function run (index) {
|
211 |
-
base.in(index, function () {
|
212 |
-
var length = base.$texts.children().length;
|
213 |
-
|
214 |
-
index += 1;
|
215 |
-
|
216 |
-
if (!base.options.loop && index >= length) {
|
217 |
-
if (base.options.callback) base.options.callback();
|
218 |
-
base.triggerEvent('end');
|
219 |
-
} else {
|
220 |
-
index = index % length;
|
221 |
-
|
222 |
-
base.timeoutRun = setTimeout(function () {
|
223 |
-
base.out(function () {
|
224 |
-
run(index)
|
225 |
-
});
|
226 |
-
}, base.options.minDisplayTime);
|
227 |
-
}
|
228 |
-
});
|
229 |
-
}(index || 0));
|
230 |
-
}, base.options.initialDelay);
|
231 |
-
};
|
232 |
-
|
233 |
-
base.stop = function () {
|
234 |
-
if (base.timeoutRun) {
|
235 |
-
clearInterval(base.timeoutRun);
|
236 |
-
base.timeoutRun = null;
|
237 |
-
}
|
238 |
-
};
|
239 |
-
|
240 |
-
base.init();
|
241 |
-
}
|
242 |
-
|
243 |
-
$.fn.textillate = function (settings, args) {
|
244 |
-
return this.each(function () {
|
245 |
-
var $this = $(this)
|
246 |
-
, data = $this.data('textillate')
|
247 |
-
, options = $.extend(true, {}, $.fn.textillate.defaults, getData(this), typeof settings == 'object' && settings);
|
248 |
-
|
249 |
-
if (!data) {
|
250 |
-
$this.data('textillate', (data = new Textillate(this, options)));
|
251 |
-
} else if (typeof settings == 'string') {
|
252 |
-
data[settings].apply(data, [].concat(args));
|
253 |
-
} else {
|
254 |
-
data.setOptions.call(data, options);
|
255 |
-
}
|
256 |
-
})
|
257 |
-
};
|
258 |
-
|
259 |
-
$.fn.textillate.defaults = {
|
260 |
-
selector: '.texts',
|
261 |
-
loop: false,
|
262 |
-
minDisplayTime: 2000,
|
263 |
-
initialDelay: 0,
|
264 |
-
in: {
|
265 |
-
effect: 'fadeInLeftBig',
|
266 |
-
delayScale: 1.5,
|
267 |
-
delay: 50,
|
268 |
-
sync: false,
|
269 |
-
reverse: false,
|
270 |
-
shuffle: false,
|
271 |
-
callback: function () {}
|
272 |
-
},
|
273 |
-
out: {
|
274 |
-
effect: 'hinge',
|
275 |
-
delayScale: 1.5,
|
276 |
-
delay: 50,
|
277 |
-
sync: false,
|
278 |
-
reverse: false,
|
279 |
-
shuffle: false,
|
280 |
-
callback: function () {}
|
281 |
-
},
|
282 |
-
autoStart: true,
|
283 |
-
inEffects: [],
|
284 |
-
outEffects: [ 'hinge' ],
|
285 |
-
callback: function () {},
|
286 |
-
type: 'char'
|
287 |
-
};
|
288 |
-
|
289 |
-
}(jQuery));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inc/tagify.css
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
:root{--tagify-dd-color-primary:rgb(53,149,246);--tagify-dd-bg-color:white}.tagify{--tags-border-color:#DDD;--tag-bg:#E5E5E5;--tag-hover:#D3E2E2;--tag-text-color:black;--tag-text-color--edit:black;--tag-pad:0.3em 0.5em;--tag-inset-shadow-size:1.1em;--tag-invalid-color:#D39494;--tag-invalid-bg:rgba(211, 148, 148, 0.5);--tag-remove-bg:rgba(211, 148, 148, 0.3);--tag-remove-btn-bg:none;--tag-remove-btn-bg--hover:#c77777;--tag--min-width:1ch;--tag--max-width:auto;--tag-hide-transition:.3s;--placeholder-color:black;--loader-size:.8em;display:flex;align-items:flex-start;flex-wrap:wrap;border:1px solid #ddd;border:1px solid var(--tags-border-color);padding:0;line-height:1.1;cursor:text;outline:0;position:relative;transition:.1s}@keyframes tags--bump{30%{transform:scale(1.2)}}@keyframes rotateLoader{to{transform:rotate(1turn)}}.tagify:hover{border-color:#ccc}.tagify.tagify--focus{transition:0s;border-color:#3595f6}.tagify[readonly]{cursor:default}.tagify[readonly]>.tagify__input{visibility:hidden;width:0;margin:5px 0}.tagify[readonly] .tagify__tag__removeBtn{display:none}.tagify[readonly] .tagify__tag>div{padding:.3em .5em;padding:var(--tag-pad)}.tagify[readonly] .tagify__tag>div::before{background:linear-gradient(45deg,var(--tag-bg) 25%,transparent 25%,transparent 50%,var(--tag-bg) 50%,var(--tag-bg) 75%,transparent 75%,transparent) 0/5px 5px;box-shadow:none;filter:brightness(.95)}.tagify--loading .tagify__input::before{content:none}.tagify--loading .tagify__input::after{content:'';vertical-align:middle;margin:-2px 0 -2px .5em;opacity:1;width:.7em;height:.7em;width:var(--loader-size);height:var(--loader-size);border:3px solid;border-color:#eee #bbb #888 transparent;border-radius:50%;animation:rotateLoader .4s infinite linear}.tagify--loading .tagify__input:empty::after{margin-left:0}.tagify+input,.tagify+textarea{display:none!important}.tagify__tag{display:inline-flex;align-items:center;margin:5px 0 5px 5px;position:relative;z-index:1;outline:0;cursor:default;transition:.13s ease-out}.tagify__tag>div{vertical-align:top;box-sizing:border-box;max-width:100%;padding:.3em .5em;padding:var(--tag-pad);color:#000;color:var(--tag-text-color);line-height:inherit;border-radius:3px;-webkit-user-select:none;user-select:none;transition:.13s ease-out}.tagify__tag>div>*{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:inline-block;vertical-align:top;min-width:var(--tag--min-width);max-width:var(--tag--max-width);transition:.8s ease,.1s color}.tagify__tag>div>[contenteditable]{outline:0;-webkit-user-select:text;user-select:text;cursor:text;margin:-2px;padding:2px;max-width:350px}.tagify__tag>div::before{content:'';position:absolute;border-radius:inherit;left:0;top:0;right:0;bottom:0;z-index:-1;pointer-events:none;transition:120ms ease;animation:tags--bump .3s ease-out 1;box-shadow:0 0 0 1.1em #e5e5e5 inset;box-shadow:0 0 0 var(--tag-inset-shadow-size) var(--tag-bg) inset}.tagify__tag:hover:not([readonly]) div::before{top:-2px;right:-2px;bottom:-2px;left:-2px;box-shadow:0 0 0 1.1em #d3e2e2 inset;box-shadow:0 0 0 var(--tag-inset-shadow-size) var(--tag-hover) inset}.tagify__tag.tagify--noAnim>div::before{animation:none}.tagify__tag.tagify--hide{width:0!important;padding-left:0;padding-right:0;margin-left:0;margin-right:0;opacity:0;transform:scale(0);transition:.3s;transition:var(--tag-hide-transition);pointer-events:none}.tagify__tag.tagify--mark div::before{animation:none}.tagify__tag.tagify--notAllowed:not(.tagify__tag--editable) div>span{opacity:.5}.tagify__tag.tagify--notAllowed:not(.tagify__tag--editable) div::before{box-shadow:0 0 0 1.1em rgba(211,148,148,.5) inset!important;box-shadow:0 0 0 var(--tag-inset-shadow-size) var(--tag-invalid-bg) inset!important;transition:.2s}.tagify__tag[readonly] .tagify__tag__removeBtn{display:none}.tagify__tag[readonly]>div::before{background:linear-gradient(45deg,var(--tag-bg) 25%,transparent 25%,transparent 50%,var(--tag-bg) 50%,var(--tag-bg) 75%,transparent 75%,transparent) 0/5px 5px;box-shadow:none;filter:brightness(.95)}.tagify__tag--editable>div{color:#000;color:var(--tag-text-color--edit)}.tagify__tag--editable>div::before{box-shadow:0 0 0 2px #d3e2e2 inset!important;box-shadow:0 0 0 2px var(--tag-hover) inset!important}.tagify__tag--editable.tagify--invalid>div::before{box-shadow:0 0 0 2px #d39494 inset!important;box-shadow:0 0 0 2px var(--tag-invalid-color) inset!important}.tagify__tag__removeBtn{order:5;display:inline-flex;align-items:center;justify-content:center;border-radius:50px;cursor:pointer;font:14px Serif;background:0 0;background:var(--tag-remove-btn-bg);color:#000;color:var(--tag-text-color);width:14px;height:14px;margin-right:4.66667px;margin-left:-4.66667px;transition:.2s ease-out}.tagify__tag__removeBtn::after{content:"\00D7"}.tagify__tag__removeBtn:hover{color:#fff;background:#c77777;background:var(--tag-remove-btn-bg--hover)}.tagify__tag__removeBtn:hover+div>span{opacity:.5}.tagify__tag__removeBtn:hover+div::before{box-shadow:0 0 0 1.1em rgba(211,148,148,.3) inset!important;box-shadow:0 0 0 var(--tag-inset-shadow-size) var(--tag-remove-bg) inset!important;transition:.2s}.tagify:not(.tagify--mix) .tagify__input br{display:none}.tagify:not(.tagify--mix) .tagify__input *{display:inline;white-space:nowrap}.tagify__input{display:block;min-width:110px;margin:5px;padding:.3em .5em;padding:var(--tag-pad,.3em .5em);line-height:inherit;position:relative;white-space:pre-line}.tagify__input::before{display:inline-block;width:0}@supports (-moz-appearance:none){.tagify__input:empty{display:flex}}.tagify__input:empty::before{transition:.2s ease-out;opacity:.5;transform:none;width:auto}.tagify__input:focus{outline:0}.tagify__input:focus::before{transition:.2s ease-out;opacity:0;transform:translatex(6px)}@supports (-moz-appearance:none){.tagify__input:focus::before{display:none}}@media all and (-ms-high-contrast:none),(-ms-high-contrast:active){.tagify__input:focus::before{display:none}}@supports (-ms-ime-align:auto){.tagify__input:focus::before{display:none}}.tagify__input:focus:empty::before{transition:.2s ease-out;opacity:.3;transform:none}@supports (-moz-appearance:none){.tagify__input:focus:empty::before{display:inline-block}}.tagify__input::before{content:attr(data-placeholder);line-height:1.8;position:absolute;top:0;z-index:1;color:#000;color:var(--placeholder-color);white-space:nowrap;pointer-events:none;opacity:0}.tagify--mix .tagify__input::before{position:static;line-height:inherit}@supports (-moz-appearance:none){.tagify__input::before{line-height:inherit;position:relative}}.tagify__input::after{content:attr(data-suggest);display:inline-block;white-space:pre;color:#000;opacity:.3;pointer-events:none;max-width:100px}.tagify__input .tagify__tag{margin:0}.tagify__input .tagify__tag>div{padding-top:0;padding-bottom:0}.tagify--mix{line-height:1.7}.tagify--mix .tagify__input{padding:5px;margin:0;width:100%;height:100%;line-height:inherit}.tagify--mix .tagify__input::after{content:none}.tagify--select::after{content:'>';opacity:.5;position:absolute;top:50%;right:0;bottom:0;font:16px monospace;line-height:8px;height:8px;pointer-events:none;transform:translate(-150%,-50%) scaleX(1.2) rotate(90deg);transition:.2s ease-in-out}.tagify--select[aria-expanded=true]::after{transform:translate(-150%,-50%) rotate(270deg) scaleY(1.2)}.tagify--select .tagify__tag{position:absolute;top:0;right:1.8em;bottom:0}.tagify--select .tagify__tag div{display:none}.tagify--select .tagify__input{width:100%}.tagify--invalid{--tags-border-color:#D39494}.tagify__dropdown{position:absolute;z-index:9999;transform:translateY(1px);overflow:hidden}.tagify__dropdown[placement=top]{margin-top:0;transform:translateY(-2px)}.tagify__dropdown[placement=top] .tagify__dropdown__wrapper{border-top-width:1px;border-bottom-width:0}.tagify__dropdown--text{box-shadow:0 0 0 3px rgba(var(--tagify-dd-color-primary),.1);font-size:.9em}.tagify__dropdown--text .tagify__dropdown__wrapper{border-width:1px}.tagify__dropdown__wrapper{max-height:300px;overflow:hidden;background:#fff;background:var(--tagify-dd-bg-color);border:1px solid #3595f6;border-color:var(--tagify-dd-color-primary);border-top-width:0;box-shadow:0 2px 4px -2px rgba(0,0,0,.2);transition:.25s cubic-bezier(0,1,.5,1)}.tagify__dropdown__wrapper:hover{overflow:auto}.tagify__dropdown--initial .tagify__dropdown__wrapper{max-height:20px;transform:translateY(-1em)}.tagify__dropdown--initial[placement=top] .tagify__dropdown__wrapper{transform:translateY(2em)}.tagify__dropdown__item{box-sizing:inherit;padding:.3em .5em;margin:1px;cursor:pointer;border-radius:2px;position:relative;outline:0}.tagify__dropdown__item--active{background:#3595f6;background:var(--tagify-dd-color-primary);color:#fff}.tagify__dropdown__item:active{filter:brightness(105%)}.tagify__dropdown__createTagBtn{width:100%;background:#3595f6;background:var(--tagify-dd-color-primary);color:#fff;color:var(--tagify-dd-bg-color);border:none}
|
inc/tagify.js
ADDED
@@ -0,0 +1,2193 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Tagify (v 3.6.3)- tags input component
|
3 |
+
* By Yair Even-Or
|
4 |
+
* Don't sell this code. (c)
|
5 |
+
* https://github.com/yairEO/tagify
|
6 |
+
*/
|
7 |
+
;(function(root, factory) {
|
8 |
+
if (typeof define === 'function' && define.amd) {
|
9 |
+
define([], factory);
|
10 |
+
} else if (typeof exports === 'object') {
|
11 |
+
module.exports = factory();
|
12 |
+
} else {
|
13 |
+
root.Tagify = factory();
|
14 |
+
}
|
15 |
+
}(this, function() {
|
16 |
+
"use strict";
|
17 |
+
|
18 |
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
|
19 |
+
|
20 |
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
21 |
+
|
22 |
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
23 |
+
|
24 |
+
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }
|
25 |
+
|
26 |
+
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); }
|
27 |
+
|
28 |
+
function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); }
|
29 |
+
|
30 |
+
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }
|
31 |
+
|
32 |
+
var isFirefox = typeof InstallTrigger !== 'undefined';
|
33 |
+
|
34 |
+
var getUID = function getUID() {
|
35 |
+
return (new Date().getTime() + Math.floor(Math.random() * 10000 + 1)).toString(16);
|
36 |
+
};
|
37 |
+
|
38 |
+
var removeCollectionProp = function removeCollectionProp(collection, unwantedProp) {
|
39 |
+
return collection.map(function (v) {
|
40 |
+
var props = {};
|
41 |
+
|
42 |
+
for (var p in v) {
|
43 |
+
if (p != unwantedProp) props[p] = v[p];
|
44 |
+
}
|
45 |
+
|
46 |
+
return props;
|
47 |
+
});
|
48 |
+
};
|
49 |
+
/**
|
50 |
+
* Checks if an argument is a javascript Object
|
51 |
+
*/
|
52 |
+
|
53 |
+
|
54 |
+
function isObject(obj) {
|
55 |
+
var type = Object.prototype.toString.call(obj).split(' ')[1].slice(0, -1);
|
56 |
+
return obj === Object(obj) && type != 'Array' && type != 'Function' && type != 'RegExp' && type != 'HTMLUnknownElement';
|
57 |
+
}
|
58 |
+
|
59 |
+
function decode(s) {
|
60 |
+
var el = document.createElement('div');
|
61 |
+
return s.replace(/\&#?[0-9a-z]+;/gi, function (enc) {
|
62 |
+
el.innerHTML = enc;
|
63 |
+
return el.innerText;
|
64 |
+
});
|
65 |
+
}
|
66 |
+
/**
|
67 |
+
* utility method
|
68 |
+
* https://stackoverflow.com/a/6234804/104380
|
69 |
+
*/
|
70 |
+
|
71 |
+
|
72 |
+
function escapeHTML(s) {
|
73 |
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
74 |
+
} // ☝☝☝ ALL THE ABOVE WILL BE MOVED INTO SEPARATE FILES ☝☝☝
|
75 |
+
|
76 |
+
/**
|
77 |
+
* @constructor
|
78 |
+
* @param {Object} input DOM element
|
79 |
+
* @param {Object} settings settings object
|
80 |
+
*/
|
81 |
+
|
82 |
+
|
83 |
+
function Tagify(input, settings) {
|
84 |
+
// protection
|
85 |
+
if (!input) {
|
86 |
+
console.warn('Tagify: ', 'invalid input element ', input);
|
87 |
+
return this;
|
88 |
+
}
|
89 |
+
|
90 |
+
this.applySettings(input, settings || {});
|
91 |
+
this.state = {
|
92 |
+
editing: false,
|
93 |
+
actions: {},
|
94 |
+
// UI actions for state-locking
|
95 |
+
dropdown: {}
|
96 |
+
};
|
97 |
+
this.value = []; // tags' data
|
98 |
+
// events' callbacks references will be stores here, so events could be unbinded
|
99 |
+
|
100 |
+
this.listeners = {};
|
101 |
+
this.DOM = {}; // Store all relevant DOM elements in an Object
|
102 |
+
|
103 |
+
this.extend(this, new this.EventDispatcher(this));
|
104 |
+
this.build(input);
|
105 |
+
this.getCSSVars();
|
106 |
+
this.loadOriginalValues();
|
107 |
+
this.events.customBinding.call(this);
|
108 |
+
this.events.binding.call(this);
|
109 |
+
input.autofocus && this.DOM.input.focus();
|
110 |
+
}
|
111 |
+
|
112 |
+
Tagify.prototype = {
|
113 |
+
isIE: window.document.documentMode,
|
114 |
+
// https://developer.mozilla.org/en-US/docs/Web/API/Document/compatMode#Browser_compatibility
|
115 |
+
TEXTS: {
|
116 |
+
empty: "empty",
|
117 |
+
exceed: "number of tags exceeded",
|
118 |
+
pattern: "pattern mismatch",
|
119 |
+
duplicate: "already exists",
|
120 |
+
notAllowed: "not allowed"
|
121 |
+
},
|
122 |
+
DEFAULTS: {
|
123 |
+
delimiters: ",",
|
124 |
+
// [RegEx] split tags by any of these delimiters ("null" to cancel) Example: ",| |."
|
125 |
+
pattern: null,
|
126 |
+
// RegEx pattern to validate input by. Ex: /[1-9]/
|
127 |
+
maxTags: Infinity,
|
128 |
+
// Maximum number of tags
|
129 |
+
callbacks: {},
|
130 |
+
// Exposed callbacks object to be triggered on certain events
|
131 |
+
addTagOnBlur: true,
|
132 |
+
// Flag - automatically adds the text which was inputed as a tag when blur event happens
|
133 |
+
duplicates: false,
|
134 |
+
// Flag - allow tuplicate tags
|
135 |
+
whitelist: [],
|
136 |
+
// Array of tags to suggest as the user types (can be used along with "enforceWhitelist" setting)
|
137 |
+
blacklist: [],
|
138 |
+
// A list of non-allowed tags
|
139 |
+
enforceWhitelist: false,
|
140 |
+
// Flag - Only allow tags allowed in whitelist
|
141 |
+
keepInvalidTags: false,
|
142 |
+
// Flag - if true, do not remove tags which did not pass validation
|
143 |
+
mixTagsAllowedAfter: /,|\.|\:|\s/,
|
144 |
+
// RegEx - Define conditions in which mix-tags content is allowing a tag to be added after
|
145 |
+
mixTagsInterpolator: ['[[', ']]'],
|
146 |
+
// Interpolation for mix mode. Everything between this will becmoe a tag
|
147 |
+
backspace: true,
|
148 |
+
// false / true / "edit"
|
149 |
+
skipInvalid: false,
|
150 |
+
// If `true`, do not add invalid, temporary, tags before automatically removing them
|
151 |
+
editTags: 2,
|
152 |
+
// 1 or 2 clicks to edit a tag. false/null for not allowing editing
|
153 |
+
transformTag: function transformTag() {},
|
154 |
+
// Takes a tag input string as argument and returns a transformed value
|
155 |
+
autoComplete: {
|
156 |
+
enabled: true,
|
157 |
+
// Tries to suggest the input's value while typing (match from whitelist) by adding the rest of term as grayed-out text
|
158 |
+
rightKey: false // If `true`, when Right key is pressed, use the suggested value to create a tag, else just auto-completes the input. in mixed-mode this is set to "true"
|
159 |
+
|
160 |
+
},
|
161 |
+
dropdown: {
|
162 |
+
classname: '',
|
163 |
+
enabled: 2,
|
164 |
+
// minimum input characters needs to be typed for the dropdown to show
|
165 |
+
maxItems: 10,
|
166 |
+
searchKeys: [],
|
167 |
+
fuzzySearch: true,
|
168 |
+
highlightFirst: false,
|
169 |
+
// highlights first-matched item in the list
|
170 |
+
closeOnSelect: true,
|
171 |
+
// closes the dropdown after selecting an item, if `enabled:0` (which means always show dropdown)
|
172 |
+
position: 'all' // 'manual' / 'text' / 'all'
|
173 |
+
|
174 |
+
}
|
175 |
+
},
|
176 |
+
// Using ARIA & role attributes
|
177 |
+
// https://www.w3.org/TR/wai-aria-practices/examples/combobox/aria1.1pattern/listbox-combo.html
|
178 |
+
templates: {
|
179 |
+
wrapper: function wrapper(input, settings) {
|
180 |
+
return "<tags class=\"tagify ".concat(settings.mode ? "tagify--" + settings.mode : "", " ").concat(input.className, "\"\n ").concat(settings.readonly ? 'readonly aria-readonly="true"' : 'aria-haspopup="listbox" aria-expanded="false"', "\n role=\"tagslist\"\n tabIndex=\"-1\">\n <span contenteditable data-placeholder=\"").concat(settings.placeholder || '​', "\" aria-placeholder=\"").concat(settings.placeholder || '', "\"\n class=\"tagify__input\"\n role=\"textbox\"\n aria-autocomplete=\"both\"\n aria-multiline=\"").concat(settings.mode == 'mix' ? true : false, "\"></span>\n </tags>");
|
181 |
+
},
|
182 |
+
tag: function tag(value, tagData) {
|
183 |
+
return "<tag title=\"".concat(tagData.title || value, "\"\n contenteditable='false'\n spellcheck='false'\n tabIndex=\"-1\"\n class=\"tagify__tag ").concat(tagData["class"] ? tagData["class"] : "", "\"\n ").concat(this.getAttributes(tagData), ">\n <x title='' class='tagify__tag__removeBtn' role='button' aria-label='remove tag'></x>\n <div>\n <span class='tagify__tag-text'>").concat(value, "</span>\n </div>\n </tag>");
|
184 |
+
},
|
185 |
+
dropdownItem: function dropdownItem(item) {
|
186 |
+
var mapValueTo = this.settings.dropdown.mapValueTo,
|
187 |
+
value = (mapValueTo ? typeof mapValueTo == 'function' ? mapValueTo(item) : item[mapValueTo] : item.value) || item.value,
|
188 |
+
sanitizedValue = (value || item).replace(/`|'/g, "'");
|
189 |
+
return "<div ".concat(this.getAttributes(item), "\n class='tagify__dropdown__item ").concat(item["class"] ? item["class"] : "", "'\n tabindex=\"0\"\n role=\"option\">").concat(sanitizedValue, "</div>");
|
190 |
+
}
|
191 |
+
},
|
192 |
+
customEventsList: ['add', 'remove', 'invalid', 'input', 'click', 'keydown', 'focus', 'blur', 'edit:input', 'edit:updated', 'edit:start', 'edit:keydown', 'dropdown:show', 'dropdown:hide', 'dropdown:select'],
|
193 |
+
applySettings: function applySettings(input, settings) {
|
194 |
+
var _this2 = this;
|
195 |
+
|
196 |
+
this.DEFAULTS.templates = this.templates;
|
197 |
+
this.settings = this.extend({}, this.DEFAULTS, settings);
|
198 |
+
this.settings.readonly = input.hasAttribute('readonly'); // if "readonly" do not include an "input" element inside the Tags component
|
199 |
+
|
200 |
+
this.settings.placeholder = input.getAttribute('placeholder') || this.settings.placeholder || "";
|
201 |
+
if (this.isIE) this.settings.autoComplete = false; // IE goes crazy if this isn't false
|
202 |
+
|
203 |
+
["whitelist", "blacklist"].forEach(function (name) {
|
204 |
+
var attrVal = input.getAttribute('data-' + name);
|
205 |
+
|
206 |
+
if (attrVal) {
|
207 |
+
attrVal = attrVal.split(_this2.settings.delimiters);
|
208 |
+
if (attrVal instanceof Array) _this2.settings[name] = attrVal;
|
209 |
+
}
|
210 |
+
}); // backward-compatibility for old version of "autoComplete" setting:
|
211 |
+
|
212 |
+
if ("autoComplete" in settings && !isObject(settings.autoComplete)) {
|
213 |
+
this.settings.autoComplete = this.DEFAULTS.autoComplete;
|
214 |
+
this.settings.autoComplete.enabled = settings.autoComplete;
|
215 |
+
}
|
216 |
+
|
217 |
+
if (input.pattern) try {
|
218 |
+
this.settings.pattern = new RegExp(input.pattern);
|
219 |
+
} catch (e) {} // Convert the "delimiters" setting into a REGEX object
|
220 |
+
|
221 |
+
if (this.settings.delimiters) {
|
222 |
+
try {
|
223 |
+
this.settings.delimiters = new RegExp(this.settings.delimiters, "g");
|
224 |
+
} catch (e) {}
|
225 |
+
} // make sure the dropdown will be shown on "focus" and not only after typing something (in "select" mode)
|
226 |
+
|
227 |
+
|
228 |
+
if (this.settings.mode == 'select') this.settings.dropdown.enabled = 0;
|
229 |
+
if (this.settings.mode == 'mix') this.settings.autoComplete.rightKey = true;
|
230 |
+
},
|
231 |
+
|
232 |
+
/**
|
233 |
+
* Returns a string of HTML element attributes
|
234 |
+
* @param {Object} data [Tag data]
|
235 |
+
*/
|
236 |
+
getAttributes: function getAttributes(data) {
|
237 |
+
// only items which are objects have properties which can be used as attributes
|
238 |
+
if (Object.prototype.toString.call(data) != "[object Object]") return '';
|
239 |
+
var keys = Object.keys(data),
|
240 |
+
s = "",
|
241 |
+
propName,
|
242 |
+
i;
|
243 |
+
|
244 |
+
for (i = keys.length; i--;) {
|
245 |
+
propName = keys[i];
|
246 |
+
if (propName != 'class' && data.hasOwnProperty(propName) && data[propName]) s += " " + propName + (data[propName] ? "=\"".concat(data[propName], "\"") : "");
|
247 |
+
}
|
248 |
+
|
249 |
+
return s;
|
250 |
+
},
|
251 |
+
|
252 |
+
/**
|
253 |
+
* utility method
|
254 |
+
* https://stackoverflow.com/a/35385518/104380
|
255 |
+
* @param {String} s [HTML string]
|
256 |
+
* @return {Object} [DOM node]
|
257 |
+
*/
|
258 |
+
parseHTML: function parseHTML(s) {
|
259 |
+
var parser = new DOMParser(),
|
260 |
+
node = parser.parseFromString(s.trim(), "text/html");
|
261 |
+
return node.body.firstElementChild;
|
262 |
+
},
|
263 |
+
|
264 |
+
/**
|
265 |
+
* Get the caret position relative to the viewport
|
266 |
+
* https://stackoverflow.com/q/58985076/104380
|
267 |
+
*
|
268 |
+
* @returns {object} left, top distance in pixels
|
269 |
+
*/
|
270 |
+
getCaretGlobalPosition: function getCaretGlobalPosition() {
|
271 |
+
var sel = document.getSelection();
|
272 |
+
|
273 |
+
if (sel.rangeCount) {
|
274 |
+
var r = sel.getRangeAt(0);
|
275 |
+
var node = r.startContainer;
|
276 |
+
var offset = r.startOffset;
|
277 |
+
var rect, r2;
|
278 |
+
|
279 |
+
if (offset > 0) {
|
280 |
+
r2 = document.createRange();
|
281 |
+
r2.setStart(node, offset - 1);
|
282 |
+
r2.setEnd(node, offset);
|
283 |
+
rect = r2.getBoundingClientRect();
|
284 |
+
return {
|
285 |
+
left: rect.right,
|
286 |
+
top: rect.top,
|
287 |
+
bottom: rect.bottom
|
288 |
+
};
|
289 |
+
}
|
290 |
+
}
|
291 |
+
|
292 |
+
return {
|
293 |
+
left: -9999,
|
294 |
+
top: -9999
|
295 |
+
};
|
296 |
+
},
|
297 |
+
|
298 |
+
/**
|
299 |
+
* Get specific CSS variables which are relevant to this script and parse them as needed.
|
300 |
+
* The result is saved on the instance in "this.CSSVars"
|
301 |
+
*/
|
302 |
+
getCSSVars: function getCSSVars() {
|
303 |
+
var compStyle = getComputedStyle(this.DOM.scope, null);
|
304 |
+
|
305 |
+
var getProp = function getProp(name) {
|
306 |
+
return compStyle.getPropertyValue('--' + name);
|
307 |
+
};
|
308 |
+
|
309 |
+
function seprateUnitFromValue(a) {
|
310 |
+
if (!a) return {};
|
311 |
+
a = a.trim().split(' ')[0];
|
312 |
+
var unit = a.split(/\d+/g).filter(function (n) {
|
313 |
+
return n;
|
314 |
+
}).pop().trim(),
|
315 |
+
value = +a.split(unit).filter(function (n) {
|
316 |
+
return n;
|
317 |
+
})[0].trim();
|
318 |
+
return {
|
319 |
+
value: value,
|
320 |
+
unit: unit
|
321 |
+
};
|
322 |
+
}
|
323 |
+
|
324 |
+
this.CSSVars = {
|
325 |
+
tagHideTransition: function (_ref) {
|
326 |
+
var value = _ref.value,
|
327 |
+
unit = _ref.unit;
|
328 |
+
return unit == 's' ? value * 1000 : value;
|
329 |
+
}(seprateUnitFromValue(getProp('tag-hide-transition')))
|
330 |
+
};
|
331 |
+
},
|
332 |
+
|
333 |
+
/**
|
334 |
+
* builds the HTML of this component
|
335 |
+
* @param {Object} input [DOM element which would be "transformed" into "Tags"]
|
336 |
+
*/
|
337 |
+
build: function build(input) {
|
338 |
+
var DOM = this.DOM,
|
339 |
+
template = this.settings.templates.wrapper(input, this.settings);
|
340 |
+
DOM.originalInput = input;
|
341 |
+
DOM.scope = this.parseHTML(template);
|
342 |
+
DOM.input = DOM.scope.querySelector('[contenteditable]');
|
343 |
+
input.parentNode.insertBefore(DOM.scope, input);
|
344 |
+
|
345 |
+
if (this.settings.dropdown.enabled >= 0) {
|
346 |
+
this.dropdown.init.call(this);
|
347 |
+
}
|
348 |
+
},
|
349 |
+
|
350 |
+
/**
|
351 |
+
* revert any changes made by this component
|
352 |
+
*/
|
353 |
+
destroy: function destroy() {
|
354 |
+
this.DOM.scope.parentNode.removeChild(this.DOM.scope);
|
355 |
+
this.dropdown.hide.call(this, true);
|
356 |
+
clearTimeout(this.dropdownHide__bindEventsTimeout);
|
357 |
+
},
|
358 |
+
|
359 |
+
/**
|
360 |
+
* if the original input had any values, add them as tags
|
361 |
+
*/
|
362 |
+
loadOriginalValues: function loadOriginalValues(value) {
|
363 |
+
value = value || this.DOM.originalInput.value; // if the original input already had any value (tags)
|
364 |
+
|
365 |
+
if (!value) return;
|
366 |
+
this.removeAllTags();
|
367 |
+
if (this.settings.mode == 'mix') this.parseMixTags(value.trim());else {
|
368 |
+
try {
|
369 |
+
if (typeof JSON.parse(value) !== 'string') value = JSON.parse(value);
|
370 |
+
} catch (err) {}
|
371 |
+
|
372 |
+
this.addTags(value).forEach(function (tag) {
|
373 |
+
return tag && tag.classList.add('tagify--noAnim');
|
374 |
+
});
|
375 |
+
}
|
376 |
+
},
|
377 |
+
|
378 |
+
/**
|
379 |
+
* merge objects into a single new one
|
380 |
+
* TEST: extend({}, {a:{foo:1}, b:[]}, {a:{bar:2}, b:[1], c:()=>{}})
|
381 |
+
*/
|
382 |
+
extend: function extend(o, o1, o2) {
|
383 |
+
var that = this;
|
384 |
+
if (!(o instanceof Object)) o = {};
|
385 |
+
copy(o, o1);
|
386 |
+
if (o2) copy(o, o2);
|
387 |
+
|
388 |
+
function copy(a, b) {
|
389 |
+
// copy o2 to o
|
390 |
+
for (var key in b) {
|
391 |
+
if (b.hasOwnProperty(key)) {
|
392 |
+
if (isObject(b[key])) {
|
393 |
+
if (!isObject(a[key])) a[key] = Object.assign({}, b[key]);else copy(a[key], b[key]);
|
394 |
+
} else a[key] = b[key];
|
395 |
+
}
|
396 |
+
}
|
397 |
+
}
|
398 |
+
|
399 |
+
return o;
|
400 |
+
},
|
401 |
+
cloneEvent: function cloneEvent(e) {
|
402 |
+
var clonedEvent = {};
|
403 |
+
|
404 |
+
for (var v in e) {
|
405 |
+
clonedEvent[v] = e[v];
|
406 |
+
}
|
407 |
+
|
408 |
+
return clonedEvent;
|
409 |
+
},
|
410 |
+
|
411 |
+
/**
|
412 |
+
* A constructor for exposing events to the outside
|
413 |
+
*/
|
414 |
+
EventDispatcher: function EventDispatcher(instance) {
|
415 |
+
// Create a DOM EventTarget object
|
416 |
+
var target = document.createTextNode('');
|
417 |
+
|
418 |
+
function addRemove(op, events, cb) {
|
419 |
+
if (cb) events.split(/\s+/g).forEach(function (name) {
|
420 |
+
return target[op + 'EventListener'].call(target, name, cb);
|
421 |
+
});
|
422 |
+
} // Pass EventTarget interface calls to DOM EventTarget object
|
423 |
+
|
424 |
+
|
425 |
+
this.off = function (events, cb) {
|
426 |
+
addRemove('remove', events, cb);
|
427 |
+
return this;
|
428 |
+
};
|
429 |
+
|
430 |
+
this.on = function (events, cb) {
|
431 |
+
if (cb && typeof cb == 'function') addRemove('add', events, cb);
|
432 |
+
return this;
|
433 |
+
};
|
434 |
+
|
435 |
+
this.trigger = function (eventName, data) {
|
436 |
+
var e;
|
437 |
+
if (!eventName) return;
|
438 |
+
|
439 |
+
if (instance.settings.isJQueryPlugin) {
|
440 |
+
if (eventName == 'remove') eventName = 'removeTag'; // issue #222
|
441 |
+
|
442 |
+
jQuery(instance.DOM.originalInput).triggerHandler(eventName, [data]);
|
443 |
+
} else {
|
444 |
+
try {
|
445 |
+
e = new CustomEvent(eventName, {
|
446 |
+
"detail": this.extend({}, data, {
|
447 |
+
tagify: this
|
448 |
+
})
|
449 |
+
});
|
450 |
+
} catch (err) {
|
451 |
+
console.warn(err);
|
452 |
+
}
|
453 |
+
|
454 |
+
target.dispatchEvent(e);
|
455 |
+
}
|
456 |
+
};
|
457 |
+
},
|
458 |
+
|
459 |
+
/**
|
460 |
+
* Toogle loading state on/off
|
461 |
+
* @param {Boolean} isLoading
|
462 |
+
*/
|
463 |
+
loading: function loading(isLoading) {
|
464 |
+
// IE11 doesn't support toggle with second parameter
|
465 |
+
this.DOM.scope.classList[isLoading ? "add" : "remove"]('tagify--loading');
|
466 |
+
return this;
|
467 |
+
},
|
468 |
+
toggleFocusClass: function toggleFocusClass(force) {
|
469 |
+
this.DOM.scope.classList.toggle('tagify--focus', !!force);
|
470 |
+
},
|
471 |
+
|
472 |
+
/**
|
473 |
+
* DOM events listeners binding
|
474 |
+
*/
|
475 |
+
events: {
|
476 |
+
// bind custom events which were passed in the settings
|
477 |
+
customBinding: function customBinding() {
|
478 |
+
var _this3 = this;
|
479 |
+
|
480 |
+
this.customEventsList.forEach(function (name) {
|
481 |
+
_this3.on(name, _this3.settings.callbacks[name]);
|
482 |
+
});
|
483 |
+
},
|
484 |
+
binding: function binding() {
|
485 |
+
var bindUnbind = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
486 |
+
|
487 |
+
var _CB = this.events.callbacks,
|
488 |
+
_CBR,
|
489 |
+
action = bindUnbind ? 'addEventListener' : 'removeEventListener'; // do not allow the main events to be bound more than once
|
490 |
+
|
491 |
+
|
492 |
+
if (this.state.mainEvents && bindUnbind) return; // set the binding state of the main events, so they will not be bound more than once
|
493 |
+
|
494 |
+
this.state.mainEvents = bindUnbind;
|
495 |
+
|
496 |
+
if (bindUnbind && !this.listeners.main) {
|
497 |
+
// this event should never be unbinded:
|
498 |
+
// IE cannot register "input" events on contenteditable elements, so the "keydown" should be used instead..
|
499 |
+
this.DOM.input.addEventListener(this.isIE ? "keydown" : "input", _CB[this.isIE ? "onInputIE" : "onInput"].bind(this));
|
500 |
+
if (this.settings.isJQueryPlugin) jQuery(this.DOM.originalInput).on('tagify.removeAllTags', this.removeAllTags.bind(this));
|
501 |
+
} // setup callback references so events could be removed later
|
502 |
+
|
503 |
+
|
504 |
+
_CBR = this.listeners.main = this.listeners.main || {
|
505 |
+
focus: ['input', _CB.onFocusBlur.bind(this)],
|
506 |
+
blur: ['input', _CB.onFocusBlur.bind(this)],
|
507 |
+
keydown: ['input', _CB.onKeydown.bind(this)],
|
508 |
+
click: ['scope', _CB.onClickScope.bind(this)],
|
509 |
+
dblclick: ['scope', _CB.onDoubleClickScope.bind(this)]
|
510 |
+
};
|
511 |
+
|
512 |
+
for (var eventName in _CBR) {
|
513 |
+
// make sure the focus/blur event is always regesitered (and never more than once)
|
514 |
+
if (eventName == 'blur' && !bindUnbind) return;
|
515 |
+
|
516 |
+
this.DOM[_CBR[eventName][0]][action](eventName, _CBR[eventName][1]);
|
517 |
+
}
|
518 |
+
},
|
519 |
+
|
520 |
+
/**
|
521 |
+
* DOM events callbacks
|
522 |
+
*/
|
523 |
+
callbacks: {
|
524 |
+
onFocusBlur: function onFocusBlur(e) {
|
525 |
+
var text = e.target ? e.target.textContent.trim() : '',
|
526 |
+
// a string
|
527 |
+
_s = this.settings,
|
528 |
+
type = e.type,
|
529 |
+
eventData = {
|
530 |
+
relatedTarget: e.relatedTarget
|
531 |
+
},
|
532 |
+
shouldAddTags; // goes into this scenario only on input "blur" and a tag was clicked
|
533 |
+
|
534 |
+
if (e.relatedTarget && e.relatedTarget.classList.contains('tagify__tag') && this.DOM.scope.contains(e.relatedTarget)) return;
|
535 |
+
|
536 |
+
if (type == 'blur' && e.relatedTarget === this.DOM.scope) {
|
537 |
+
this.dropdown.hide.call(this);
|
538 |
+
this.DOM.input.focus();
|
539 |
+
return;
|
540 |
+
}
|
541 |
+
|
542 |
+
if (this.state.actions.selectOption && (_s.dropdown.enabled || !_s.dropdown.closeOnSelect)) return;
|
543 |
+
this.state.hasFocus = type == "focus" ? +new Date() : false;
|
544 |
+
this.toggleFocusClass(this.state.hasFocus);
|
545 |
+
this.setRangeAtStartEnd(false);
|
546 |
+
|
547 |
+
if (_s.mode == 'mix') {
|
548 |
+
if (type == "focus") {
|
549 |
+
this.trigger("focus", eventData);
|
550 |
+
} else if (e.type == "blur") {
|
551 |
+
this.trigger("blur", eventData);
|
552 |
+
this.loading(false);
|
553 |
+
this.dropdown.hide.call(this);
|
554 |
+
}
|
555 |
+
|
556 |
+
return;
|
557 |
+
}
|
558 |
+
|
559 |
+
if (type == "focus") {
|
560 |
+
this.trigger("focus", eventData); // e.target.classList.remove('placeholder');
|
561 |
+
|
562 |
+
if (_s.dropdown.enabled === 0 && _s.mode != "select") {
|
563 |
+
this.dropdown.show.call(this);
|
564 |
+
}
|
565 |
+
|
566 |
+
return;
|
567 |
+
} else if (type == "blur") {
|
568 |
+
this.trigger("blur", eventData);
|
569 |
+
this.loading(false);
|
570 |
+
shouldAddTags = this.settings.mode == 'select' ? !this.value.length || this.value[0].value != text : text && !this.state.actions.selectOption && _s.addTagOnBlur; // do not add a tag if "selectOption" action was just fired (this means a tag was just added from the dropdown)
|
571 |
+
|
572 |
+
shouldAddTags && this.addTags(text, true);
|
573 |
+
}
|
574 |
+
|
575 |
+
this.DOM.input.removeAttribute('style');
|
576 |
+
this.dropdown.hide.call(this);
|
577 |
+
},
|
578 |
+
onKeydown: function onKeydown(e) {
|
579 |
+
var _this4 = this;
|
580 |
+
|
581 |
+
var s = e.target.textContent.trim();
|
582 |
+
this.trigger("keydown", {
|
583 |
+
originalEvent: this.cloneEvent(e)
|
584 |
+
});
|
585 |
+
/**
|
586 |
+
* ONLY FOR MIX-MODE:
|
587 |
+
*/
|
588 |
+
|
589 |
+
if (this.settings.mode == 'mix') {
|
590 |
+
switch (e.key) {
|
591 |
+
case 'Left':
|
592 |
+
case 'ArrowLeft':
|
593 |
+
{
|
594 |
+
// when left arrow was pressed, raise a flag so when the dropdown is shown, right-arrow will be ignored
|
595 |
+
// because it seems likely the user wishes to use the arrows to move the caret
|
596 |
+
this.state.actions.ArrowLeft = true;
|
597 |
+
break;
|
598 |
+
}
|
599 |
+
|
600 |
+
case 'Delete':
|
601 |
+
case 'Backspace':
|
602 |
+
{
|
603 |
+
if (this.state.editing) return;
|
604 |
+
var selection = document.getSelection(),
|
605 |
+
lastInputValue = decode(this.DOM.input.innerHTML),
|
606 |
+
lastTagElems = this.getTagElms();
|
607 |
+
if (selection.anchorNode.nodeType == 3 && // node at caret location is a Text node
|
608 |
+
!selection.anchorNode.nodeValue && // has some text
|
609 |
+
selection.anchorNode.previousElementSibling) // text node has a Tag node before it
|
610 |
+
e.preventDefault(); // if( isFirefox && selection && selection.anchorOffset == 0 )
|
611 |
+
// this.removeTag(selection.anchorNode.previousSibling)
|
612 |
+
// a minimum delay is needed before the node actually gets ditached from the document (don't know why),
|
613 |
+
// to know exactly which tag was deleted. This is the easiest way of knowing besides using MutationObserver
|
614 |
+
|
615 |
+
setTimeout(function () {
|
616 |
+
// fixes #384, where the first and only tag will not get removed with backspace
|
617 |
+
if (decode(_this4.DOM.input.innerHTML).length >= lastInputValue.length) {
|
618 |
+
_this4.removeTag(selection.anchorNode.previousElementSibling); // the above "removeTag" methods removes the tag with a transition. Chrome adds a <br> element for some reason at this stage
|
619 |
+
|
620 |
+
|
621 |
+
if (_this4.DOM.input.children.length == 2 && _this4.DOM.input.children[1].tagName == "BR") {
|
622 |
+
_this4.DOM.input.innerHTML = "";
|
623 |
+
_this4.value.length = 0;
|
624 |
+
return true;
|
625 |
+
}
|
626 |
+
} // find out which tag(s) were deleted and trigger "remove" event
|
627 |
+
// iterate over the list of tags still in the document and then filter only those from the "this.value" collection
|
628 |
+
|
629 |
+
|
630 |
+
_this4.value = [].map.call(lastTagElems, function (node, nodeIdx) {
|
631 |
+
var tagData = node.__tagifyTagData;
|
632 |
+
if (node.parentNode) return tagData;else _this4.trigger('remove', {
|
633 |
+
tag: node,
|
634 |
+
index: nodeIdx,
|
635 |
+
data: tagData
|
636 |
+
});
|
637 |
+
}).filter(function (n) {
|
638 |
+
return n;
|
639 |
+
}); // remove empty items in the mapped array
|
640 |
+
}, 50); // Firefox needs this higher duration for some reason or things get buggy when to deleting text from the end
|
641 |
+
|
642 |
+
break;
|
643 |
+
}
|
644 |
+
// currently commented to allow new lines in mixed-mode
|
645 |
+
// case 'Enter' :
|
646 |
+
// e.preventDefault(); // solves Chrome bug - http://stackoverflow.com/a/20398191/104380
|
647 |
+
}
|
648 |
+
|
649 |
+
return true;
|
650 |
+
}
|
651 |
+
|
652 |
+
switch (e.key) {
|
653 |
+
case 'Backspace':
|
654 |
+
if (!this.state.dropdown.visible) {
|
655 |
+
if (s == "" || s.charCodeAt(0) == 8203) {
|
656 |
+
// 8203: ZERO WIDTH SPACE unicode
|
657 |
+
if (this.settings.backspace === true) this.removeTag();else if (this.settings.backspace == 'edit') setTimeout(this.editTag.bind(this), 0); // timeout reason: when edited tag gets focused and the caret is placed at the end, the last character gets deletec (because of backspace)
|
658 |
+
}
|
659 |
+
}
|
660 |
+
|
661 |
+
break;
|
662 |
+
|
663 |
+
case 'Esc':
|
664 |
+
case 'Escape':
|
665 |
+
if (this.state.dropdown.visible) return;
|
666 |
+
e.target.blur();
|
667 |
+
break;
|
668 |
+
|
669 |
+
case 'Down':
|
670 |
+
case 'ArrowDown':
|
671 |
+
// if( this.settings.mode == 'select' ) // issue #333
|
672 |
+
if (!this.state.dropdown.visible) this.dropdown.show.call(this);
|
673 |
+
break;
|
674 |
+
|
675 |
+
case 'ArrowRight':
|
676 |
+
{
|
677 |
+
var tagData = this.state.inputSuggestion || this.state.ddItemData;
|
678 |
+
|
679 |
+
if (tagData && this.settings.autoComplete.rightKey) {
|
680 |
+
this.addTags([tagData], true);
|
681 |
+
return;
|
682 |
+
}
|
683 |
+
|
684 |
+
break;
|
685 |
+
}
|
686 |
+
|
687 |
+
case 'Tab':
|
688 |
+
{
|
689 |
+
if (!s || this.settings.mode == 'select') return true;
|
690 |
+
}
|
691 |
+
|
692 |
+
case 'Enter':
|
693 |
+
e.preventDefault(); // solves Chrome bug - http://stackoverflow.com/a/20398191/104380
|
694 |
+
// because the main "keydown" event is bound before the dropdown events, this will fire first and will not *yet*
|
695 |
+
// know if an option was just selected from the dropdown menu. If an option was selected,
|
696 |
+
// the dropdown events should handle adding the tag
|
697 |
+
|
698 |
+
setTimeout(function () {
|
699 |
+
if (_this4.state.actions.selectOption) return;
|
700 |
+
|
701 |
+
_this4.addTags(s, true);
|
702 |
+
});
|
703 |
+
}
|
704 |
+
},
|
705 |
+
onInput: function onInput(e) {
|
706 |
+
var value = this.settings.mode == 'mix' ? this.DOM.input.textContent : this.input.normalize.call(this),
|
707 |
+
showSuggestions = value.length >= this.settings.dropdown.enabled,
|
708 |
+
eventData = {
|
709 |
+
value: value,
|
710 |
+
inputElm: this.DOM.input
|
711 |
+
};
|
712 |
+
if (this.settings.mode == 'mix') return this.events.callbacks.onMixTagsInput.call(this, e);
|
713 |
+
eventData.isValid = this.validateTag({
|
714 |
+
value: value
|
715 |
+
});
|
716 |
+
this.trigger('input', eventData); // "input" event must be triggered at this point, before the dropdown is shown
|
717 |
+
|
718 |
+
if (!value) {
|
719 |
+
this.input.set.call(this, '');
|
720 |
+
return;
|
721 |
+
}
|
722 |
+
|
723 |
+
if (this.input.value == value) return; // for IE; since IE doesn't have an "input" event so "keyDown" is used instead
|
724 |
+
// save the value on the input's State object
|
725 |
+
|
726 |
+
this.input.set.call(this, value, false); // update the input with the normalized value and run validations
|
727 |
+
// this.setRangeAtStartEnd(); // fix caret position
|
728 |
+
|
729 |
+
if (value.search(this.settings.delimiters) != -1) {
|
730 |
+
if (this.addTags(value)) {
|
731 |
+
this.input.set.call(this); // clear the input field's value
|
732 |
+
}
|
733 |
+
} else if (this.settings.dropdown.enabled >= 0) {
|
734 |
+
this.dropdown[showSuggestions ? "show" : "hide"].call(this, value);
|
735 |
+
}
|
736 |
+
},
|
737 |
+
onMixTagsInput: function onMixTagsInput(e) {
|
738 |
+
var _this5 = this;
|
739 |
+
|
740 |
+
var range,
|
741 |
+
split,
|
742 |
+
tag,
|
743 |
+
showSuggestions,
|
744 |
+
selection,
|
745 |
+
_s = this.settings,
|
746 |
+
lastTagsCount = this.value.length,
|
747 |
+
tagsCount = this.getTagElms().length; // check if ANY tags were magically added through browser redo/undo
|
748 |
+
|
749 |
+
if (tagsCount > lastTagsCount) {
|
750 |
+
this.value = [].map.call(this.getTagElms(), function (node) {
|
751 |
+
return node.__tagifyTagData;
|
752 |
+
});
|
753 |
+
this.update();
|
754 |
+
return;
|
755 |
+
}
|
756 |
+
|
757 |
+
if (this.hasMaxTags()) return true;
|
758 |
+
|
759 |
+
if (window.getSelection) {
|
760 |
+
selection = window.getSelection(); // only detect tags if selection is inside a textNode (not somehow on already-existing tag)
|
761 |
+
|
762 |
+
if (selection.rangeCount > 0 && selection.anchorNode.nodeType == 3) {
|
763 |
+
range = selection.getRangeAt(0).cloneRange();
|
764 |
+
range.collapse(true);
|
765 |
+
range.setStart(selection.focusNode, 0);
|
766 |
+
split = range.toString().split(_s.mixTagsAllowedAfter); // ["foo", "bar", "@a"]
|
767 |
+
|
768 |
+
tag = split[split.length - 1].match(_s.pattern); // tag = range.toString().match(_s.pattern) // allow spaces
|
769 |
+
|
770 |
+
if (tag) {
|
771 |
+
this.state.actions.ArrowLeft = false; // start fresh, assuming the user did not (yet) used any arrow to move the caret
|
772 |
+
|
773 |
+
this.state.tag = {
|
774 |
+
prefix: tag[0],
|
775 |
+
value: tag.input.split(tag[0])[1]
|
776 |
+
};
|
777 |
+
showSuggestions = this.state.tag.value.length >= _s.dropdown.enabled;
|
778 |
+
}
|
779 |
+
}
|
780 |
+
} // wait until the "this.value" has been updated (see "onKeydown" method for "mix-mode")
|
781 |
+
// the dropdown must be shown only after this event has been driggered, so an implementer could
|
782 |
+
// dynamically change the whitelist.
|
783 |
+
|
784 |
+
|
785 |
+
setTimeout(function () {
|
786 |
+
_this5.update();
|
787 |
+
|
788 |
+
_this5.trigger("input", _this5.extend({}, _this5.state.tag, {
|
789 |
+
textContent: _this5.DOM.input.textContent
|
790 |
+
}));
|
791 |
+
|
792 |
+
if (_this5.state.tag) _this5.dropdown[showSuggestions ? "show" : "hide"].call(_this5, _this5.state.tag.value);
|
793 |
+
}, 10);
|
794 |
+
},
|
795 |
+
onInputIE: function onInputIE(e) {
|
796 |
+
var _this = this; // for the "e.target.textContent" to be changed, the browser requires a small delay
|
797 |
+
|
798 |
+
|
799 |
+
setTimeout(function () {
|
800 |
+
_this.events.callbacks.onInput.call(_this, e);
|
801 |
+
});
|
802 |
+
},
|
803 |
+
onClickScope: function onClickScope(e) {
|
804 |
+
var tagElm = e.target.closest('.tagify__tag'),
|
805 |
+
_s = this.settings,
|
806 |
+
timeDiffFocus = +new Date() - this.state.hasFocus,
|
807 |
+
tagElmIdx;
|
808 |
+
|
809 |
+
if (e.target == this.DOM.scope) {
|
810 |
+
// if( !this.state.hasFocus )
|
811 |
+
// this.dropdown.hide.call(this)
|
812 |
+
this.DOM.input.focus();
|
813 |
+
return;
|
814 |
+
} else if (e.target.classList.contains("tagify__tag__removeBtn")) {
|
815 |
+
this.removeTag(e.target.parentNode);
|
816 |
+
return;
|
817 |
+
} else if (tagElm) {
|
818 |
+
tagElmIdx = this.getNodeIndex(tagElm);
|
819 |
+
this.trigger("click", {
|
820 |
+
tag: tagElm,
|
821 |
+
index: tagElmIdx,
|
822 |
+
data: this.value[tagElmIdx],
|
823 |
+
originalEvent: this.cloneEvent(e)
|
824 |
+
});
|
825 |
+
if (this.settings.editTags == 1) this.events.callbacks.onDoubleClickScope.call(this, e);
|
826 |
+
return;
|
827 |
+
} // when clicking on the input itself
|
828 |
+
else if (e.target == this.DOM.input && timeDiffFocus > 500) {
|
829 |
+
if (this.state.dropdown.visible) this.dropdown.hide.call(this);else if (_s.dropdown.enabled === 0 && _s.mode != 'mix') this.dropdown.show.call(this);
|
830 |
+
return;
|
831 |
+
}
|
832 |
+
|
833 |
+
if (_s.mode == 'select') !this.state.dropdown.visible && this.dropdown.show.call(this);
|
834 |
+
},
|
835 |
+
onEditTagInput: function onEditTagInput(editableElm, e) {
|
836 |
+
var tagElm = editableElm.closest('tag'),
|
837 |
+
tagElmIdx = this.getNodeIndex(tagElm),
|
838 |
+
value = this.input.normalize.call(this, editableElm),
|
839 |
+
isValid = this.validateTag({
|
840 |
+
value: value
|
841 |
+
}); // the value chould have been invalid in the first-place so make sure to re-validate it
|
842 |
+
|
843 |
+
tagElm.classList.toggle('tagify--invalid', isValid !== true);
|
844 |
+
tagElm.__tagifyTagData.__isValid = isValid; // show dropdown if typed text is equal or more than the "enabled" dropdown setting
|
845 |
+
|
846 |
+
if (value.length >= this.settings.dropdown.enabled) {
|
847 |
+
this.state.editing.value = value;
|
848 |
+
this.dropdown.show.call(this, value);
|
849 |
+
}
|
850 |
+
|
851 |
+
this.trigger("edit:input", {
|
852 |
+
tag: tagElm,
|
853 |
+
index: tagElmIdx,
|
854 |
+
data: this.extend({}, this.value[tagElmIdx], {
|
855 |
+
newValue: value
|
856 |
+
}),
|
857 |
+
originalEvent: this.cloneEvent(e)
|
858 |
+
});
|
859 |
+
},
|
860 |
+
onEditTagFocus: function onEditTagFocus(tagElm) {
|
861 |
+
this.state.editing = {
|
862 |
+
scope: tagElm,
|
863 |
+
input: tagElm.querySelector("[contenteditable]")
|
864 |
+
};
|
865 |
+
},
|
866 |
+
onEditTagBlur: function onEditTagBlur(editableElm) {
|
867 |
+
if (!this.state.hasFocus) this.toggleFocusClass();
|
868 |
+
if (!this.DOM.scope.contains(editableElm)) return;
|
869 |
+
var tagElm = editableElm.closest('.tagify__tag'),
|
870 |
+
currentValue = this.input.normalize.call(this, editableElm),
|
871 |
+
value = currentValue,
|
872 |
+
// || editableElm.originalValue,
|
873 |
+
hasChanged = value != editableElm.originalValue,
|
874 |
+
tagData = this.extend({}, tagElm.__tagifyTagData, {
|
875 |
+
value: value
|
876 |
+
}),
|
877 |
+
isValid = this.validateTag(tagData); // this.DOM.input.focus()
|
878 |
+
|
879 |
+
if (!currentValue) {
|
880 |
+
this.removeTag(tagElm);
|
881 |
+
this.onEditTagDone(null, tagData);
|
882 |
+
return;
|
883 |
+
}
|
884 |
+
|
885 |
+
if (hasChanged) {
|
886 |
+
this.settings.transformTag.call(this, tagData); // MUST re-validate after tag transformation
|
887 |
+
|
888 |
+
isValid = this.validateTag(tagData);
|
889 |
+
} else {
|
890 |
+
// tagData.__isValid = this.validateTag(tagData)
|
891 |
+
this.onEditTagDone(tagElm, tagData);
|
892 |
+
return;
|
893 |
+
}
|
894 |
+
|
895 |
+
if (isValid !== true) {
|
896 |
+
this.trigger("invalid", {
|
897 |
+
data: tagData,
|
898 |
+
tag: tagElm,
|
899 |
+
message: isValid
|
900 |
+
});
|
901 |
+
return;
|
902 |
+
}
|
903 |
+
|
904 |
+
this.onEditTagDone(tagElm, tagData);
|
905 |
+
},
|
906 |
+
onEditTagkeydown: function onEditTagkeydown(e, tagElm) {
|
907 |
+
this.trigger("edit:keydown", {
|
908 |
+
originalEvent: this.cloneEvent(e)
|
909 |
+
});
|
910 |
+
|
911 |
+
switch (e.key) {
|
912 |
+
case 'Esc':
|
913 |
+
case 'Escape':
|
914 |
+
e.target.textContent = e.target.originalValue; // revert back data as it was pre-edit
|
915 |
+
|
916 |
+
tagElm.__tagifyTagData = tagElm.__tagifyTagData.__originalData;
|
917 |
+
|
918 |
+
case 'Enter':
|
919 |
+
case 'Tab':
|
920 |
+
e.preventDefault();
|
921 |
+
e.target.blur();
|
922 |
+
}
|
923 |
+
},
|
924 |
+
onDoubleClickScope: function onDoubleClickScope(e) {
|
925 |
+
var tagElm = e.target.closest('tag'),
|
926 |
+
_s = this.settings,
|
927 |
+
isEditingTag,
|
928 |
+
isReadyOnlyTag;
|
929 |
+
if (!tagElm) return;
|
930 |
+
isEditingTag = tagElm.classList.contains('tagify__tag--editable');
|
931 |
+
isReadyOnlyTag = tagElm.hasAttribute('readonly');
|
932 |
+
if (_s.mode != 'select' && !_s.readonly && !isEditingTag && !isReadyOnlyTag && this.settings.editTags) this.editTag(tagElm);
|
933 |
+
this.toggleFocusClass(true);
|
934 |
+
}
|
935 |
+
}
|
936 |
+
},
|
937 |
+
|
938 |
+
/**
|
939 |
+
* Enters a tag into "edit" mode
|
940 |
+
* @param {Node} tagElm the tag element to edit. if nothing specified, use last last
|
941 |
+
*/
|
942 |
+
editTag: function editTag(tagElm, opts) {
|
943 |
+
var _this6 = this;
|
944 |
+
|
945 |
+
tagElm = tagElm || this.getLastTag();
|
946 |
+
opts = opts || {};
|
947 |
+
|
948 |
+
var editableElm = tagElm.querySelector('.tagify__tag-text'),
|
949 |
+
tagIdx = this.getNodeIndex(tagElm),
|
950 |
+
tagData = tagElm.__tagifyTagData,
|
951 |
+
_CB = this.events.callbacks,
|
952 |
+
that = this,
|
953 |
+
isValid = true,
|
954 |
+
delayed_onEditTagBlur = function delayed_onEditTagBlur() {
|
955 |
+
that.state.editing = false;
|
956 |
+
setTimeout(_CB.onEditTagBlur.bind(that), 0, editableElm);
|
957 |
+
};
|
958 |
+
|
959 |
+
if (!editableElm) {
|
960 |
+
console.warn('Cannot find element in Tag template: ', '.tagify__tag-text');
|
961 |
+
return;
|
962 |
+
}
|
963 |
+
|
964 |
+
if (tagData instanceof Object && "editable" in tagData && !tagData.editable) return; // cache the original data, on the DOM node, before any modification ocurs, for possible revert
|
965 |
+
|
966 |
+
tagElm.__tagifyTagData.__originalData = this.extend({}, tagData);
|
967 |
+
tagElm.classList.add('tagify__tag--editable');
|
968 |
+
editableElm.originalValue = editableElm.textContent;
|
969 |
+
editableElm.setAttribute('contenteditable', true);
|
970 |
+
editableElm.addEventListener('focus', _CB.onEditTagFocus.bind(this, tagElm));
|
971 |
+
editableElm.addEventListener('blur', delayed_onEditTagBlur);
|
972 |
+
editableElm.addEventListener('input', _CB.onEditTagInput.bind(this, editableElm));
|
973 |
+
editableElm.addEventListener('keydown', function (e) {
|
974 |
+
return _CB.onEditTagkeydown.call(_this6, e, tagElm);
|
975 |
+
});
|
976 |
+
editableElm.focus();
|
977 |
+
this.setRangeAtStartEnd(false, editableElm);
|
978 |
+
if (!opts.skipValidation) isValid = this.editTagToggleValidity(tagElm, tagData.value);
|
979 |
+
this.trigger("edit:start", {
|
980 |
+
tag: tagElm,
|
981 |
+
index: tagIdx,
|
982 |
+
data: tagData,
|
983 |
+
isValid: isValid
|
984 |
+
});
|
985 |
+
return this;
|
986 |
+
},
|
987 |
+
editTagToggleValidity: function editTagToggleValidity(tagElm, value) {
|
988 |
+
var tagData = tagElm.__tagifyTagData,
|
989 |
+
toggleState;
|
990 |
+
|
991 |
+
if (!tagData) {
|
992 |
+
console.warn("tag has no data: ", tagElm, tagData);
|
993 |
+
return;
|
994 |
+
}
|
995 |
+
|
996 |
+
toggleState = !!(tagData.__isValid && tagData.__isValid != true); //this.validateTag(tagData);
|
997 |
+
|
998 |
+
tagElm.classList.toggle('tagify--invalid', toggleState);
|
999 |
+
return tagData.__isValid;
|
1000 |
+
},
|
1001 |
+
onEditTagDone: function onEditTagDone(tagElm, tagData) {
|
1002 |
+
tagData = tagData || {};
|
1003 |
+
var eventData = {
|
1004 |
+
tag: tagElm,
|
1005 |
+
index: this.getNodeIndex(tagElm),
|
1006 |
+
data: tagData
|
1007 |
+
};
|
1008 |
+
this.trigger("edit:beforeUpdate", eventData);
|
1009 |
+
delete tagData.__originalData;
|
1010 |
+
|
1011 |
+
if (tagElm) {
|
1012 |
+
this.editTagToggleValidity(tagElm);
|
1013 |
+
this.replaceTag(tagElm, tagData);
|
1014 |
+
}
|
1015 |
+
|
1016 |
+
this.trigger("edit:updated", eventData);
|
1017 |
+
this.dropdown.hide.call(this);
|
1018 |
+
},
|
1019 |
+
|
1020 |
+
/**
|
1021 |
+
* Replaces an exisitng tag with a new one and update the relevant state
|
1022 |
+
* @param {Object} tagElm [DOM node to replace]
|
1023 |
+
* @param {Object} tagData [data to create new tag from]
|
1024 |
+
*/
|
1025 |
+
replaceTag: function replaceTag(tagElm, tagData) {
|
1026 |
+
var _this7 = this;
|
1027 |
+
|
1028 |
+
if (!tagData || !tagData.value) tagData = tagElm.__tagifyTagData; // if tag is invalid, make the according changes in the newly created element
|
1029 |
+
|
1030 |
+
if (tagData.__isValid && tagData.__isValid != true) this.extend(tagData, this.getInvaildTagParams(tagData, tagData.__isValid));
|
1031 |
+
var newTag = this.createTagElem(tagData); // when editing a tag and selecting a dropdown suggested item, the state should be "locked"
|
1032 |
+
// so "onEditTagBlur" won't run and change the tag also *after* it was just changed.
|
1033 |
+
|
1034 |
+
if (this.state.editing.locked) return;
|
1035 |
+
this.state.editing = {
|
1036 |
+
locked: true
|
1037 |
+
};
|
1038 |
+
setTimeout(function () {
|
1039 |
+
return delete _this7.state.editing.locked;
|
1040 |
+
}, 500); // update DOM
|
1041 |
+
|
1042 |
+
tagElm.parentNode.replaceChild(newTag, tagElm);
|
1043 |
+
this.updateValueByDOMTags();
|
1044 |
+
},
|
1045 |
+
|
1046 |
+
/**
|
1047 |
+
* update value by traversing all valid tags
|
1048 |
+
*/
|
1049 |
+
updateValueByDOMTags: function updateValueByDOMTags() {
|
1050 |
+
var _this8 = this;
|
1051 |
+
|
1052 |
+
this.value = [];
|
1053 |
+
[].forEach.call(this.getTagElms(), function (node) {
|
1054 |
+
if (node.classList.contains('tagify--notAllowed')) return;
|
1055 |
+
|
1056 |
+
_this8.value.push(node.__tagifyTagData);
|
1057 |
+
});
|
1058 |
+
this.update();
|
1059 |
+
},
|
1060 |
+
|
1061 |
+
/** https://stackoverflow.com/a/59156872/104380
|
1062 |
+
* @param {Boolean} start indicating where to place it (start or end of the node)
|
1063 |
+
* @param {Object} node DOM node to place the caret at
|
1064 |
+
*/
|
1065 |
+
setRangeAtStartEnd: function setRangeAtStartEnd(start, node) {
|
1066 |
+
node = node || this.DOM.input;
|
1067 |
+
node = node.lastChild || node;
|
1068 |
+
var sel = document.getSelection();
|
1069 |
+
|
1070 |
+
if (sel.rangeCount) {
|
1071 |
+
['Start', 'End'].forEach(function (pos) {
|
1072 |
+
return sel.getRangeAt(0)["set" + pos](node, start ? 0 : node.length);
|
1073 |
+
});
|
1074 |
+
}
|
1075 |
+
},
|
1076 |
+
|
1077 |
+
/**
|
1078 |
+
* input bridge for accessing & setting
|
1079 |
+
* @type {Object}
|
1080 |
+
*/
|
1081 |
+
input: {
|
1082 |
+
value: '',
|
1083 |
+
set: function set() {
|
1084 |
+
var s = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
1085 |
+
var updateDOM = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
1086 |
+
var hideDropdown = this.settings.dropdown.closeOnSelect;
|
1087 |
+
this.input.value = s;
|
1088 |
+
if (updateDOM) this.DOM.input.innerHTML = s;
|
1089 |
+
if (!s && hideDropdown) setTimeout(this.dropdown.hide.bind(this), 20); // setTimeout duration must be HIGER than the dropdown's item "onClick" method's "focus()" event, because the "hide" method re-binds the main events and it will catch the "blur" event and will cause
|
1090 |
+
|
1091 |
+
this.input.autocomplete.suggest.call(this);
|
1092 |
+
this.input.validate.call(this);
|
1093 |
+
},
|
1094 |
+
|
1095 |
+
/**
|
1096 |
+
* Marks the tagify's input as "invalid" if the value did not pass "validateTag()"
|
1097 |
+
*/
|
1098 |
+
validate: function validate() {
|
1099 |
+
var isValid = !this.input.value || this.validateTag({
|
1100 |
+
value: this.input.value
|
1101 |
+
});
|
1102 |
+
if (this.settings.mode == 'select') this.DOM.scope.classList.toggle('tagify--invalid', isValid !== true);else this.DOM.input.classList.toggle('tagify__input--invalid', isValid !== true);
|
1103 |
+
},
|
1104 |
+
// remove any child DOM elements that aren't of type TEXT (like <br>)
|
1105 |
+
normalize: function normalize(node) {
|
1106 |
+
var clone = node || this.DOM.input,
|
1107 |
+
//.cloneNode(true),
|
1108 |
+
v = []; // when a text was pasted in FF, the "this.DOM.input" element will have <br> but no newline symbols (\n), and this will
|
1109 |
+
// result in tags no being properly created if one wishes to create a separate tag per newline.
|
1110 |
+
|
1111 |
+
clone.childNodes.forEach(function (n) {
|
1112 |
+
return n.nodeType == 3 && v.push(n.nodeValue);
|
1113 |
+
});
|
1114 |
+
v = v.join("\n");
|
1115 |
+
|
1116 |
+
try {
|
1117 |
+
// "delimiters" might be of a non-regex value, where this will fail ("Tags With Properties" example in demo page):
|
1118 |
+
v = v.replace(/(?:\r\n|\r|\n)/g, this.settings.delimiters.source.charAt(0));
|
1119 |
+
} catch (err) {}
|
1120 |
+
|
1121 |
+
v = v.replace(/\s/g, ' ') // replace NBSPs with spaces characters
|
1122 |
+
.replace(/^\s+/, ""); // trimLeft
|
1123 |
+
|
1124 |
+
return v;
|
1125 |
+
},
|
1126 |
+
|
1127 |
+
/**
|
1128 |
+
* suggest the rest of the input's value (via CSS "::after" using "content:attr(...)")
|
1129 |
+
* @param {String} s [description]
|
1130 |
+
*/
|
1131 |
+
autocomplete: {
|
1132 |
+
suggest: function suggest(data) {
|
1133 |
+
if (!this.settings.autoComplete.enabled) return;
|
1134 |
+
data = data || {};
|
1135 |
+
if (typeof data == 'string') data = {
|
1136 |
+
value: data
|
1137 |
+
};
|
1138 |
+
var suggestedText = data.value || '',
|
1139 |
+
suggestionStart = suggestedText.substr(0, this.input.value.length).toLowerCase(),
|
1140 |
+
suggestionTrimmed = suggestedText.substring(this.input.value.length);
|
1141 |
+
|
1142 |
+
if (!suggestedText || !this.input.value || suggestionStart != this.input.value.toLowerCase()) {
|
1143 |
+
this.DOM.input.removeAttribute("data-suggest");
|
1144 |
+
delete this.state.inputSuggestion;
|
1145 |
+
} else {
|
1146 |
+
this.DOM.input.setAttribute("data-suggest", suggestionTrimmed);
|
1147 |
+
this.state.inputSuggestion = data;
|
1148 |
+
}
|
1149 |
+
},
|
1150 |
+
|
1151 |
+
/**
|
1152 |
+
* sets the suggested text as the input's value & cleanup the suggestion autocomplete.
|
1153 |
+
* @param {String} s [text]
|
1154 |
+
*/
|
1155 |
+
set: function set(s) {
|
1156 |
+
var dataSuggest = this.DOM.input.getAttribute('data-suggest'),
|
1157 |
+
suggestion = s || (dataSuggest ? this.input.value + dataSuggest : null);
|
1158 |
+
|
1159 |
+
if (suggestion) {
|
1160 |
+
if (this.settings.mode == 'mix') {
|
1161 |
+
this.replaceTextWithNode(document.createTextNode(this.state.tag.prefix + suggestion));
|
1162 |
+
} else {
|
1163 |
+
this.input.set.call(this, suggestion);
|
1164 |
+
this.setRangeAtStartEnd();
|
1165 |
+
}
|
1166 |
+
|
1167 |
+
this.input.autocomplete.suggest.call(this);
|
1168 |
+
this.dropdown.hide.call(this);
|
1169 |
+
return true;
|
1170 |
+
}
|
1171 |
+
|
1172 |
+
return false;
|
1173 |
+
}
|
1174 |
+
}
|
1175 |
+
},
|
1176 |
+
getNodeIndex: function getNodeIndex(node) {
|
1177 |
+
var index = 0;
|
1178 |
+
if (node) while (node = node.previousElementSibling) {
|
1179 |
+
index++;
|
1180 |
+
}
|
1181 |
+
return index;
|
1182 |
+
},
|
1183 |
+
getTagElms: function getTagElms() {
|
1184 |
+
return this.DOM.scope.querySelectorAll('.tagify__tag');
|
1185 |
+
},
|
1186 |
+
getLastTag: function getLastTag() {
|
1187 |
+
var lastTag = this.DOM.scope.querySelectorAll('tag:not(.tagify--hide):not([readonly])');
|
1188 |
+
return lastTag[lastTag.length - 1];
|
1189 |
+
},
|
1190 |
+
|
1191 |
+
/**
|
1192 |
+
* Searches if any tag with a certain value already exis
|
1193 |
+
* @param {String/Object} v [text value / tag data object]
|
1194 |
+
* @return {Boolean}
|
1195 |
+
*/
|
1196 |
+
isTagDuplicate: function isTagDuplicate(value) {
|
1197 |
+
var duplications; // duplications are irrelevant for this scenario
|
1198 |
+
|
1199 |
+
if (this.settings.mode == 'select') return false;
|
1200 |
+
duplications = this.value.reduce(function (acc, item) {
|
1201 |
+
return value.trim().toLowerCase() === item.value.toLowerCase() ? acc + 1 : acc;
|
1202 |
+
}, 0);
|
1203 |
+
return duplications; // this.value.some(item => value.trim().toLowerCase() === item.value.toLowerCase())
|
1204 |
+
},
|
1205 |
+
getTagIndexByValue: function getTagIndexByValue(value) {
|
1206 |
+
var result = [];
|
1207 |
+
this.getTagElms().forEach(function (tagElm, i) {
|
1208 |
+
if (tagElm.textContent.trim().toLowerCase() == value.toLowerCase()) result.push(i);
|
1209 |
+
});
|
1210 |
+
return result;
|
1211 |
+
},
|
1212 |
+
getTagElmByValue: function getTagElmByValue(value) {
|
1213 |
+
var tagIdx = this.getTagIndexByValue(value)[0];
|
1214 |
+
return this.getTagElms()[tagIdx];
|
1215 |
+
},
|
1216 |
+
|
1217 |
+
/**
|
1218 |
+
* Mark a tag element by its value
|
1219 |
+
* @param {String|Number} value [text value to search for]
|
1220 |
+
* @param {Object} tagElm [a specific "tag" element to compare to the other tag elements siblings]
|
1221 |
+
* @return {boolean} [found / not found]
|
1222 |
+
*/
|
1223 |
+
markTagByValue: function markTagByValue(value, tagElm) {
|
1224 |
+
tagElm = tagElm || this.getTagElmByValue(value); // check AGAIN if "tagElm" is defined
|
1225 |
+
|
1226 |
+
if (tagElm) {
|
1227 |
+
tagElm.classList.add('tagify--mark');
|
1228 |
+
setTimeout(function () {
|
1229 |
+
tagElm.classList.remove('tagify--mark');
|
1230 |
+
}, 100);
|
1231 |
+
return tagElm;
|
1232 |
+
}
|
1233 |
+
|
1234 |
+
return false;
|
1235 |
+
},
|
1236 |
+
|
1237 |
+
/**
|
1238 |
+
* make sure the tag, or words in it, is not in the blacklist
|
1239 |
+
*/
|
1240 |
+
isTagBlacklisted: function isTagBlacklisted(v) {
|
1241 |
+
v = v.toLowerCase().trim();
|
1242 |
+
return this.settings.blacklist.filter(function (x) {
|
1243 |
+
return v == x.toLowerCase();
|
1244 |
+
}).length;
|
1245 |
+
},
|
1246 |
+
|
1247 |
+
/**
|
1248 |
+
* make sure the tag, or words in it, is not in the blacklist
|
1249 |
+
*/
|
1250 |
+
isTagWhitelisted: function isTagWhitelisted(v) {
|
1251 |
+
return this.settings.whitelist.some(function (item) {
|
1252 |
+
return typeof v == 'string' ? v.trim().toLowerCase() === (item.value || item).toLowerCase() : JSON.stringify(item).toLowerCase() === JSON.stringify(v).toLowerCase();
|
1253 |
+
});
|
1254 |
+
},
|
1255 |
+
|
1256 |
+
/**
|
1257 |
+
* validate a tag object BEFORE the actual tag will be created & appeneded
|
1258 |
+
* @param {String} s
|
1259 |
+
* @param {String} uid [unique ID, to not inclue own tag when cheking for duplicates]
|
1260 |
+
* @return {Boolean/String} ["true" if validation has passed, String for a fail]
|
1261 |
+
*/
|
1262 |
+
validateTag: function validateTag(tagData) {
|
1263 |
+
var value = tagData.value.trim(),
|
1264 |
+
_s = this.settings,
|
1265 |
+
result = true; // check for empty value
|
1266 |
+
|
1267 |
+
if (!value) result = this.TEXTS.empty; // check if pattern should be used and if so, use it to test the value
|
1268 |
+
else if (_s.pattern && _s.pattern instanceof RegExp && !_s.pattern.test(value)) result = this.TEXTS.pattern; // if duplicates are not allowed and there is a duplicate
|
1269 |
+
else if (!_s.duplicates && this.isTagDuplicate(value)) result = this.TEXTS.duplicate;else if (this.isTagBlacklisted(value) || _s.enforceWhitelist && !this.isTagWhitelisted(value)) result = this.TEXTS.notAllowed;
|
1270 |
+
return result;
|
1271 |
+
},
|
1272 |
+
getInvaildTagParams: function getInvaildTagParams(tagData, validation) {
|
1273 |
+
return {
|
1274 |
+
"aria-invalid": true,
|
1275 |
+
"class": (tagData["class"] || '') + ' tagify--notAllowed',
|
1276 |
+
"title": validation
|
1277 |
+
};
|
1278 |
+
},
|
1279 |
+
hasMaxTags: function hasMaxTags() {
|
1280 |
+
if (this.value.length >= this.settings.maxTags) return this.TEXTS.exceed;
|
1281 |
+
return false;
|
1282 |
+
},
|
1283 |
+
|
1284 |
+
/**
|
1285 |
+
* pre-proccess the tagsItems, which can be a complex tagsItems like an Array of Objects or a string comprised of multiple words
|
1286 |
+
* so each item should be iterated on and a tag created for.
|
1287 |
+
* @return {Array} [Array of Objects]
|
1288 |
+
*/
|
1289 |
+
normalizeTags: function normalizeTags(tagsItems) {
|
1290 |
+
var _this$settings = this.settings,
|
1291 |
+
whitelist = _this$settings.whitelist,
|
1292 |
+
delimiters = _this$settings.delimiters,
|
1293 |
+
mode = _this$settings.mode,
|
1294 |
+
whitelistWithProps = whitelist ? whitelist[0] instanceof Object : false,
|
1295 |
+
isArray = tagsItems instanceof Array,
|
1296 |
+
isCollection = isArray && tagsItems[0] instanceof Object && "value" in tagsItems[0],
|
1297 |
+
temp = [],
|
1298 |
+
mapStringToCollection = function mapStringToCollection(s) {
|
1299 |
+
return (s + "").split(delimiters).filter(function (n) {
|
1300 |
+
return n;
|
1301 |
+
}).map(function (v) {
|
1302 |
+
return {
|
1303 |
+
value: v.trim()
|
1304 |
+
};
|
1305 |
+
});
|
1306 |
+
}; // no need to continue if "tagsItems" is an Array of Objects
|
1307 |
+
|
1308 |
+
|
1309 |
+
if (isCollection) {
|
1310 |
+
var _ref2;
|
1311 |
+
|
1312 |
+
// iterate the collection items and check for values that can be splitted into multiple tags
|
1313 |
+
tagsItems = (_ref2 = []).concat.apply(_ref2, _toConsumableArray(tagsItems.map(function (item) {
|
1314 |
+
return mapStringToCollection(item.value).map(function (newItem) {
|
1315 |
+
return _objectSpread({}, item, {}, newItem);
|
1316 |
+
});
|
1317 |
+
})));
|
1318 |
+
return tagsItems;
|
1319 |
+
}
|
1320 |
+
|
1321 |
+
if (typeof tagsItems == 'number') tagsItems = tagsItems.toString(); // if the value is a "simple" String, ex: "aaa, bbb, ccc"
|
1322 |
+
|
1323 |
+
if (typeof tagsItems == 'string') {
|
1324 |
+
if (!tagsItems.trim()) return []; // go over each tag and add it (if there were multiple ones)
|
1325 |
+
|
1326 |
+
tagsItems = mapStringToCollection(tagsItems);
|
1327 |
+
} else if (isArray) {
|
1328 |
+
var _ref3;
|
1329 |
+
|
1330 |
+
tagsItems = (_ref3 = []).concat.apply(_ref3, _toConsumableArray(tagsItems.map(function (item) {
|
1331 |
+
return mapStringToCollection(item);
|
1332 |
+
})));
|
1333 |
+
} // search if the tag exists in the whitelist as an Object (has props),
|
1334 |
+
// to be able to use its properties
|
1335 |
+
|
1336 |
+
|
1337 |
+
if (whitelistWithProps) {
|
1338 |
+
tagsItems.forEach(function (item) {
|
1339 |
+
// the "value" prop should preferably be unique
|
1340 |
+
var matchObj = whitelist.filter(function (WL_item) {
|
1341 |
+
return WL_item.value.toLowerCase() == item.value.toLowerCase();
|
1342 |
+
});
|
1343 |
+
|
1344 |
+
if (matchObj[0]) {
|
1345 |
+
temp.push(matchObj[0]); // set the Array (with the found Object) as the new value
|
1346 |
+
} else if (mode != 'mix') temp.push(item);
|
1347 |
+
});
|
1348 |
+
tagsItems = temp;
|
1349 |
+
}
|
1350 |
+
|
1351 |
+
return tagsItems;
|
1352 |
+
},
|
1353 |
+
|
1354 |
+
/**
|
1355 |
+
* Used to parse the initial value of a textarea (or input) element and gemerate mixed text w/ tags
|
1356 |
+
* https://stackoverflow.com/a/57598892/104380
|
1357 |
+
* @param {String} s
|
1358 |
+
*/
|
1359 |
+
parseMixTags: function parseMixTags(s) {
|
1360 |
+
var _this9 = this;
|
1361 |
+
|
1362 |
+
var _this$settings2 = this.settings,
|
1363 |
+
mixTagsInterpolator = _this$settings2.mixTagsInterpolator,
|
1364 |
+
duplicates = _this$settings2.duplicates,
|
1365 |
+
transformTag = _this$settings2.transformTag,
|
1366 |
+
enforceWhitelist = _this$settings2.enforceWhitelist,
|
1367 |
+
tagsDataSet = [];
|
1368 |
+
s = s.split(mixTagsInterpolator[0]).map(function (s1, i) {
|
1369 |
+
var s2 = s1.split(mixTagsInterpolator[1]),
|
1370 |
+
preInterpolated = s2[0],
|
1371 |
+
tagData,
|
1372 |
+
tagElm;
|
1373 |
+
|
1374 |
+
try {
|
1375 |
+
tagData = JSON.parse(preInterpolated);
|
1376 |
+
} catch (err) {
|
1377 |
+
tagData = _this9.normalizeTags(preInterpolated)[0]; //{value:preInterpolated}
|
1378 |
+
}
|
1379 |
+
|
1380 |
+
if (s2.length > 1 && (!enforceWhitelist || _this9.isTagWhitelisted(tagData.value)) && !(!duplicates && _this9.isTagDuplicate(tagData.value))) {
|
1381 |
+
transformTag.call(_this9, tagData);
|
1382 |
+
tagElm = _this9.createTagElem(tagData);
|
1383 |
+
tagsDataSet.push(tagData);
|
1384 |
+
tagElm.classList.add('tagify--noAnim');
|
1385 |
+
s2[0] = tagElm.outerHTML; //+ "⁠" // put a zero-space at the end so the caret won't jump back to the start (when the last input's child element is a tag)
|
1386 |
+
|
1387 |
+
_this9.value.push(tagData);
|
1388 |
+
} else if (s1) return i ? mixTagsInterpolator[0] + s1 : s1;
|
1389 |
+
|
1390 |
+
return s2.join('');
|
1391 |
+
}).join('');
|
1392 |
+
this.DOM.input.innerHTML = s;
|
1393 |
+
this.DOM.input.appendChild(document.createTextNode(''));
|
1394 |
+
this.DOM.input.normalize();
|
1395 |
+
this.getTagElms().forEach(function (elm, idx) {
|
1396 |
+
return elm.__tagifyTagData = tagsDataSet[idx];
|
1397 |
+
});
|
1398 |
+
this.update();
|
1399 |
+
return s;
|
1400 |
+
},
|
1401 |
+
|
1402 |
+
/**
|
1403 |
+
* For mixed-mode: replaces a text starting with a prefix with a wrapper element (tag or something)
|
1404 |
+
* First there *has* to be a "this.state.tag" which is a string that was just typed and is staring with a prefix
|
1405 |
+
*/
|
1406 |
+
replaceTextWithNode: function replaceTextWithNode(wrapperElm, tagString) {
|
1407 |
+
if (!this.state.tag && !tagString) return;
|
1408 |
+
tagString = tagString || this.state.tag.prefix + this.state.tag.value;
|
1409 |
+
var idx,
|
1410 |
+
replacedNode,
|
1411 |
+
selection = this.state.selection || window.getSelection(),
|
1412 |
+
nodeAtCaret = selection.anchorNode; // ex. replace #ba with the tag "bart" where "|" is where the caret is:
|
1413 |
+
// start with: "#ba #ba| #ba"
|
1414 |
+
// split the text node at the index of the caret
|
1415 |
+
|
1416 |
+
nodeAtCaret.splitText(selection.anchorOffset); // "#ba #ba"
|
1417 |
+
// get index of last occurence of "#ba"
|
1418 |
+
|
1419 |
+
idx = nodeAtCaret.nodeValue.lastIndexOf(tagString);
|
1420 |
+
replacedNode = nodeAtCaret.splitText(idx); // clean up the tag's string and put tag element instead
|
1421 |
+
|
1422 |
+
replacedNode.nodeValue = replacedNode.nodeValue.replace(tagString, '');
|
1423 |
+
nodeAtCaret.parentNode.insertBefore(wrapperElm, replacedNode);
|
1424 |
+
this.DOM.input.normalize();
|
1425 |
+
return replacedNode;
|
1426 |
+
},
|
1427 |
+
|
1428 |
+
/**
|
1429 |
+
* For selecting a single option (not used for multiple tags)
|
1430 |
+
* @param {Object} tagElm Tag DOM node
|
1431 |
+
* @param {Object} tagData Tag data
|
1432 |
+
*/
|
1433 |
+
selectTag: function selectTag(tagElm, tagData) {
|
1434 |
+
this.input.set.call(this, tagData.value, true); // place the caret at the end of the input, only if a dropdown option was selected (and not by manually typing another value and clicking "TAB")
|
1435 |
+
|
1436 |
+
if (this.state.actions.selectOption) setTimeout(this.setRangeAtStartEnd.bind(this));
|
1437 |
+
if (this.getLastTag()) this.replaceTag(this.getLastTag(), tagData);else this.appendTag(tagElm);
|
1438 |
+
this.value[0] = tagData;
|
1439 |
+
this.trigger('add', {
|
1440 |
+
tag: tagElm,
|
1441 |
+
data: tagData
|
1442 |
+
});
|
1443 |
+
this.update();
|
1444 |
+
return [tagElm];
|
1445 |
+
},
|
1446 |
+
|
1447 |
+
/**
|
1448 |
+
* add an empty "tag" element in an editable state
|
1449 |
+
*/
|
1450 |
+
addEmptyTag: function addEmptyTag() {
|
1451 |
+
var tagData = {
|
1452 |
+
value: ""
|
1453 |
+
},
|
1454 |
+
tagElm = this.createTagElem(tagData); // must be assigned ASAP, before "validateTag" method below
|
1455 |
+
|
1456 |
+
tagElm.__tagifyTagData = tagData; // add the tag to the component's DOM
|
1457 |
+
|
1458 |
+
this.appendTag(tagElm);
|
1459 |
+
this.editTag(tagElm, {
|
1460 |
+
skipValidation: true
|
1461 |
+
});
|
1462 |
+
},
|
1463 |
+
|
1464 |
+
/**
|
1465 |
+
* add a "tag" element to the "tags" component
|
1466 |
+
* @param {String/Array} tagsItems [A string (single or multiple values with a delimiter), or an Array of Objects or just Array of Strings]
|
1467 |
+
* @param {Boolean} clearInput [flag if the input's value should be cleared after adding tags]
|
1468 |
+
* @param {Boolean} skipInvalid [do not add, mark & remove invalid tags]
|
1469 |
+
* @return {Array} Array of DOM elements (tags)
|
1470 |
+
*/
|
1471 |
+
addTags: function addTags(tagsItems, clearInput) {
|
1472 |
+
var _this10 = this;
|
1473 |
+
|
1474 |
+
var skipInvalid = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.settings.skipInvalid;
|
1475 |
+
var tagElems = [],
|
1476 |
+
tagElm,
|
1477 |
+
_s = this.settings;
|
1478 |
+
|
1479 |
+
if (!tagsItems || tagsItems.length == 0) {
|
1480 |
+
// is mode is "select" clean all tags
|
1481 |
+
if (_s.mode == 'select') this.removeAllTags();
|
1482 |
+
return tagElems;
|
1483 |
+
} // converts Array/String/Object to an Array of Objects
|
1484 |
+
|
1485 |
+
|
1486 |
+
tagsItems = this.normalizeTags(tagsItems); // if in edit-mode, do not continue but instead replace the tag's text.
|
1487 |
+
// the scenario is that "addTags" was called from a dropdown suggested option selected while editing
|
1488 |
+
|
1489 |
+
if (this.state.editing.scope) {
|
1490 |
+
tagsItems[0].__isValid = true; // must be "true" at this point because it must have been coming from the dropdown sugegstions list
|
1491 |
+
|
1492 |
+
return this.onEditTagDone(this.state.editing.scope, tagsItems[0]);
|
1493 |
+
}
|
1494 |
+
|
1495 |
+
if (_s.mode == 'mix') {
|
1496 |
+
_s.transformTag.call(this, tagsItems[0]); // TODO: should check if the tag is valid
|
1497 |
+
|
1498 |
+
|
1499 |
+
tagElm = this.createTagElem(tagsItems[0]); // tries to replace a taged textNode with a tagElm, and if not able,
|
1500 |
+
// insert the new tag to the END if "addTags" was called from outside
|
1501 |
+
|
1502 |
+
if (!this.replaceTextWithNode(tagElm)) {
|
1503 |
+
this.DOM.input.appendChild(tagElm);
|
1504 |
+
} // fixes a firefox bug where if the last child of the input is a tag and not a text, the input cannot get focus (by Tab key)
|
1505 |
+
|
1506 |
+
|
1507 |
+
this.DOM.input.appendChild(document.createTextNode(''));
|
1508 |
+
setTimeout(function () {
|
1509 |
+
return tagElm.classList.add('tagify--noAnim');
|
1510 |
+
}, 300);
|
1511 |
+
tagsItems[0].prefix = tagsItems[0].prefix || this.state.tag ? this.state.tag.prefix : (_s.pattern.source || _s.pattern)[0];
|
1512 |
+
this.value.push(tagsItems[0]);
|
1513 |
+
this.update();
|
1514 |
+
this.state.tag = null;
|
1515 |
+
this.trigger('add', this.extend({}, {
|
1516 |
+
tag: tagElm
|
1517 |
+
}, {
|
1518 |
+
data: tagsItems[0]
|
1519 |
+
})); // fixes a firefox bug where if the last child of the input is a tag and not a text, the input cannot get focus (by Tab key)
|
1520 |
+
|
1521 |
+
this.DOM.input.appendChild(document.createTextNode(''));
|
1522 |
+
return tagElm;
|
1523 |
+
}
|
1524 |
+
|
1525 |
+
if (_s.mode == 'select') clearInput = false;
|
1526 |
+
this.DOM.input.removeAttribute('style');
|
1527 |
+
tagsItems.forEach(function (tagData) {
|
1528 |
+
var tagElm,
|
1529 |
+
tagElmParams = {}; // shallow-clone tagData so later modifications will not apply to the source
|
1530 |
+
|
1531 |
+
tagData = Object.assign({}, tagData);
|
1532 |
+
|
1533 |
+
_s.transformTag.call(_this10, tagData); ///////////////// ( validation )//////////////////////
|
1534 |
+
|
1535 |
+
|
1536 |
+
tagData.__isValid = _this10.hasMaxTags() || _this10.validateTag(tagData);
|
1537 |
+
|
1538 |
+
if (tagData.__isValid !== true) {
|
1539 |
+
if (skipInvalid) return;
|
1540 |
+
|
1541 |
+
_this10.extend(tagElmParams, _this10.getInvaildTagParams(tagData, tagData.__isValid)); // mark, for a brief moment, the tag THIS CURRENT tag is a duplcate of
|
1542 |
+
|
1543 |
+
|
1544 |
+
if (tagData.__isValid == _this10.TEXTS.duplicate) _this10.markTagByValue(tagData.value);
|
1545 |
+
} /////////////////////////////////////////////////////
|
1546 |
+
// add accessibility attributes
|
1547 |
+
|
1548 |
+
|
1549 |
+
tagElmParams.role = "tag";
|
1550 |
+
if (tagData.readonly) tagElmParams["aria-readonly"] = true; // Create tag HTML element
|
1551 |
+
|
1552 |
+
tagElm = _this10.createTagElem(_this10.extend({}, tagData, tagElmParams));
|
1553 |
+
tagElm.__tagifyTagData = tagData;
|
1554 |
+
tagElems.push(tagElm); // mode-select overrides
|
1555 |
+
|
1556 |
+
if (_s.mode == 'select') {
|
1557 |
+
return _this10.selectTag(tagElm, tagData);
|
1558 |
+
} // add the tag to the component's DOM
|
1559 |
+
|
1560 |
+
|
1561 |
+
_this10.appendTag(tagElm);
|
1562 |
+
|
1563 |
+
if (tagData.__isValid && tagData.__isValid === true) {
|
1564 |
+
// update state
|
1565 |
+
_this10.value.push(tagData);
|
1566 |
+
|
1567 |
+
_this10.update();
|
1568 |
+
|
1569 |
+
_this10.trigger('add', {
|
1570 |
+
tag: tagElm,
|
1571 |
+
index: _this10.value.length - 1,
|
1572 |
+
data: tagData
|
1573 |
+
});
|
1574 |
+
} else {
|
1575 |
+
_this10.trigger("invalid", {
|
1576 |
+
data: tagData,
|
1577 |
+
index: _this10.value.length,
|
1578 |
+
tag: tagElm,
|
1579 |
+
message: tagData.__isValid
|
1580 |
+
});
|
1581 |
+
|
1582 |
+
if (!_s.keepInvalidTags) // remove invalid tags (if "keepInvalidTags" is set to "false")
|
1583 |
+
setTimeout(function () {
|
1584 |
+
return _this10.removeTag(tagElm, true);
|
1585 |
+
}, 1000);
|
1586 |
+
}
|
1587 |
+
|
1588 |
+
_this10.dropdown.position.call(_this10); // reposition the dropdown because the just-added tag might cause a new-line
|
1589 |
+
|
1590 |
+
});
|
1591 |
+
|
1592 |
+
if (tagsItems.length && clearInput) {
|
1593 |
+
this.input.set.call(this);
|
1594 |
+
}
|
1595 |
+
|
1596 |
+
this.dropdown.refilter.call(this);
|
1597 |
+
return tagElems;
|
1598 |
+
},
|
1599 |
+
|
1600 |
+
/**
|
1601 |
+
* appened (validated) tag to the component's DOM scope
|
1602 |
+
*/
|
1603 |
+
appendTag: function appendTag(tagElm) {
|
1604 |
+
var insertBeforeNode = this.DOM.scope.lastElementChild;
|
1605 |
+
if (insertBeforeNode === this.DOM.input) this.DOM.scope.insertBefore(tagElm, insertBeforeNode);else this.DOM.scope.appendChild(tagElm);
|
1606 |
+
},
|
1607 |
+
|
1608 |
+
/**
|
1609 |
+
* Removed new lines and irrelevant spaces which might affect layout, and are better gone
|
1610 |
+
* @param {string} s [HTML string]
|
1611 |
+
*/
|
1612 |
+
minify: function minify(s) {
|
1613 |
+
return s ? s.replace(/\>[\r\n ]+\</g, "><").replace(/(<.*?>)|\s+/g, function (m, $1) {
|
1614 |
+
return $1 ? $1 : ' ';
|
1615 |
+
}) // https://stackoverflow.com/a/44841484/104380
|
1616 |
+
: "";
|
1617 |
+
},
|
1618 |
+
|
1619 |
+
/**
|
1620 |
+
* creates a DOM tag element and injects it into the component (this.DOM.scope)
|
1621 |
+
* @param {Object} tagData [text value & properties for the created tag]
|
1622 |
+
* @return {Object} [DOM element]
|
1623 |
+
*/
|
1624 |
+
createTagElem: function createTagElem(tagData) {
|
1625 |
+
var tagElm,
|
1626 |
+
v = escapeHTML(tagData.value),
|
1627 |
+
template = this.settings.templates.tag.call(this, v, tagData);
|
1628 |
+
if (this.settings.readonly) tagData.readonly = true; // tagData.__uid = tagData.__uid || getUID()
|
1629 |
+
|
1630 |
+
template = this.minify(template);
|
1631 |
+
tagElm = this.parseHTML(template);
|
1632 |
+
tagElm.__tagifyTagData = tagData;
|
1633 |
+
return tagElm;
|
1634 |
+
},
|
1635 |
+
reCheckInvalidTags: function reCheckInvalidTags() {
|
1636 |
+
var _this11 = this;
|
1637 |
+
|
1638 |
+
// find all invalid tags and re-check them
|
1639 |
+
var tagElms = this.DOM.scope.querySelectorAll('.tagify__tag.tagify--notAllowed');
|
1640 |
+
[].forEach.call(tagElms, function (node) {
|
1641 |
+
var tagData = node.__tagifyTagData,
|
1642 |
+
wasNodeDuplicate = node.getAttribute('title') == _this11.TEXTS.duplicate,
|
1643 |
+
isNodeValid = _this11.validateTag(tagData) === true; // if this tag node was marked as a dulpicate, unmark it (it might have been marked as "notAllowed" for other reasons)
|
1644 |
+
|
1645 |
+
|
1646 |
+
if (wasNodeDuplicate && isNodeValid) {
|
1647 |
+
tagData.__isValid = true;
|
1648 |
+
|
1649 |
+
_this11.replaceTag(node, tagData);
|
1650 |
+
}
|
1651 |
+
});
|
1652 |
+
},
|
1653 |
+
|
1654 |
+
/**
|
1655 |
+
* Removes a tag
|
1656 |
+
* @param {Object|String} tagElm [DOM element or a String value. if undefined or null, remove last added tag]
|
1657 |
+
* @param {Boolean} silent [A flag, which when turned on, does not removes any value and does not update the original input value but simply removes the tag from tagify]
|
1658 |
+
* @param {Number} tranDuration [Transition duration in MS]
|
1659 |
+
*/
|
1660 |
+
removeTag: function removeTag(tagElm, silent, tranDuration) {
|
1661 |
+
var tagData;
|
1662 |
+
tagElm = tagElm || this.getLastTag();
|
1663 |
+
tranDuration = tranDuration || this.CSSVars.tagHideTransition;
|
1664 |
+
if (typeof tagElm == 'string') tagElm = this.getTagElmByValue(tagElm);
|
1665 |
+
if (!(tagElm instanceof HTMLElement)) return;
|
1666 |
+
var that = this,
|
1667 |
+
tagIdx = this.getNodeIndex(tagElm); // this.getTagIndexByValue(tagElm.textContent)
|
1668 |
+
|
1669 |
+
if (this.settings.mode == 'select') {
|
1670 |
+
tranDuration = 0;
|
1671 |
+
this.input.set.call(this);
|
1672 |
+
}
|
1673 |
+
|
1674 |
+
if (tagElm.classList.contains('tagify--notAllowed')) silent = true;
|
1675 |
+
|
1676 |
+
function removeNode() {
|
1677 |
+
if (!tagElm.parentNode) return;
|
1678 |
+
tagData = tagElm.__tagifyTagData;
|
1679 |
+
tagElm.parentNode.removeChild(tagElm);
|
1680 |
+
|
1681 |
+
if (!silent) {
|
1682 |
+
if (tagIdx > -1) that.value.splice(tagIdx, 1); // that.removeValueById(tagData.__uid)
|
1683 |
+
|
1684 |
+
that.update(); // update the original input with the current value
|
1685 |
+
|
1686 |
+
that.trigger('remove', {
|
1687 |
+
tag: tagElm,
|
1688 |
+
index: tagIdx,
|
1689 |
+
data: tagData
|
1690 |
+
});
|
1691 |
+
that.dropdown.refilter.call(that);
|
1692 |
+
that.dropdown.position.call(that); // check if any of the current tags which might have been marked as "duplicate" should be now un-marked
|
1693 |
+
|
1694 |
+
if (that.settings.keepInvalidTags) that.reCheckInvalidTags();
|
1695 |
+
} else if (that.settings.keepInvalidTags) that.trigger('remove', {
|
1696 |
+
tag: tagElm,
|
1697 |
+
index: tagIdx
|
1698 |
+
});
|
1699 |
+
}
|
1700 |
+
|
1701 |
+
function animation() {
|
1702 |
+
tagElm.style.width = parseFloat(window.getComputedStyle(tagElm).width) + 'px';
|
1703 |
+
document.body.clientTop; // force repaint for the width to take affect before the "hide" class below
|
1704 |
+
|
1705 |
+
tagElm.classList.add('tagify--hide'); // manual timeout (hack, since transitionend cannot be used because of hover)
|
1706 |
+
|
1707 |
+
setTimeout(removeNode, tranDuration);
|
1708 |
+
}
|
1709 |
+
|
1710 |
+
if (tranDuration && tranDuration > 10) animation();else removeNode();
|
1711 |
+
},
|
1712 |
+
removeAllTags: function removeAllTags() {
|
1713 |
+
this.value = [];
|
1714 |
+
if (this.settings.mode == 'mix') this.DOM.input.innerHTML = '';else Array.prototype.slice.call(this.getTagElms()).forEach(function (elm) {
|
1715 |
+
return elm.parentNode.removeChild(elm);
|
1716 |
+
});
|
1717 |
+
this.dropdown.position.call(this);
|
1718 |
+
if (this.settings.mode == 'select') this.input.set.call(this);
|
1719 |
+
this.update();
|
1720 |
+
},
|
1721 |
+
|
1722 |
+
/**
|
1723 |
+
* Removes an item in "this.value" by its UID
|
1724 |
+
* @param {String} uid
|
1725 |
+
*/
|
1726 |
+
removeValueById: function removeValueById(uid) {// this.value = this.value.filter(item => item.__tagifyTagData.__uid != uid)
|
1727 |
+
},
|
1728 |
+
preUpdate: function preUpdate() {
|
1729 |
+
this.DOM.scope.classList.toggle('tagify--hasMaxTags', this.value.length >= this.settings.maxTags);
|
1730 |
+
this.DOM.scope.classList.toggle('tagify--noTags', !this.value.length);
|
1731 |
+
},
|
1732 |
+
|
1733 |
+
/**
|
1734 |
+
* update the origianl (hidden) input field's value
|
1735 |
+
* see - https://stackoverflow.com/q/50957841/104380
|
1736 |
+
*/
|
1737 |
+
update: function update() {
|
1738 |
+
this.preUpdate();
|
1739 |
+
var value = removeCollectionProp(this.value, "__isValid");
|
1740 |
+
this.DOM.originalInput.value = this.settings.mode == 'mix' ? this.getMixedTagsAsString(value) : this.value.length ? JSON.stringify(value) : "";
|
1741 |
+
this.DOM.originalInput.dispatchEvent(new CustomEvent('change'));
|
1742 |
+
},
|
1743 |
+
getMixedTagsAsString: function getMixedTagsAsString(value) {
|
1744 |
+
var result = "",
|
1745 |
+
i = 0,
|
1746 |
+
currentTags = value,
|
1747 |
+
_interpolator = this.settings.mixTagsInterpolator;
|
1748 |
+
|
1749 |
+
function iterateChildren(rootNode) {
|
1750 |
+
rootNode.childNodes.forEach(function (node) {
|
1751 |
+
if (node.nodeType == 1) {
|
1752 |
+
if (node.classList.contains("tagify__tag")) {
|
1753 |
+
result += _interpolator[0] + JSON.stringify(currentTags[i++]) + _interpolator[1];
|
1754 |
+
return;
|
1755 |
+
} // Chrome adds <div><br></div> for empty new lines, and FF only adds <br>
|
1756 |
+
|
1757 |
+
|
1758 |
+
if (isFirefox && node.tagName == 'BR') result += "\r\n";else if (node.tagName == 'DIV') {
|
1759 |
+
result += "\r\n";
|
1760 |
+
iterateChildren(node);
|
1761 |
+
}
|
1762 |
+
} else result += node.textContent;
|
1763 |
+
});
|
1764 |
+
}
|
1765 |
+
|
1766 |
+
iterateChildren(this.DOM.input);
|
1767 |
+
return result;
|
1768 |
+
},
|
1769 |
+
|
1770 |
+
/**
|
1771 |
+
* Meassures an element's height, which might yet have been added DOM
|
1772 |
+
* https://stackoverflow.com/q/5944038/104380
|
1773 |
+
* @param {DOM} node
|
1774 |
+
*/
|
1775 |
+
getNodeHeight: function getNodeHeight(node) {
|
1776 |
+
var height,
|
1777 |
+
clone = node.cloneNode(true);
|
1778 |
+
clone.style.cssText = "position:fixed; top:-9999px; opacity:0";
|
1779 |
+
document.body.appendChild(clone);
|
1780 |
+
height = clone.clientHeight;
|
1781 |
+
clone.parentNode.removeChild(clone);
|
1782 |
+
return height;
|
1783 |
+
},
|
1784 |
+
|
1785 |
+
/**
|
1786 |
+
* Dropdown controller
|
1787 |
+
* @type {Object}
|
1788 |
+
*/
|
1789 |
+
dropdown: {
|
1790 |
+
init: function init() {
|
1791 |
+
this.DOM.dropdown = this.dropdown.build.call(this);
|
1792 |
+
this.DOM.dropdown.content = this.DOM.dropdown.querySelector('.tagify__dropdown__wrapper');
|
1793 |
+
},
|
1794 |
+
build: function build() {
|
1795 |
+
var _this$settings$dropdo = this.settings.dropdown,
|
1796 |
+
position = _this$settings$dropdo.position,
|
1797 |
+
classname = _this$settings$dropdo.classname,
|
1798 |
+
_className = "".concat(position == 'manual' ? "" : "tagify__dropdown tagify__dropdown--".concat(position), " ").concat(classname).trim(),
|
1799 |
+
elm = this.parseHTML("<div class=\"".concat(_className, "\" role=\"listbox\" aria-labelledby=\"dropdown\">\n <div class=\"tagify__dropdown__wrapper\"></div>\n </div>"));
|
1800 |
+
|
1801 |
+
return elm;
|
1802 |
+
},
|
1803 |
+
show: function show(value) {
|
1804 |
+
var _this12 = this;
|
1805 |
+
|
1806 |
+
var HTMLContent,
|
1807 |
+
_s = this.settings,
|
1808 |
+
firstListItem,
|
1809 |
+
firstListItemValue,
|
1810 |
+
ddHeight,
|
1811 |
+
selection = window.getSelection(),
|
1812 |
+
allowNewTags = _s.mode == 'mix' && !_s.enforceWhitelist,
|
1813 |
+
noWhitelist = !_s.whitelist || !_s.whitelist.length,
|
1814 |
+
isManual = _s.dropdown.position == 'manual';
|
1815 |
+
if (noWhitelist && !allowNewTags || _s.dropdown.enable === false) return;
|
1816 |
+
clearTimeout(this.dropdownHide__bindEventsTimeout); // if no value was supplied, show all the "whitelist" items in the dropdown
|
1817 |
+
// @type [Array] listItems
|
1818 |
+
// TODO: add a Setting to control items' sort order for "listItems"
|
1819 |
+
|
1820 |
+
this.suggestedListItems = this.dropdown.filterListItems.call(this, value);
|
1821 |
+
|
1822 |
+
if (!this.suggestedListItems.length) {
|
1823 |
+
// in mix-mode, if the value isn't included in the whilelist & "enforceWhitelist" setting is "false",
|
1824 |
+
// then add a custom suggestion item to the dropdown
|
1825 |
+
if (allowNewTags && !this.state.editing.scope) {
|
1826 |
+
this.suggestedListItems = [{
|
1827 |
+
value: value
|
1828 |
+
}];
|
1829 |
+
} // hide suggestions list if no suggestions were matched & cleanup
|
1830 |
+
else {
|
1831 |
+
this.input.autocomplete.suggest.call(this);
|
1832 |
+
this.dropdown.hide.call(this);
|
1833 |
+
return;
|
1834 |
+
}
|
1835 |
+
}
|
1836 |
+
|
1837 |
+
firstListItem = this.suggestedListItems[0];
|
1838 |
+
firstListItemValue = firstListItem.value || firstListItem;
|
1839 |
+
|
1840 |
+
if (_s.autoComplete) {
|
1841 |
+
// only fill the sugegstion if the value of the first list item STARTS with the input value (regardless of "fuzzysearch" setting)
|
1842 |
+
if (firstListItemValue.indexOf(value) == 0) this.input.autocomplete.suggest.call(this, firstListItem);
|
1843 |
+
}
|
1844 |
+
|
1845 |
+
HTMLContent = this.dropdown.createListHTML.call(this, this.suggestedListItems);
|
1846 |
+
this.DOM.dropdown.content.innerHTML = this.minify(HTMLContent); // if "enforceWhitelist" is "true", highlight the first suggested item
|
1847 |
+
|
1848 |
+
if (_s.enforceWhitelist && !isManual || _s.dropdown.highlightFirst) this.dropdown.highlightOption.call(this, this.DOM.dropdown.content.children[0]);
|
1849 |
+
this.DOM.scope.setAttribute("aria-expanded", true);
|
1850 |
+
this.trigger("dropdown:show", this.DOM.dropdown); // set the dropdown visible state to be the same as the searched value.
|
1851 |
+
// MUST be set *before* position() is called
|
1852 |
+
|
1853 |
+
this.state.dropdown.visible = value || true;
|
1854 |
+
this.state.selection = {
|
1855 |
+
anchorOffset: selection.anchorOffset,
|
1856 |
+
anchorNode: selection.anchorNode
|
1857 |
+
};
|
1858 |
+
this.dropdown.position.call(this); // if the dropdown has yet to be appended to the document,
|
1859 |
+
// append the dropdown to the body element & handle events
|
1860 |
+
|
1861 |
+
if (!document.body.contains(this.DOM.dropdown)) {
|
1862 |
+
if (!isManual) {
|
1863 |
+
this.events.binding.call(this, false); // unbind the main events
|
1864 |
+
// let the element render in the DOM first to accurately measure it
|
1865 |
+
// this.DOM.dropdown.style.cssText = "left:-9999px; top:-9999px;";
|
1866 |
+
|
1867 |
+
ddHeight = this.getNodeHeight(this.DOM.dropdown);
|
1868 |
+
this.DOM.dropdown.classList.add('tagify__dropdown--initial');
|
1869 |
+
this.dropdown.position.call(this, ddHeight);
|
1870 |
+
document.body.appendChild(this.DOM.dropdown);
|
1871 |
+
setTimeout(function () {
|
1872 |
+
return _this12.DOM.dropdown.classList.remove('tagify__dropdown--initial');
|
1873 |
+
});
|
1874 |
+
} // timeout is needed for when pressing arrow down to show the dropdown,
|
1875 |
+
// so the key event won't get registered in the dropdown events listeners
|
1876 |
+
|
1877 |
+
|
1878 |
+
setTimeout(this.dropdown.events.binding.bind(this));
|
1879 |
+
}
|
1880 |
+
},
|
1881 |
+
hide: function hide(force) {
|
1882 |
+
var _this$DOM = this.DOM,
|
1883 |
+
scope = _this$DOM.scope,
|
1884 |
+
dropdown = _this$DOM.dropdown,
|
1885 |
+
isManual = this.settings.dropdown.position == 'manual' && !force;
|
1886 |
+
if (!dropdown || !document.body.contains(dropdown) || isManual) return;
|
1887 |
+
window.removeEventListener('resize', this.dropdown.position);
|
1888 |
+
this.dropdown.events.binding.call(this, false); // unbind all events
|
1889 |
+
// if the dropdown is open, and the input (scope) is clicked,
|
1890 |
+
// the dropdown should be now "closed", and the next click (on the scope)
|
1891 |
+
// should re-open it, and without a timeout, clicking to close will re-open immediately
|
1892 |
+
|
1893 |
+
clearTimeout(this.dropdownHide__bindEventsTimeout);
|
1894 |
+
this.dropdownHide__bindEventsTimeout = setTimeout(this.events.binding.bind(this), 250); // re-bind main events
|
1895 |
+
|
1896 |
+
scope.setAttribute("aria-expanded", false);
|
1897 |
+
dropdown.parentNode.removeChild(dropdown);
|
1898 |
+
this.state.dropdown.visible = false;
|
1899 |
+
this.state.ddItemData = this.state.ddItemElm = this.state.selection = null;
|
1900 |
+
this.trigger("dropdown:hide", dropdown);
|
1901 |
+
},
|
1902 |
+
|
1903 |
+
/**
|
1904 |
+
* fill data into the suggestions list (mainly used to update the list when removing tags, so they will be re-added to the list. not efficient)
|
1905 |
+
*/
|
1906 |
+
refilter: function refilter() {
|
1907 |
+
this.suggestedListItems = this.dropdown.filterListItems.call(this, '');
|
1908 |
+
var listHTML = this.dropdown.createListHTML.call(this, this.suggestedListItems);
|
1909 |
+
this.DOM.dropdown.content.innerHTML = this.minify(listHTML);
|
1910 |
+
this.trigger("dropdown:updated", this.DOM.dropdown);
|
1911 |
+
},
|
1912 |
+
position: function position(ddHeight) {
|
1913 |
+
var isBelowViewport,
|
1914 |
+
rect,
|
1915 |
+
top,
|
1916 |
+
bottom,
|
1917 |
+
left,
|
1918 |
+
width,
|
1919 |
+
ddElm = this.DOM.dropdown;
|
1920 |
+
if (!this.state.dropdown.visible) return;
|
1921 |
+
|
1922 |
+
if (this.settings.dropdown.position == 'text') {
|
1923 |
+
rect = this.getCaretGlobalPosition();
|
1924 |
+
bottom = rect.bottom;
|
1925 |
+
top = rect.top;
|
1926 |
+
left = rect.left;
|
1927 |
+
width = 'auto';
|
1928 |
+
} else {
|
1929 |
+
rect = this.DOM.scope.getBoundingClientRect();
|
1930 |
+
top = rect.top;
|
1931 |
+
bottom = rect.bottom - 1;
|
1932 |
+
left = rect.left;
|
1933 |
+
width = rect.width + "px";
|
1934 |
+
}
|
1935 |
+
|
1936 |
+
top = Math.floor(top);
|
1937 |
+
bottom = Math.ceil(bottom);
|
1938 |
+
isBelowViewport = document.documentElement.clientHeight - bottom < (ddHeight || ddElm.clientHeight); // flip vertically if there is no space for the dropdown below the input
|
1939 |
+
|
1940 |
+
ddElm.style.cssText = "left:" + (left + window.pageXOffset) + "px; width:" + width + ";" + (isBelowViewport ? "bottom:" + (document.documentElement.clientHeight - top - window.pageYOffset - 2) + "px;" : "top: " + (bottom + window.pageYOffset) + "px");
|
1941 |
+
ddElm.setAttribute('placement', isBelowViewport ? "top" : "bottom");
|
1942 |
+
},
|
1943 |
+
events: {
|
1944 |
+
/**
|
1945 |
+
* Events should only be binded when the dropdown is rendered and removed when isn't
|
1946 |
+
* @param {Boolean} bindUnbind [optional. true when wanting to unbind all the events]
|
1947 |
+
*/
|
1948 |
+
binding: function binding() {
|
1949 |
+
var bindUnbind = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
1950 |
+
|
1951 |
+
// references to the ".bind()" methods must be saved so they could be unbinded later
|
1952 |
+
var _CB = this.dropdown.events.callbacks,
|
1953 |
+
_CBR = this.listeners.dropdown = this.listeners.dropdown || {
|
1954 |
+
position: this.dropdown.position.bind(this),
|
1955 |
+
onKeyDown: _CB.onKeyDown.bind(this),
|
1956 |
+
onMouseOver: _CB.onMouseOver.bind(this),
|
1957 |
+
onMouseLeave: _CB.onMouseLeave.bind(this),
|
1958 |
+
onClick: _CB.onClick.bind(this),
|
1959 |
+
onScroll: _CB.onScroll.bind(this)
|
1960 |
+
},
|
1961 |
+
action = bindUnbind ? 'addEventListener' : 'removeEventListener';
|
1962 |
+
|
1963 |
+
if (this.settings.dropdown.position != 'manual') {
|
1964 |
+
window[action]('resize', _CBR.position);
|
1965 |
+
window[action]('keydown', _CBR.onKeyDown);
|
1966 |
+
} // window[action]('mousedown', _CBR.onClick);
|
1967 |
+
|
1968 |
+
|
1969 |
+
this.DOM.dropdown[action]('mouseover', _CBR.onMouseOver);
|
1970 |
+
this.DOM.dropdown[action]('mouseleave', _CBR.onMouseLeave);
|
1971 |
+
this.DOM.dropdown[action]('mousedown', _CBR.onClick);
|
1972 |
+
this.DOM.dropdown.content[action]('scroll', _CBR.onScroll); // add back the main "click" event because it is needed for removing/clicking already-existing tags, even if dropdown is shown
|
1973 |
+
|
1974 |
+
this.DOM[this.listeners.main.click[0]][action]('click', this.listeners.main.click[1]);
|
1975 |
+
},
|
1976 |
+
callbacks: {
|
1977 |
+
onKeyDown: function onKeyDown(e) {
|
1978 |
+
// get the "active" element, and if there was none (yet) active, use first child
|
1979 |
+
var activeListElm = this.DOM.dropdown.querySelector("[class$='--active']"),
|
1980 |
+
selectedElm = activeListElm;
|
1981 |
+
|
1982 |
+
switch (e.key) {
|
1983 |
+
case 'ArrowDown':
|
1984 |
+
case 'ArrowUp':
|
1985 |
+
case 'Down': // >IE11
|
1986 |
+
|
1987 |
+
case 'Up':
|
1988 |
+
{
|
1989 |
+
// >IE11
|
1990 |
+
e.preventDefault();
|
1991 |
+
var dropdownItems;
|
1992 |
+
if (selectedElm) selectedElm = selectedElm[(e.key == 'ArrowUp' || e.key == 'Up' ? "previous" : "next") + "ElementSibling"]; // if no element was found, loop
|
1993 |
+
|
1994 |
+
if (!selectedElm) {
|
1995 |
+
dropdownItems = this.DOM.dropdown.content.children;
|
1996 |
+
selectedElm = dropdownItems[e.key == 'ArrowUp' || e.key == 'Up' ? dropdownItems.length - 1 : 0];
|
1997 |
+
}
|
1998 |
+
|
1999 |
+
this.dropdown.highlightOption.call(this, selectedElm, true);
|
2000 |
+
break;
|
2001 |
+
}
|
2002 |
+
|
2003 |
+
case 'Escape':
|
2004 |
+
case 'Esc':
|
2005 |
+
// IE11
|
2006 |
+
this.dropdown.hide.call(this);
|
2007 |
+
break;
|
2008 |
+
|
2009 |
+
case 'ArrowRight':
|
2010 |
+
if (this.state.actions.ArrowLeft) return;
|
2011 |
+
|
2012 |
+
case 'Tab':
|
2013 |
+
{
|
2014 |
+
// in mix-mode, treat arrowRight like Enter key, so a tag will be created
|
2015 |
+
if (this.settings.mode != 'mix' && !this.settings.autoComplete.rightKey) {
|
2016 |
+
try {
|
2017 |
+
var value = selectedElm ? selectedElm.textContent : this.suggestedListItems[0].value;
|
2018 |
+
this.input.autocomplete.set.call(this, value);
|
2019 |
+
} catch (err) {}
|
2020 |
+
|
2021 |
+
return false;
|
2022 |
+
}
|
2023 |
+
}
|
2024 |
+
|
2025 |
+
case 'Enter':
|
2026 |
+
{
|
2027 |
+
e.preventDefault();
|
2028 |
+
this.dropdown.selectOption.call(this, activeListElm);
|
2029 |
+
break;
|
2030 |
+
}
|
2031 |
+
|
2032 |
+
case 'Backspace':
|
2033 |
+
{
|
2034 |
+
if (this.settings.mode == 'mix' || this.state.editing.scope) return;
|
2035 |
+
|
2036 |
+
var _value = this.input.value.trim();
|
2037 |
+
|
2038 |
+
if (_value == "" || _value.charCodeAt(0) == 8203) {
|
2039 |
+
if (this.settings.backspace === true) this.removeTag();else if (this.settings.backspace == 'edit') setTimeout(this.editTag.bind(this), 0);
|
2040 |
+
}
|
2041 |
+
}
|
2042 |
+
}
|
2043 |
+
},
|
2044 |
+
onMouseOver: function onMouseOver(e) {
|
2045 |
+
var ddItem = e.target.closest('.tagify__dropdown__item'); // event delegation check
|
2046 |
+
|
2047 |
+
ddItem && this.dropdown.highlightOption.call(this, ddItem);
|
2048 |
+
},
|
2049 |
+
onMouseLeave: function onMouseLeave(e) {
|
2050 |
+
// de-highlight any previously highlighted option
|
2051 |
+
this.dropdown.highlightOption.call(this);
|
2052 |
+
},
|
2053 |
+
onClick: function onClick(e) {
|
2054 |
+
if (e.button != 0 || e.target == this.DOM.dropdown) return; // allow only mouse left-clicks
|
2055 |
+
|
2056 |
+
var listItemElm = e.target.closest(".tagify__dropdown__item");
|
2057 |
+
this.dropdown.selectOption.call(this, listItemElm);
|
2058 |
+
},
|
2059 |
+
onScroll: function onScroll(e) {
|
2060 |
+
var elm = e.target,
|
2061 |
+
pos = elm.scrollTop / (elm.scrollHeight - elm.parentNode.clientHeight) * 100;
|
2062 |
+
this.trigger("dropdown:scroll", {
|
2063 |
+
percentage: Math.round(pos)
|
2064 |
+
});
|
2065 |
+
}
|
2066 |
+
}
|
2067 |
+
},
|
2068 |
+
|
2069 |
+
/**
|
2070 |
+
* mark the currently active suggestion option
|
2071 |
+
* @param {Object} elm option DOM node
|
2072 |
+
* @param {Boolean} adjustScroll when navigation with keyboard arrows (up/down), aut-scroll to always show the highlighted element
|
2073 |
+
*/
|
2074 |
+
highlightOption: function highlightOption(elm, adjustScroll) {
|
2075 |
+
var className = "tagify__dropdown__item--active",
|
2076 |
+
itemData; // focus casues a bug in Firefox with the placeholder been shown on the input element
|
2077 |
+
// if( this.settings.dropdown.position != 'manual' )
|
2078 |
+
// elm.focus();
|
2079 |
+
|
2080 |
+
if (this.state.ddItemElm) {
|
2081 |
+
this.state.ddItemElm.classList.remove(className);
|
2082 |
+
this.state.ddItemElm.removeAttribute("aria-selected");
|
2083 |
+
}
|
2084 |
+
|
2085 |
+
if (!elm) {
|
2086 |
+
this.state.ddItemData = null;
|
2087 |
+
this.state.ddItemElm = null;
|
2088 |
+
this.input.autocomplete.suggest.call(this);
|
2089 |
+
return;
|
2090 |
+
}
|
2091 |
+
|
2092 |
+
itemData = this.suggestedListItems[this.getNodeIndex(elm)];
|
2093 |
+
this.state.ddItemData = itemData;
|
2094 |
+
this.state.ddItemElm = elm; // this.DOM.dropdown.querySelectorAll("[class$='--active']").forEach(activeElm => activeElm.classList.remove(className));
|
2095 |
+
|
2096 |
+
elm.classList.add(className);
|
2097 |
+
elm.setAttribute("aria-selected", true);
|
2098 |
+
if (adjustScroll) elm.parentNode.scrollTop = elm.clientHeight + elm.offsetTop - elm.parentNode.clientHeight; // Try to autocomplete the typed value with the currently highlighted dropdown item
|
2099 |
+
|
2100 |
+
if (this.settings.autoComplete) {
|
2101 |
+
this.input.autocomplete.suggest.call(this, itemData);
|
2102 |
+
if (this.settings.dropdown.position != 'manual') this.dropdown.position.call(this); // suggestions might alter the height of the tagify wrapper because of unkown suggested term length that could drop to the next line
|
2103 |
+
}
|
2104 |
+
},
|
2105 |
+
|
2106 |
+
/**
|
2107 |
+
* Create a tag from the currently active suggestion option
|
2108 |
+
* @param {Object} elm DOM node to select
|
2109 |
+
*/
|
2110 |
+
selectOption: function selectOption(elm) {
|
2111 |
+
var _this13 = this;
|
2112 |
+
|
2113 |
+
if (!elm) return; // temporary set the "actions" state to indicate to the main "blur" event it shouldn't run
|
2114 |
+
|
2115 |
+
this.state.actions.selectOption = true;
|
2116 |
+
setTimeout(function () {
|
2117 |
+
return _this13.state.actions.selectOption = false;
|
2118 |
+
}, 50);
|
2119 |
+
var hideDropdown = this.settings.dropdown.closeOnSelect,
|
2120 |
+
value = this.suggestedListItems[this.getNodeIndex(elm)] || this.input.value;
|
2121 |
+
this.trigger("dropdown:select", value);
|
2122 |
+
this.addTags([value], true); // Tagify instances should re-focus to the input element once an option was selected, to allow continuous typing
|
2123 |
+
|
2124 |
+
if (!this.state.editing) setTimeout(function () {
|
2125 |
+
_this13.DOM.input.focus();
|
2126 |
+
|
2127 |
+
_this13.toggleFocusClass(true);
|
2128 |
+
});
|
2129 |
+
|
2130 |
+
if (hideDropdown) {
|
2131 |
+
this.dropdown.hide.call(this); // setTimeout(() => this.events.callbacks.onFocusBlur.call(this, {type:"blur"}), 60)
|
2132 |
+
}
|
2133 |
+
},
|
2134 |
+
|
2135 |
+
/**
|
2136 |
+
* returns an HTML string of the suggestions' list items
|
2137 |
+
* @param {string} value string to filter the whitelist by
|
2138 |
+
* @return {Array} list of filtered whitelist items according to the settings provided and current value
|
2139 |
+
*/
|
2140 |
+
filterListItems: function filterListItems(value) {
|
2141 |
+
var _this14 = this;
|
2142 |
+
|
2143 |
+
var _s = this.settings,
|
2144 |
+
list = [],
|
2145 |
+
whitelist = _s.whitelist,
|
2146 |
+
suggestionsCount = _s.dropdown.maxItems || Infinity,
|
2147 |
+
searchKeys = _s.dropdown.searchKeys.concat(["searchBy", "value"]),
|
2148 |
+
whitelistItem,
|
2149 |
+
valueIsInWhitelist,
|
2150 |
+
whitelistItemValueIndex,
|
2151 |
+
searchBy,
|
2152 |
+
isDuplicate,
|
2153 |
+
i = 0;
|
2154 |
+
|
2155 |
+
if (!value) {
|
2156 |
+
return (_s.duplicates ? whitelist : whitelist.filter(function (item) {
|
2157 |
+
return !_this14.isTagDuplicate(isObject(item) ? item.value : item);
|
2158 |
+
}) // don't include tags which have already been added.
|
2159 |
+
).slice(0, suggestionsCount); // respect "maxItems" dropdown setting
|
2160 |
+
}
|
2161 |
+
|
2162 |
+
for (; i < whitelist.length; i++) {
|
2163 |
+
whitelistItem = whitelist[i] instanceof Object ? whitelist[i] : {
|
2164 |
+
value: whitelist[i]
|
2165 |
+
}; //normalize value as an Object
|
2166 |
+
|
2167 |
+
searchBy = searchKeys.reduce(function (values, k) {
|
2168 |
+
return values + " " + (whitelistItem[k] || "");
|
2169 |
+
}, "").toLowerCase();
|
2170 |
+
whitelistItemValueIndex = searchBy.indexOf(value.toLowerCase());
|
2171 |
+
valueIsInWhitelist = _s.dropdown.fuzzySearch ? whitelistItemValueIndex >= 0 : whitelistItemValueIndex == 0;
|
2172 |
+
isDuplicate = !_s.duplicates && this.isTagDuplicate(isObject(whitelistItem) ? whitelistItem.value : whitelistItem); // match for the value within each "whitelist" item
|
2173 |
+
|
2174 |
+
if (valueIsInWhitelist && !isDuplicate && suggestionsCount--) list.push(whitelistItem);
|
2175 |
+
if (suggestionsCount == 0) break;
|
2176 |
+
}
|
2177 |
+
|
2178 |
+
return list;
|
2179 |
+
},
|
2180 |
+
|
2181 |
+
/**
|
2182 |
+
* Creates the dropdown items' HTML
|
2183 |
+
* @param {Array} list [Array of Objects]
|
2184 |
+
* @return {String}
|
2185 |
+
*/
|
2186 |
+
createListHTML: function createListHTML(optionsArr) {
|
2187 |
+
var template = this.settings.templates.dropdownItem.bind(this);
|
2188 |
+
return this.minify(optionsArr.map(template).join(""));
|
2189 |
+
}
|
2190 |
+
}
|
2191 |
+
};
|
2192 |
+
return Tagify;
|
2193 |
+
}));
|
inc/yturbo-css.css
CHANGED
@@ -1,3 +1,5 @@
|
|
|
|
|
|
1 |
tt {
|
2 |
padding: 1px 5px 1px;
|
3 |
margin: 0 1px;
|
@@ -134,6 +136,11 @@ td table {
|
|
134 |
.hide {
|
135 |
display:none;
|
136 |
}
|
|
|
|
|
|
|
|
|
|
|
137 |
.types, .shortcodes {
|
138 |
margin-bottom: 6px;
|
139 |
display: table;
|
@@ -232,10 +239,74 @@ td table {
|
|
232 |
vertical-align: super;
|
233 |
}
|
234 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
235 |
/* блок восстановления css старого wordpress begin */
|
236 |
.foptions .postbox {
|
237 |
border: 1px solid #D8D8D8;
|
238 |
}
|
|
|
239 |
.foptions input[type=color],
|
240 |
.foptions input[type=date],
|
241 |
.foptions input[type=datetime-local],
|
@@ -260,6 +331,7 @@ td table {
|
|
260 |
border: 1px solid #b4b9be;
|
261 |
border-radius: 3px;
|
262 |
}
|
|
|
263 |
.foptions input[type=checkbox]:focus,
|
264 |
.foptions input[type=color]:focus,
|
265 |
.foptions input[type=date]:focus,
|
@@ -296,6 +368,7 @@ td table {
|
|
296 |
.foptions input[type=week] {
|
297 |
padding: 0 0 0 8px;
|
298 |
}
|
|
|
299 |
.foptions input:disabled,
|
300 |
.foptions select:disabled,
|
301 |
.foptions textarea:disabled {
|
1 |
+
@charset "utf-8";
|
2 |
+
|
3 |
tt {
|
4 |
padding: 1px 5px 1px;
|
5 |
margin: 0 1px;
|
136 |
.hide {
|
137 |
display:none;
|
138 |
}
|
139 |
+
.foptions #current-version {
|
140 |
+
font-size: 12px;
|
141 |
+
vertical-align: super;
|
142 |
+
font-weight: 600;
|
143 |
+
}
|
144 |
.types, .shortcodes {
|
145 |
margin-bottom: 6px;
|
146 |
display: table;
|
239 |
vertical-align: super;
|
240 |
}
|
241 |
|
242 |
+
/* блок выбора тегов begin */
|
243 |
+
.tagify__dropdown__wrapper {
|
244 |
+
max-width: 484px;
|
245 |
+
padding: 2px 1px 3px 1px;
|
246 |
+
border: 1px solid #BDE0FF;
|
247 |
+
margin-top: 2px;
|
248 |
+
margin-bottom: 2px;
|
249 |
+
box-shadow: none;
|
250 |
+
background: aliceblue;
|
251 |
+
border-radius: 3px;
|
252 |
+
}
|
253 |
+
.ytexcludetagslist-input,
|
254 |
+
.ytexcludetagslist-input2 {
|
255 |
+
max-width: 484px;
|
256 |
+
padding: 2px 1px 3px 1px;
|
257 |
+
margin-bottom: 8px;
|
258 |
+
--tag-bg: #9d989838;
|
259 |
+
--tag-hover: #40a0ed63;
|
260 |
+
--tag-text-color: #23282d;
|
261 |
+
--tag-remove-bg: #c21c1c9e;
|
262 |
+
--tag-remove-btn-bg--hover: #940707c7;
|
263 |
+
}
|
264 |
+
.ytexcludetagslist-input .tagify__tag__removeBtn:hover+div>span {
|
265 |
+
opacity: 1;
|
266 |
+
color: #881010;
|
267 |
+
}
|
268 |
+
.ytexcludetagslist-input2 .tagify__tag__removeBtn:hover+div>span {
|
269 |
+
opacity: 1;
|
270 |
+
color: #881010;
|
271 |
+
}
|
272 |
+
.tagify__tag {
|
273 |
+
margin: 5px 1px 1px 5px;
|
274 |
+
}
|
275 |
+
.tagify__input {
|
276 |
+
min-width: 10px;
|
277 |
+
padding-left: 1px;
|
278 |
+
padding-right: 1px;
|
279 |
+
margin-top: 6px;
|
280 |
+
font-size: 12px;
|
281 |
+
}
|
282 |
+
.tags-look .tagify__dropdown__item {
|
283 |
+
display: inline-block;
|
284 |
+
border-radius: 3px;
|
285 |
+
padding: .3em .5em;
|
286 |
+
border: 1px solid #CCC;
|
287 |
+
background: #F3F3F3;
|
288 |
+
margin: 3px 0px 2px 5px;
|
289 |
+
font-size: .85em;
|
290 |
+
color: black;
|
291 |
+
transition: 0s;
|
292 |
+
}
|
293 |
+
.tags-look .tagify__dropdown__item--active {
|
294 |
+
color: black;
|
295 |
+
}
|
296 |
+
.tags-look .tagify__dropdown__item:hover {
|
297 |
+
background: lightyellow;
|
298 |
+
border-color: gold;
|
299 |
+
}
|
300 |
+
.tagify__tag>div>* {
|
301 |
+
line-height: 1.2;
|
302 |
+
}
|
303 |
+
/* блок выбора тегов end */
|
304 |
+
|
305 |
/* блок восстановления css старого wordpress begin */
|
306 |
.foptions .postbox {
|
307 |
border: 1px solid #D8D8D8;
|
308 |
}
|
309 |
+
.foptions .tagify,
|
310 |
.foptions input[type=color],
|
311 |
.foptions input[type=date],
|
312 |
.foptions input[type=datetime-local],
|
331 |
border: 1px solid #b4b9be;
|
332 |
border-radius: 3px;
|
333 |
}
|
334 |
+
.foptions .tagify--focus,
|
335 |
.foptions input[type=checkbox]:focus,
|
336 |
.foptions input[type=color]:focus,
|
337 |
.foptions input[type=date]:focus,
|
368 |
.foptions input[type=week] {
|
369 |
padding: 0 0 0 8px;
|
370 |
}
|
371 |
+
.foptions .tagify:disabled,
|
372 |
.foptions input:disabled,
|
373 |
.foptions select:disabled,
|
374 |
.foptions textarea:disabled {
|
inc/yturbo-script.js
CHANGED
@@ -1,33 +1,3 @@
|
|
1 |
-
jQuery(document).ready(function($) {
|
2 |
-
$('.tcode').textillate({
|
3 |
-
loop: true,
|
4 |
-
minDisplayTime: 5000,
|
5 |
-
initialDelay: 800,
|
6 |
-
autoStart: true,
|
7 |
-
inEffects: [],
|
8 |
-
outEffects: [],
|
9 |
-
in: {
|
10 |
-
effect: 'rollIn',
|
11 |
-
delayScale: 1.5,
|
12 |
-
delay: 50,
|
13 |
-
sync: false,
|
14 |
-
shuffle: true,
|
15 |
-
reverse: false,
|
16 |
-
callback: function() {}
|
17 |
-
},
|
18 |
-
out: {
|
19 |
-
effect: 'fadeOut',
|
20 |
-
delayScale: 1.5,
|
21 |
-
delay: 50,
|
22 |
-
sync: false,
|
23 |
-
shuffle: true,
|
24 |
-
reverse: false,
|
25 |
-
callback: function() {}
|
26 |
-
},
|
27 |
-
callback: function() {}
|
28 |
-
});
|
29 |
-
})
|
30 |
-
|
31 |
jQuery(document).ready(function($) {
|
32 |
var thumb = jQuery('#ytthumbnail');
|
33 |
var select = this.value;
|
@@ -300,6 +270,15 @@ jQuery(document).ready(function($) {
|
|
300 |
}
|
301 |
});
|
302 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
303 |
var block1 = jQuery('#ytad1');
|
304 |
|
305 |
if (jQuery('#ytad1').is(':checked')) {
|
@@ -1065,7 +1044,7 @@ jQuery(document).ready(function($){
|
|
1065 |
});
|
1066 |
|
1067 |
function setExpTime() {
|
1068 |
-
var limit =
|
1069 |
var time = localStorage.getItem('yt-time');
|
1070 |
if (time === null) {
|
1071 |
localStorage.setItem('yt-time', +new Date());
|
@@ -1078,7 +1057,7 @@ jQuery(document).ready(function($){
|
|
1078 |
}
|
1079 |
|
1080 |
function checkExpTime() {
|
1081 |
-
var limit =
|
1082 |
var time = localStorage.getItem('yt-time');
|
1083 |
if (time === null) {
|
1084 |
|
@@ -1089,4 +1068,125 @@ jQuery(document).ready(function($){
|
|
1089 |
}
|
1090 |
}
|
1091 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1092 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
jQuery(document).ready(function($) {
|
2 |
var thumb = jQuery('#ytthumbnail');
|
3 |
var select = this.value;
|
270 |
}
|
271 |
});
|
272 |
|
273 |
+
var rurls = jQuery('#ytexcludeurls');
|
274 |
+
rurls.change(function() {
|
275 |
+
if (jQuery('#ytexcludeurls').is(':checked')) {
|
276 |
+
jQuery('.ytexcludeurlslisttr').fadeIn();
|
277 |
+
} else {
|
278 |
+
jQuery('.ytexcludeurlslisttr').hide();
|
279 |
+
}
|
280 |
+
});
|
281 |
+
|
282 |
var block1 = jQuery('#ytad1');
|
283 |
|
284 |
if (jQuery('#ytad1').is(':checked')) {
|
1044 |
});
|
1045 |
|
1046 |
function setExpTime() {
|
1047 |
+
var limit = 90 * 24 * 60 * 60 * 1000; // 3 месяца
|
1048 |
var time = localStorage.getItem('yt-time');
|
1049 |
if (time === null) {
|
1050 |
localStorage.setItem('yt-time', +new Date());
|
1057 |
}
|
1058 |
|
1059 |
function checkExpTime() {
|
1060 |
+
var limit = 90 * 24 * 60 * 60 * 1000; // 3 месяца
|
1061 |
var time = localStorage.getItem('yt-time');
|
1062 |
if (time === null) {
|
1063 |
|
1068 |
}
|
1069 |
}
|
1070 |
|
1071 |
+
});
|
1072 |
+
|
1073 |
+
jQuery(document).ready(function($) {
|
1074 |
+
|
1075 |
+
var str = $('#tags-list').val();
|
1076 |
+
var whitelist = str.split(',');
|
1077 |
+
|
1078 |
+
var input = document.querySelector('input[name="ytexcludetagslist-input"]'),
|
1079 |
+
tagify = new Tagify(input, {
|
1080 |
+
whitelist: whitelist,
|
1081 |
+
enforceWhitelist: true,
|
1082 |
+
dropdown: {
|
1083 |
+
maxItems: 20,
|
1084 |
+
classname: 'tags-look',
|
1085 |
+
enabled: 0,
|
1086 |
+
closeOnSelect: false,
|
1087 |
+
}
|
1088 |
+
})
|
1089 |
+
|
1090 |
+
tagify
|
1091 |
+
.on('add', onAddTag)
|
1092 |
+
.on('remove', onRemoveTag)
|
1093 |
+
.on('invalid', onInvalidTag)
|
1094 |
+
|
1095 |
+
function onAddTag(e) {
|
1096 |
+
|
1097 |
+
$('tag').data('title', $('tag').attr('title')).removeAttr('title');
|
1098 |
+
var str = tagify.DOM.originalInput.value;
|
1099 |
+
var temp = str.replace(/{"value":"/g, '');
|
1100 |
+
temp = temp.replace(/"}/g, '');
|
1101 |
+
temp = temp.replace(/"}/g, '');
|
1102 |
+
temp = temp.replace(/\[/g, '');
|
1103 |
+
temp = temp.replace(/\]/g, '');
|
1104 |
+
|
1105 |
+
$('#ytexcludetagslist').val(temp);
|
1106 |
+
}
|
1107 |
+
|
1108 |
+
function onRemoveTag(e) {
|
1109 |
+
if ($('tags').hasClass('tagify--focus')) {
|
1110 |
+
tagify.dropdown.hide.call(tagify);
|
1111 |
+
$('tags').removeClass('tagify--focus');
|
1112 |
+
}
|
1113 |
+
|
1114 |
+
var str = tagify.DOM.originalInput.value;
|
1115 |
+
var temp = str.replace(/{"value":"/g, '');
|
1116 |
+
temp = temp.replace(/"}/g, '');
|
1117 |
+
temp = temp.replace(/"}/g, '');
|
1118 |
+
temp = temp.replace(/\[/g, '');
|
1119 |
+
temp = temp.replace(/\]/g, '');
|
1120 |
+
|
1121 |
+
$('#ytexcludetagslist').val(temp);
|
1122 |
+
|
1123 |
+
}
|
1124 |
+
|
1125 |
+
function onInvalidTag(e) {
|
1126 |
+
tagify.dropdown.show.call(tagify);
|
1127 |
+
}
|
1128 |
+
|
1129 |
+
$('tag').data('title', $('tag').attr('title')).removeAttr('title');
|
1130 |
+
|
1131 |
+
});
|
1132 |
+
|
1133 |
+
|
1134 |
+
jQuery(document).ready(function($) {
|
1135 |
+
|
1136 |
+
var str = $('#tags-list2').val();
|
1137 |
+
var whitelist = str.split(',');
|
1138 |
+
|
1139 |
+
var input = document.querySelector('input[name="ytexcludetagslist-input2"]'),
|
1140 |
+
tagify2 = new Tagify(input, {
|
1141 |
+
whitelist: whitelist,
|
1142 |
+
enforceWhitelist: true,
|
1143 |
+
dropdown: {
|
1144 |
+
maxItems: 20,
|
1145 |
+
classname: 'tags-look',
|
1146 |
+
enabled: 0,
|
1147 |
+
closeOnSelect: false,
|
1148 |
+
}
|
1149 |
+
})
|
1150 |
+
|
1151 |
+
tagify2
|
1152 |
+
.on('add', onAddTag2)
|
1153 |
+
.on('remove', onRemoveTag2)
|
1154 |
+
.on('invalid', onInvalidTag2)
|
1155 |
+
|
1156 |
+
function onAddTag2(e) {
|
1157 |
+
|
1158 |
+
$('tag').data('title', $('tag').attr('title')).removeAttr('title');
|
1159 |
+
var str = tagify2.DOM.originalInput.value;
|
1160 |
+
var temp = str.replace(/{"value":"/g, '');
|
1161 |
+
temp = temp.replace(/"}/g, '');
|
1162 |
+
temp = temp.replace(/"}/g, '');
|
1163 |
+
temp = temp.replace(/\[/g, '');
|
1164 |
+
temp = temp.replace(/\]/g, '');
|
1165 |
+
|
1166 |
+
$('#ytexcludetagslist2').val(temp);
|
1167 |
+
}
|
1168 |
+
|
1169 |
+
function onRemoveTag2(e) {
|
1170 |
+
if ($('tags').hasClass('tagify--focus')) {
|
1171 |
+
tagify2.dropdown.hide.call(tagify2);
|
1172 |
+
$('tags').removeClass('tagify--focus');
|
1173 |
+
}
|
1174 |
+
|
1175 |
+
var str = tagify2.DOM.originalInput.value;
|
1176 |
+
var temp = str.replace(/{"value":"/g, '');
|
1177 |
+
temp = temp.replace(/"}/g, '');
|
1178 |
+
temp = temp.replace(/"}/g, '');
|
1179 |
+
temp = temp.replace(/\[/g, '');
|
1180 |
+
temp = temp.replace(/\]/g, '');
|
1181 |
+
|
1182 |
+
$('#ytexcludetagslist2').val(temp);
|
1183 |
+
|
1184 |
+
}
|
1185 |
+
|
1186 |
+
function onInvalidTag2(e) {
|
1187 |
+
tagify2.dropdown.show.call(tagify2);
|
1188 |
+
}
|
1189 |
+
|
1190 |
+
$('tag').data('title', $('tag').attr('title')).removeAttr('title');
|
1191 |
+
|
1192 |
});
|
readme.txt
CHANGED
@@ -5,7 +5,7 @@ Tags: yandex, turbo, yandex turbo, rss, feed, турбо, яндекс турб
|
|
5 |
Requires at least: 4.4
|
6 |
Tested up to: 5.4
|
7 |
Requires PHP: 5.3
|
8 |
-
Stable tag: 1.
|
9 |
|
10 |
Создание RSS-ленты для сервиса Яндекс.Турбо.
|
11 |
|
@@ -19,6 +19,7 @@ Stable tag: 1.26
|
|
19 |
|
20 |
Если вам понравился этот плагин, то, <strong>пожалуйста</strong>, поставьте ему 5 звезд.
|
21 |
|
|
|
22 |
|
23 |
== Frequently Asked Questions ==
|
24 |
|
@@ -39,6 +40,10 @@ Stable tag: 1.26
|
|
39 |
|
40 |
Четвертое. Не стесняйтесь писать Платонам и требовать от них четкого ответа, что именно не так с вашими турбо-страницами. Яндекс запустил проверку турбо-страниц, но работает она сейчас достаточно криво. Например, Яндекс ругается на отсутствие даты и дает для примера старую версию турбо-страницы и забанненую версию этой турбо-страницы. Самое удивительное - и там и там даты нет. Как можно ругаться на несоответствие дат, если и там и там их нет? Поэтому еще раз повторю, доставайте Платонов - пусть связываются с командой, работающей над турбо-страницами и узнают точную причину бана. В противном случае, велика вероятность, что Платоны на глазок определят проблему и в этом случае устранить бан турбо-страниц будет сложно.
|
41 |
|
|
|
|
|
|
|
|
|
42 |
= Лента не проходит валидацию, что делать? =
|
43 |
|
44 |
RSS-лента для Яндекс.Турбо никогда не сможет пройти обычную валидацию, так как технические требования Яндекс.Турбо несовместимы со стандартами обычного RSS.
|
@@ -339,7 +344,7 @@ function ct_get_steps() {
|
|
339 |
<p>второе изображение</p>
|
340 |
<p>контент записи</p>`
|
341 |
|
342 |
-
Учтите, что результат вывода вашего шаблона будет потом обработан фильтрами плагина.
|
343 |
|
344 |
= Какие шорткоды можно использовать в шаблонах? =
|
345 |
|
@@ -401,6 +406,23 @@ add_filter( 'yturbo_custom_title', 'my_custom_title_for_turbo' );`
|
|
401 |
|
402 |
В этом случае будут выполнены все требования Яндекса к заголовкам записей.
|
403 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
404 |
== Screenshots ==
|
405 |
|
406 |
1. Пример добавленных RSS-лент в Яндекс.Вебмастере.
|
@@ -409,7 +431,16 @@ add_filter( 'yturbo_custom_title', 'my_custom_title_for_turbo' );`
|
|
409 |
|
410 |
== Changelog ==
|
411 |
|
412 |
-
= 1.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
413 |
|
414 |
* изменен интерфейс удаления шорткодов из контента турбо-страниц.
|
415 |
* удалена опция вывода заголовков из SEO-плагинов (Яндекс стал требовать соответствия заголовков).
|
5 |
Requires at least: 4.4
|
6 |
Tested up to: 5.4
|
7 |
Requires PHP: 5.3
|
8 |
+
Stable tag: 1.27
|
9 |
|
10 |
Создание RSS-ленты для сервиса Яндекс.Турбо.
|
11 |
|
19 |
|
20 |
Если вам понравился этот плагин, то, <strong>пожалуйста</strong>, поставьте ему 5 звезд.
|
21 |
|
22 |
+
Для плагина есть премиум-дополнение [WPCase: Turbo Ads](https://wpcase.ru/wpcase-turbo-ads/) для неограниченной вставки рекламы на турбо-страницах.
|
23 |
|
24 |
== Frequently Asked Questions ==
|
25 |
|
40 |
|
41 |
Четвертое. Не стесняйтесь писать Платонам и требовать от них четкого ответа, что именно не так с вашими турбо-страницами. Яндекс запустил проверку турбо-страниц, но работает она сейчас достаточно криво. Например, Яндекс ругается на отсутствие даты и дает для примера старую версию турбо-страницы и забанненую версию этой турбо-страницы. Самое удивительное - и там и там даты нет. Как можно ругаться на несоответствие дат, если и там и там их нет? Поэтому еще раз повторю, доставайте Платонов - пусть связываются с командой, работающей над турбо-страницами и узнают точную причину бана. В противном случае, велика вероятность, что Платоны на глазок определят проблему и в этом случае устранить бан турбо-страниц будет сложно.
|
42 |
|
43 |
+
= Лента не меняется, что делать? =
|
44 |
+
|
45 |
+
Один из самых частых вопросов. Вы изменили настройки плагина, потом смотрите вашу RSS-ленту в браузере и не видите никаких изменений. Так происходит из-за того, что все браузеры кэшируют открытые RSS-ленты. Чтобы увидеть изменения надо произвести "жесткую" перезагрузку страницы. В браузерах это делается при нажатии клавиш <strong>Ctrl + F5</strong>.
|
46 |
+
|
47 |
= Лента не проходит валидацию, что делать? =
|
48 |
|
49 |
RSS-лента для Яндекс.Турбо никогда не сможет пройти обычную валидацию, так как технические требования Яндекс.Турбо несовместимы со стандартами обычного RSS.
|
344 |
<p>второе изображение</p>
|
345 |
<p>контент записи</p>`
|
346 |
|
347 |
+
Учтите, что результат вывода вашего шаблона будет потом обработан фильтрами плагина. Это может вызвать определенные проблемы, так как фильтры плагина удалят всю лишнюю разметку, которая вам может быть нужна. Например, если вы пытаетесь создать турбо-галерею, а плагин каждую вашу картинку оборачивает в тег `<figure>`, что портит разметку турбо-галереи. В таком случае вам нужно воспользоваться фильтром `yturbo_before_ads`, который срабатывает почти в самом конце обработки контента записи прямо перед вставкой рекламы. Однако, ваши переменные не должны быть обернуты символами <strong>%%</strong> (их содержимое будет удалено при обработке шаблона). Воспользуйтесь любыми другими символами, чтобы отфильтровать потом вашу переменную.
|
348 |
|
349 |
= Какие шорткоды можно использовать в шаблонах? =
|
350 |
|
406 |
|
407 |
В этом случае будут выполнены все требования Яндекса к заголовкам записей.
|
408 |
|
409 |
+
= Как переопределить список тегов для удаления? =
|
410 |
+
|
411 |
+
По умолчанию в плагине можно удалить теги только из предустановленного списка тегов. В этом списке нет важных тегов вроде `<p>` и `<ul>`, так как их неосторожное удаление может привести к фатальным последствиям. Однако, в плагине есть фильтр, которым можно расширить список тегов для удаления и включить в него нужные вам теги. Делается это так:
|
412 |
+
|
413 |
+
`function my_custom_tags_list( $tags ) {
|
414 |
+
|
415 |
+
//скобки и пробелы недопустимы
|
416 |
+
//не забываем запятую в начале
|
417 |
+
$tags .= ',p,table,ul';
|
418 |
+
|
419 |
+
return $tags;
|
420 |
+
}
|
421 |
+
add_filter( 'yturbo_tags_list', 'my_custom_tags_list' );`
|
422 |
+
|
423 |
+
В список можно включать только парные теги (имеющие тег закрытия). Самозакрывающиеся теги фильтром будут проигнорированы.
|
424 |
+
|
425 |
+
|
426 |
== Screenshots ==
|
427 |
|
428 |
1. Пример добавленных RSS-лент в Яндекс.Вебмастере.
|
431 |
|
432 |
== Changelog ==
|
433 |
|
434 |
+
= 1.27 (06.04.2020) =
|
435 |
+
|
436 |
+
* добавлена опция формирования RSS-ленты из удаленных записей.
|
437 |
+
* изменен интерфейс фильтров удаления тегов.
|
438 |
+
* исправлена ошибка с исчезновением записей больше 64k символов.
|
439 |
+
* немного изменен цикл выборки записей (стал быстрее).
|
440 |
+
* добавлен фильтр "yturbo_before_ads" - выполняется перед вставкой рекламы.
|
441 |
+
* добавлена реклама плагина-дополнения [WPCase: Turbo Ads](https://wpcase.ru/wpcase-turbo-ads/).
|
442 |
+
|
443 |
+
= 1.26 (20.03.2020) =
|
444 |
|
445 |
* изменен интерфейс удаления шорткодов из контента турбо-страниц.
|
446 |
* удалена опция вывода заголовков из SEO-плагинов (Яндекс стал требовать соответствия заголовков).
|
rss-for-yandex-turbo.php
CHANGED
@@ -3,17 +3,31 @@
|
|
3 |
Plugin Name: RSS for Yandex Turbo
|
4 |
Plugin URI: https://wordpress.org/plugins/rss-for-yandex-turbo/
|
5 |
Description: Создание RSS-ленты для сервиса Яндекс.Турбо.
|
6 |
-
Version: 1.
|
7 |
Author: Flector
|
8 |
Author URI: https://profiles.wordpress.org/flector#content-plugins
|
9 |
Text Domain: rss-for-yandex-turbo
|
10 |
*/
|
11 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
//проверка версии плагина (запуск функции установки новых опций) begin
|
13 |
function yturbo_check_version() {
|
14 |
$yturbo_options = get_option('yturbo_options');
|
15 |
if (!isset($yturbo_options['version'])){$yturbo_options['version']='1.00';update_option('yturbo_options',$yturbo_options);}
|
16 |
-
if ( $yturbo_options['version'] != '1.
|
17 |
yturbo_set_new_options();
|
18 |
}
|
19 |
}
|
@@ -128,7 +142,28 @@ function yturbo_set_new_options() {
|
|
128 |
$yturbo_options['ytdescription'] = esc_html(yturbo_remove_emoji(strip_tags($yturbo_options['ytdescription'])));
|
129 |
if (!isset($yturbo_options['required'])) {$yturbo_options['required']='1.00';}
|
130 |
|
131 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
132 |
update_option('yturbo_options', $yturbo_options);
|
133 |
}
|
134 |
//функция установки новых опций при обновлении плагина у пользователей end
|
@@ -136,7 +171,7 @@ function yturbo_set_new_options() {
|
|
136 |
//функция установки значений по умолчанию при активации плагина begin
|
137 |
function yturbo_init() {
|
138 |
$yturbo_options = array();
|
139 |
-
$yturbo_options['version'] = '1.
|
140 |
$yturbo_options['ytrssname'] = 'turbo';
|
141 |
$yturbo_options['yttitle'] = esc_html(yturbo_remove_emoji(strip_tags(get_bloginfo_rss('title'))));
|
142 |
$yturbo_options['ytlink'] = get_bloginfo_rss('url');
|
@@ -151,10 +186,10 @@ function yturbo_init() {
|
|
151 |
$yturbo_options['ytauthor'] = '';
|
152 |
$yturbo_options['ytthumbnail'] = 'enabled';
|
153 |
$yturbo_options['ytselectthumb'] = 'large';
|
154 |
-
$yturbo_options['ytexcludetags'] = '
|
155 |
-
$yturbo_options['ytexcludetagslist'] = '
|
156 |
-
$yturbo_options['ytexcludetags2'] = '
|
157 |
-
$yturbo_options['ytexcludetagslist2'] = '
|
158 |
$yturbo_options['ytexcludecontent'] = 'disabled';
|
159 |
$yturbo_options['ytexcludecontentlist'] = esc_textarea('<!--more-->\n<p></p>\n<p> </p>');
|
160 |
|
@@ -264,6 +299,10 @@ function yturbo_init() {
|
|
264 |
$yturbo_options['ytturbocolumn'] = 'enabled';
|
265 |
$yturbo_options['ytrelateddate'] = '12';
|
266 |
|
|
|
|
|
|
|
|
|
267 |
$yturbo_options['required']='1.00';
|
268 |
|
269 |
add_option('yturbo_options', $yturbo_options);
|
@@ -295,6 +334,7 @@ register_deactivation_hook( __FILE__, 'yturbo_on_deactivation' );
|
|
295 |
function yturbo_on_uninstall() {
|
296 |
if ( ! current_user_can('activate_plugins') ) return;
|
297 |
delete_option('yturbo_options');
|
|
|
298 |
}
|
299 |
register_uninstall_hook( __FILE__, 'yturbo_on_uninstall' );
|
300 |
//функция при удалении плагина end
|
@@ -316,18 +356,13 @@ add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ),'yturbo_actions
|
|
316 |
//функция загрузки скриптов и стилей плагина только в админке и только на странице настроек плагина begin
|
317 |
function yturbo_files_admin( $hook_suffix ) {
|
318 |
$purl = plugins_url('', __FILE__);
|
|
|
319 |
if ( $hook_suffix == 'settings_page_rss-for-yandex-turbo' ) {
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
wp_register_style('yturbo-animate', $purl . '/inc/animate.min.css');
|
326 |
-
wp_enqueue_style('yturbo-animate');
|
327 |
-
wp_register_script('yturbo-script', $purl . '/inc/yturbo-script.js', array(), '1.26');
|
328 |
-
wp_enqueue_script('yturbo-script');
|
329 |
-
wp_register_style('yturbo-css', $purl . '/inc/yturbo-css.css', array(), '1.26');
|
330 |
-
wp_enqueue_style('yturbo-css');
|
331 |
}
|
332 |
}
|
333 |
add_action( 'admin_enqueue_scripts', 'yturbo_files_admin' );
|
@@ -385,19 +420,18 @@ if ( ! wp_verify_nonce( $_POST['yturbo_nonce'], plugin_basename(__FILE__) ) || !
|
|
385 |
$yturbo_options['ytselectthumb'] = sanitize_text_field($_POST['ytselectthumb']);
|
386 |
|
387 |
if(isset($_POST['ytexcludetags'])){$yturbo_options['ytexcludetags'] = sanitize_text_field($_POST['ytexcludetags']);}else{$yturbo_options['ytexcludetags'] = 'disabled';}
|
388 |
-
$ytexcludetagslist = preg_replace('
|
389 |
-
$
|
390 |
-
$yturbo_options['ytexcludetagslist'] = esc_textarea($ytexcludetagslist);
|
391 |
|
392 |
if(isset($_POST['ytexcludetags2'])){$yturbo_options['ytexcludetags2'] = sanitize_text_field($_POST['ytexcludetags2']);}else{$yturbo_options['ytexcludetags2'] = 'disabled';}
|
393 |
-
$ytexcludetagslist2 = preg_replace('
|
394 |
-
$
|
395 |
-
$yturbo_options['ytexcludetagslist2'] = esc_textarea($ytexcludetagslist2);
|
396 |
|
397 |
if(isset($_POST['ytexcludecontent'])){$yturbo_options['ytexcludecontent'] = sanitize_text_field($_POST['ytexcludecontent']);}else{$yturbo_options['ytexcludecontent'] = 'disabled';}
|
398 |
-
$
|
|
|
399 |
|
400 |
-
if(isset($_POST['ytad1'])){$yturbo_options['ytad1'] = sanitize_text_field($_POST['ytad1']);}else{$yturbo_options['ytad1'] = 'disabled';}
|
401 |
$yturbo_options['ytad1set'] = sanitize_text_field($_POST['ytad1set']);
|
402 |
$yturbo_options['ytad1rsa'] = sanitize_text_field($_POST['ytad1rsa']);
|
403 |
$yturbo_options['ytadfox1'] = esc_html($_POST['ytadfox1']);
|
@@ -574,6 +608,11 @@ if ( ! wp_verify_nonce( $_POST['yturbo_nonce'], plugin_basename(__FILE__) ) || !
|
|
574 |
$yturbo_options['ytrelateddate'] = sanitize_text_field($_POST['ytrelateddate']);
|
575 |
}
|
576 |
|
|
|
|
|
|
|
|
|
|
|
577 |
update_option('yturbo_options', $yturbo_options);
|
578 |
|
579 |
yturbo_clear_transients();
|
@@ -592,7 +631,7 @@ if ( ! wp_verify_nonce( $_POST['yturbo_nonce'], plugin_basename(__FILE__) ) || !
|
|
592 |
<?php endif; ?>
|
593 |
|
594 |
<div class="wrap foptions">
|
595 |
-
<h2><?php _e('Настройки плагина “Яндекс.Турбо“', 'rss-for-yandex-turbo');
|
596 |
|
597 |
<div class="metabox-holder" id="poststuff">
|
598 |
<div class="meta-box-sortables">
|
@@ -605,7 +644,7 @@ if (closedonat == 'yes') {
|
|
605 |
document.getElementById('restore-hide-blocks').className = 'dashicons dashicons-admin-generic';
|
606 |
}
|
607 |
</script>
|
608 |
-
<h3 style="border-bottom: 1px solid #E1E1E1;background: #f7f7f7;"
|
609 |
<span id="close-donat" class="dashicons dashicons-no-alt" title="<?php _e('Скрыть блок', 'rss-for-yandex-turbo'); ?>"></span></h3>
|
610 |
<div class="inside" style="display: block;margin-right: 12px;">
|
611 |
<img src="<?php echo $purl . '/img/icon_coffee.png'; ?>" title="<?php _e('Купить мне чашку кофе :)', 'rss-for-yandex-turbo'); ?>" style=" margin: 5px; float:left;" />
|
@@ -685,7 +724,7 @@ if (closedonat == 'yes') {
|
|
685 |
<br /><small><?php _e('Язык статей RSS-ленты в стандарте <a target="_blank" href="https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%B4%D1%8B_%D1%8F%D0%B7%D1%8B%D0%BA%D0%BE%D0%B2">ISO 639-1</a> (Россия - <strong>ru</strong>, Украина - <strong>uk</strong> и т.д.).', 'rss-for-yandex-turbo'); ?> </small>
|
686 |
</td>
|
687 |
</tr>
|
688 |
-
|
689 |
<th><?php _e('Количество записей:', 'rss-for-yandex-turbo'); ?></th>
|
690 |
<td>
|
691 |
<input style="max-width: 74px;" name="ytnumber" type="number" min="1" max="999999" step="1" value="<?php echo $yturbo_options['ytnumber']; ?>" />
|
@@ -714,10 +753,50 @@ if (closedonat == 'yes') {
|
|
714 |
</small>
|
715 |
</td>
|
716 |
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
717 |
<tr class="trbordertop">
|
718 |
-
<th class="tdcheckbox"><?php _e('
|
719 |
<td>
|
720 |
-
<label for="ytremoveturbo"><input type="checkbox" value="enabled" name="ytremoveturbo" id="ytremoveturbo" <?php if ($yturbo_options['ytremoveturbo'] == 'enabled') echo 'checked="checked"'; ?> /><?php _e('
|
721 |
<br /><small><?php _e('Эта опция добавит в RSS-ленту атрибут <tt>turbo="false"</tt> к тегу <tt><item></tt> для всех записей.', 'rss-for-yandex-turbo'); ?> <br />
|
722 |
<?php _e('Это единственный способ заставить Яндекс отключить турбо-страницы для вашего сайта.', 'rss-for-yandex-turbo'); ?><br />
|
723 |
<?php _e('Простое удаление плагина не поможет - необходимо, чтобы бот Яндекса "съел" ленту с <tt>turbo="false"</tt>.', 'rss-for-yandex-turbo'); ?><br />
|
@@ -1478,9 +1557,10 @@ if (closedonat == 'yes') {
|
|
1478 |
<div class="xyztabs__content<?php if($yturbo_options['yttab']=='Реклама'){echo ' active';} ?>"><!-- begin tab -->
|
1479 |
|
1480 |
<?php if ( yturbo_check_ads() == true ) echo '<div style="display:none;">'; ?>
|
1481 |
-
<p><?php _e('Реклама, установленная в Яндекс.Вебмастере, распределяется равномерно по тексту страницы (примерно каждые 2-3 экрана).', 'rss-for-yandex-turbo'); ?><br />
|
1482 |
-
<?php _e('Если у вас большие по размеру контента
|
1483 |
-
<?php _e('В
|
|
|
1484 |
<?php _e('При проблемах с настройкой рекламной сети ADFOX ознакомьтесь со справочными материалами: <a target="_blank" href="https://sites.help.adfox.ru/page/225">статья</a>, <a target="_blank" href="https://webmaster.yandex.ru/blog/videourok-kak-razmeschat-reklamu-na-turbo-stranitsakh-cherez-adfox">видеоурок</a>.', 'rss-for-yandex-turbo'); ?><br />
|
1485 |
</p>
|
1486 |
|
@@ -1794,7 +1874,7 @@ if (closedonat == 'yes') {
|
|
1794 |
|
1795 |
<p><?php _e('В шаблоне можно использовать шорткоды (убедитесь, что их вывод не содержит скрипты или css-код).', 'rss-for-yandex-turbo'); ?><br />
|
1796 |
<?php _e('В плагин встроено несколько собственных шорткодов, полный их список вы можете посмотреть <a target="_blank" href="https://ru.wordpress.org/plugins/rss-for-yandex-turbo/#%D0%BA%D0%B0%D0%BA%D0%B8%D0%B5%20%D1%88%D0%BE%D1%80%D1%82%D0%BA%D0%BE%D0%B4%D1%8B%20%D0%BC%D0%BE%D0%B6%D0%BD%D0%BE%20%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D1%8C%20%D0%B2%20%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%B0%D1%85%3F">здесь</a>.', 'rss-for-yandex-turbo'); ?></p>
|
1797 |
-
<p> <?php _e('<strong>Внимание!</strong> Произвольные поля плагина <strong>Advanced Custom Fields</strong> необходимо обрабатывать <a target="_blank" href="https://ru.wordpress.org/plugins/rss-for-yandex-turbo/#%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D1%8B%20%D0%B8%20%D0%BF%D0%BB%D0%B0%D0%B3%D0%B8%D0%BD%20advanced%20custom%20fields"
|
1798 |
</p>
|
1799 |
|
1800 |
<table class="form-table">
|
@@ -1830,7 +1910,7 @@ if (closedonat == 'yes') {
|
|
1830 |
'toolbar1' => 'undo,redo,formatselect,bold,italic,underline,strikethrough,superscript,subscript,hr,blockquote,link,unlink,bullist,numlist,table,yablocks,',
|
1831 |
'toolbar2' => '',
|
1832 |
'toolbar3' => '',
|
1833 |
-
'content_css' => $purl . '/inc/editor.css?ver=
|
1834 |
),
|
1835 |
'quicktags' => array(
|
1836 |
'id' => $editor_id,
|
@@ -1885,27 +1965,37 @@ if (closedonat == 'yes') {
|
|
1885 |
$ytshortcodes = explode(",", $yturbo_options['ytexcludeshortcodeslist']);
|
1886 |
$ytshortcodes = array_diff($ytshortcodes, array(''));
|
1887 |
|
1888 |
-
|
|
|
|
|
1889 |
<label class="shortcodes" for="<?php echo $shortcode; ?>"><input type="checkbox" value="<?php echo $shortcode; ?>" name="shortcodes[]" id="<?php echo $shortcode; ?>" <?php if (in_array($shortcode, $ytshortcodes)) echo 'checked="checked"'; ?> />[<?php echo $shortcode; ?>]</label>
|
1890 |
<?php } ?>
|
1891 |
<small><?php _e('В списке находятся все зарегистрированные на сайте шорткоды, кроме системных.', 'rss-for-yandex-turbo'); ?><br />
|
1892 |
</small>
|
|
|
|
|
|
|
|
|
1893 |
</td>
|
1894 |
</tr>
|
1895 |
<tr class="ytexcludetagstr trbordertop">
|
1896 |
<th class="tdcheckbox"><?php _e('Фильтр тегов (без контента):', 'rss-for-yandex-turbo'); ?></th>
|
1897 |
<td>
|
1898 |
<label for="ytexcludetags"><input type="checkbox" value="enabled" name="ytexcludetags" id="ytexcludetags" <?php if ($yturbo_options['ytexcludetags'] == 'enabled') echo 'checked="checked"'; ?> /><?php _e('Удалить указанные html-теги', 'rss-for-yandex-turbo'); ?></label>
|
1899 |
-
<br /><small><?php _e('Из контента записей будут удалены все указанные html-теги (<strong
|
|
|
|
|
1900 |
</td>
|
1901 |
</tr>
|
1902 |
<tr class="ytexcludetagslisttr" <?php if ($yturbo_options['ytexcludetags'] == 'disabled') echo 'style="display:none;"'; ?>>
|
1903 |
-
<th><?php _e('Теги для удаления:', 'rss-for-yandex-turbo'); ?></th>
|
1904 |
-
<td>
|
1905 |
-
<
|
1906 |
-
<
|
1907 |
-
|
1908 |
-
|
|
|
|
|
1909 |
</small>
|
1910 |
</td>
|
1911 |
</tr>
|
@@ -1913,16 +2003,18 @@ if (closedonat == 'yes') {
|
|
1913 |
<th class="tdcheckbox"><?php _e('Фильтр тегов (с контентом):', 'rss-for-yandex-turbo'); ?></th>
|
1914 |
<td>
|
1915 |
<label for="ytexcludetags2"><input type="checkbox" value="enabled" name="ytexcludetags2" id="ytexcludetags2" <?php if ($yturbo_options['ytexcludetags2'] == 'enabled') echo 'checked="checked"'; ?> /><?php _e('Удалить указанные html-теги', 'rss-for-yandex-turbo'); ?></label>
|
1916 |
-
<br /><small><?php _e('Из контента записей будут удалены все указанные html-теги (<strong>включая
|
1917 |
</td>
|
1918 |
</tr>
|
1919 |
<tr class="ytexcludetagslist2tr" <?php if ($yturbo_options['ytexcludetags2'] == 'disabled') echo 'style="display:none;"'; ?>>
|
1920 |
-
<th><?php _e('Теги для удаления:', 'rss-for-yandex-turbo'); ?></th>
|
1921 |
-
<td>
|
1922 |
-
<
|
1923 |
-
<
|
1924 |
-
|
1925 |
-
|
|
|
|
|
1926 |
</small>
|
1927 |
</td>
|
1928 |
</tr>
|
@@ -1961,7 +2053,7 @@ if (closeabout == 'yes') {
|
|
1961 |
document.getElementById('restore-hide-blocks').className = 'dashicons dashicons-admin-generic';
|
1962 |
}
|
1963 |
</script>
|
1964 |
-
<h3 style="border-bottom: 1px solid #E1E1E1;background: #f7f7f7;"
|
1965 |
<span id="close-about" class="dashicons dashicons-no-alt" title="<?php _e('Скрыть блок', 'rss-for-yandex-turbo'); ?>"></span></h3>
|
1966 |
<div class="inside" style="padding-bottom:15px;display: block;">
|
1967 |
|
@@ -1977,7 +2069,7 @@ if (closeabout == 'yes') {
|
|
1977 |
<li><a target="_blank" href="https://ru.wordpress.org/plugins/today-yesterday-dates/">Today-Yesterday Dates</a> - <?php _e('относительные даты для записей за сегодня и вчера.', 'rss-for-yandex-turbo'); ?> </li>
|
1978 |
<li><a target="_blank" href="https://ru.wordpress.org/plugins/truncate-comments/">Truncate Comments</a> - <?php _e('плагин скрывает длинные комментарии js-скриптом (в стиле Яндекса или Амазона).', 'rss-for-yandex-turbo'); ?> </li>
|
1979 |
<li><a target="_blank" href="https://ru.wordpress.org/plugins/easy-yandex-share/">Easy Yandex Share</a> - <?php _e('продвинутый вывод блока “Яндекс.Поделиться”.', 'rss-for-yandex-turbo'); ?></li>
|
1980 |
-
<li><a target="_blank" href="https://wordpress.org/plugins/hide-my-dates/">Hide My Dates</a> - <?php _e('
|
1981 |
<li style="margin: 3px 0px 3px 35px;"><a target="_blank" href="https://ru.wordpress.org/plugins/html5-cumulus/">HTML5 Cumulus</a> <span class="new">new</span> - <?php _e('современная (HTML5) версия классического плагина “WP-Cumulus”.', 'rss-for-yandex-turbo'); ?></li>
|
1982 |
|
1983 |
</ul>
|
@@ -1988,6 +2080,7 @@ if (closeabout == 'yes') {
|
|
1988 |
</form>
|
1989 |
</div>
|
1990 |
</div>
|
|
|
1991 |
<?php
|
1992 |
}
|
1993 |
//функция вывода страницы настроек плагина end
|
@@ -2241,7 +2334,7 @@ tt{padding: 1px 5px 1px;margin: 0 1px;background: #eaeaea;background: rgba(0, 0,
|
|
2241 |
'toolbar1' => 'undo,redo,formatselect,bold,italic,underline,strikethrough,superscript,subscript,hr,blockquote,link,unlink,bullist,numlist,table,yablocks,',
|
2242 |
'toolbar2' => '',
|
2243 |
'toolbar3' => '',
|
2244 |
-
'content_css' => $purl . '/inc/editor.css?ver=
|
2245 |
),
|
2246 |
'quicktags' => array(
|
2247 |
'id' => 'customtemplate',
|
@@ -2324,9 +2417,9 @@ $ytad5rsa = $yturbo_options['ytad5rsa'];
|
|
2324 |
$ytadfox5 = html_entity_decode(stripcslashes($yturbo_options['ytadfox5']),ENT_QUOTES);
|
2325 |
|
2326 |
$ytexcludetags = $yturbo_options['ytexcludetags'];
|
2327 |
-
$ytexcludetagslist =
|
2328 |
$ytexcludetags2 = $yturbo_options['ytexcludetags2'];
|
2329 |
-
$ytexcludetagslist2 =
|
2330 |
$ytexcludecontent = $yturbo_options['ytexcludecontent'];
|
2331 |
$ytexcludecontentlist = html_entity_decode($yturbo_options['ytexcludecontentlist']);
|
2332 |
$tax_query = array();
|
@@ -2411,25 +2504,37 @@ if ($ytrazb == 'enabled' && $ytrazbnumber) {
|
|
2411 |
if (isset($_GET['paged'])) {
|
2412 |
$paged = $_GET['paged'];
|
2413 |
} else {
|
2414 |
-
$paged = 0;
|
2415 |
-
}
|
2416 |
-
$offset = $ytrazbnumber * ($paged - 1);
|
2417 |
-
if ($paged == 0) {
|
2418 |
$paged = 1;
|
2419 |
-
$offset = 0;
|
2420 |
}
|
2421 |
-
$
|
2422 |
-
if ($paged > $temp) {echo 'Не хватает записей для этой ленты, измените настройки плагина.'; return;}
|
2423 |
-
$perpage = $ytrazbnumber * $paged;
|
2424 |
} else {
|
2425 |
-
$
|
2426 |
$ytrazbnumber = $ytnumber;
|
2427 |
}
|
2428 |
-
if($
|
2429 |
-
|
2430 |
-
|
2431 |
-
|
2432 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2433 |
$query = new WP_Query( $args );
|
2434 |
|
2435 |
header('Content-Type: ' . feed_content_type('rss2') . '; charset=' . get_option('blog_charset'), true);
|
@@ -2453,7 +2558,7 @@ echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>'.PHP_EO
|
|
2453 |
<?php if ($ytmediascope) { ?><turbo:analytics id="<?php echo $ytmediascope; ?>" type="Mediascope"></turbo:analytics><?php echo PHP_EOL; ?><?php } ?>
|
2454 |
<?php do_action( 'yturbo_ads_header' ); echo yturbo_turbo_ads(); ?>
|
2455 |
<language><?php echo $ytlanguage; ?></language>
|
2456 |
-
<generator>RSS for Yandex Turbo
|
2457 |
<?php do_action( 'yturbo_generator' ); ?>
|
2458 |
<?php while($query->have_posts()) : $query->the_post(); ?>
|
2459 |
<?php $ytremove = get_post_meta(get_the_ID(), 'ytremove_meta_value', true); ?>
|
@@ -2665,7 +2770,8 @@ echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>'.PHP_EO
|
|
2665 |
<?php if ($yturbo_options['ytsearch'] != 'disabled' && $yturbo_options['ytsearchmesto'] == 'В начале записи') {echo yturbo_search_widget();} ?>
|
2666 |
<?php if ($yturbo_options['ytfeedback'] != 'disabled' && $yturbo_options['ytfeedbackselect'] == 'false' && $yturbo_options['ytfeedbackselectmesto'] == 'В начале записи') {echo yturbo_widget_feedback();} ?>
|
2667 |
<?php
|
2668 |
-
$
|
|
|
2669 |
if ( $temp != $content ) {
|
2670 |
echo $temp;
|
2671 |
} else {
|
@@ -2806,6 +2912,15 @@ function yturbo_the_content_feed() {
|
|
2806 |
|
2807 |
//функция удаления тегов вместе с их контентом begin
|
2808 |
function yturbo_strip_tags_with_content( $text, $tags = '', $invert = FALSE ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2809 |
preg_match_all( '/<(.+?)[\s]*\/?[\s]*>/si', trim( $tags ), $tags_array );
|
2810 |
$tags_array = array_unique( $tags_array[1] );
|
2811 |
|
@@ -2835,6 +2950,14 @@ function yturbo_strip_tags_with_content( $text, $tags = '', $invert = FALSE ) {
|
|
2835 |
//функция удаления тегов без их контента begin
|
2836 |
function yturbo_strip_tags_without_content( $text, $tags = '' ) {
|
2837 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2838 |
preg_match_all('/<(.+?)[\s]*\/?[\s]*>/si', trim($tags), $tags);
|
2839 |
$tags = array_unique($tags[1]);
|
2840 |
|
@@ -3031,7 +3154,7 @@ function yturbo_add_advert( $content ) {
|
|
3031 |
$ads = PHP_EOL.'<figure data-turbo-ad-id="second_ad_place"></figure>';
|
3032 |
}
|
3033 |
|
3034 |
-
if (mb_strlen($tempcontent) > (int)$ytrazmer) {
|
3035 |
$content = preg_replace('~[^^]{'. $num .'}.*?(?:\r?\n\r?\n|</p>|</figure>|</ul>|</pre>|</table>|</ol>|</blockquote>)~su', "\${0}$ads", trim( $content ), 1);
|
3036 |
}
|
3037 |
|
@@ -3216,7 +3339,7 @@ function yturbo_comments( $comment, $args, $depth ) {
|
|
3216 |
<?php if ($args['has_children'] && $ytcommentsdrevo=='enabled') { ?><?php echo '<div data-block="comments">'; ?><?php }
|
3217 |
}
|
3218 |
|
3219 |
-
function yturbo_comments_end($comment, $args, $depth) {
|
3220 |
$yturbo_options = get_option('yturbo_options');
|
3221 |
$ytcommentsdrevo = $yturbo_options['ytcommentsdrevo'];
|
3222 |
?>
|
@@ -3505,11 +3628,9 @@ function yturbo_toc( $content ) {
|
|
3505 |
if ( ! in_array( get_post_type( get_the_ID() ), $types ) )
|
3506 |
return $content;
|
3507 |
|
3508 |
-
//подключение файла с классом
|
3509 |
-
|
3510 |
-
|
3511 |
-
}
|
3512 |
-
//подключение файла с классом Kama_Contents end
|
3513 |
|
3514 |
$selectors = array();
|
3515 |
if ($yturbo_options['yttoch1']=='enabled'){array_push($selectors, 'h1');}
|
@@ -3529,19 +3650,11 @@ function yturbo_toc( $content ) {
|
|
3529 |
'selectors' => $selectors,
|
3530 |
);
|
3531 |
|
3532 |
-
$contents =
|
3533 |
|
3534 |
$contents = str_replace("\n", '', $contents);
|
3535 |
$contents = trim(preg_replace('/\t+/', '', $contents));
|
3536 |
$contents = wpautop($contents);
|
3537 |
-
$contents = str_replace('<div class="kc__wrap" ><span style="display:block;" class="kc-title kc__title" id="kcmenu">', '<div><h3>', $contents);
|
3538 |
-
$contents = str_replace('</span></p>', '</h3>', $contents);
|
3539 |
-
$contents = str_replace(' class="contents"', '', $contents);
|
3540 |
-
$contents = str_replace(' class="top"', '', $contents);
|
3541 |
-
$contents = str_replace(' rel="nofollow"', '', $contents);
|
3542 |
-
$contents = str_replace('<ul>', '<ol>', $contents);
|
3543 |
-
$contents = str_replace('<ul id="kcmenu">', '<ol>', $contents);
|
3544 |
-
$contents = str_replace('</ul>', '</ol>', $contents);
|
3545 |
|
3546 |
if ( $yturbo_options['yttocmesto'] == 'В начале записи' ) {
|
3547 |
return PHP_EOL . $contents . $content;
|
@@ -3623,9 +3736,10 @@ function yturbo_empty_title( $title ) {
|
|
3623 |
|
3624 |
//добавляем плагины в визуальный редактор begin
|
3625 |
function yturbo_add_plugins_tinymce( $plugins ) {
|
|
|
3626 |
$purl = plugins_url('', __FILE__);
|
3627 |
-
$plugins['yablocks'] = $purl . '/inc/yablocks.js?ver=
|
3628 |
-
$plugins['table'] = $purl . '/inc/table.js?ver=
|
3629 |
return $plugins;
|
3630 |
}
|
3631 |
add_filter( 'mce_external_plugins', 'yturbo_add_plugins_tinymce' );
|
@@ -3789,4 +3903,109 @@ function yturbo_hide_custom_fields( $protected, $meta_key ){
|
|
3789 |
return $protected;
|
3790 |
}
|
3791 |
add_filter( 'is_protected_meta', 'yturbo_hide_custom_fields', 10, 2 );
|
3792 |
-
//скрываем произвольные поля плагина end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
Plugin Name: RSS for Yandex Turbo
|
4 |
Plugin URI: https://wordpress.org/plugins/rss-for-yandex-turbo/
|
5 |
Description: Создание RSS-ленты для сервиса Яндекс.Турбо.
|
6 |
+
Version: 1.27
|
7 |
Author: Flector
|
8 |
Author URI: https://profiles.wordpress.org/flector#content-plugins
|
9 |
Text Domain: rss-for-yandex-turbo
|
10 |
*/
|
11 |
|
12 |
+
//вывод admin notice с рекламкой (для админов) begin
|
13 |
+
require_once plugin_dir_path( __FILE__ ) . 'inc/AdminNotice.php';
|
14 |
+
use \YTurboAdminNotices\AdminNotice;
|
15 |
+
function yturbo_add_notice_ads() {
|
16 |
+
AdminNotice::create('yturbo-ads1')
|
17 |
+
->requiredCap('administrator')
|
18 |
+
->persistentlyDismissible(AdminNotice::DISMISS_PER_USER)
|
19 |
+
->success()
|
20 |
+
->rawHtml(__('<p>Для плагина <strong>RSS for Yandex Turbo</strong> появилось премиум-дополнение <strong><a target="_blank" href="https://wpcase.ru/wpcase-turbo-ads/">WPCase: Turbo Ads</a></strong>, которое позволит <br />вам добавить на турбо-страницы неограниченное количество рекламных блоков в нужных вам местах.</p>', 'rss-for-yandex-turbo'))
|
21 |
+
->show();
|
22 |
+
}
|
23 |
+
add_action( 'admin_notices', 'yturbo_add_notice_ads' );
|
24 |
+
//вывод admin notice с рекламкой (для админов) end
|
25 |
+
|
26 |
//проверка версии плагина (запуск функции установки новых опций) begin
|
27 |
function yturbo_check_version() {
|
28 |
$yturbo_options = get_option('yturbo_options');
|
29 |
if (!isset($yturbo_options['version'])){$yturbo_options['version']='1.00';update_option('yturbo_options',$yturbo_options);}
|
30 |
+
if ( $yturbo_options['version'] != '1.27' ) {
|
31 |
yturbo_set_new_options();
|
32 |
}
|
33 |
}
|
142 |
$yturbo_options['ytdescription'] = esc_html(yturbo_remove_emoji(strip_tags($yturbo_options['ytdescription'])));
|
143 |
if (!isset($yturbo_options['required'])) {$yturbo_options['required']='1.00';}
|
144 |
|
145 |
+
// новый формат хранения удаляемых тегов begin
|
146 |
+
$yturbo_options['ytexcludetagslist'] = preg_replace('/[^A-Za-z0-9,]/', '', html_entity_decode($yturbo_options['ytexcludetagslist']));
|
147 |
+
$yturbo_options['ytexcludetagslist'] = mb_strtolower($yturbo_options['ytexcludetagslist']);
|
148 |
+
$a = explode(",", $yturbo_options['ytexcludetagslist'] );
|
149 |
+
$a = array_diff($a, array(''));
|
150 |
+
$yturbo_options['ytexcludetagslist'] = implode(",", $a );
|
151 |
+
// новый формат хранения удаляемых тегов end
|
152 |
+
|
153 |
+
// новый формат хранения удаляемых тегов begin
|
154 |
+
$yturbo_options['ytexcludetagslist2'] = preg_replace('/[^A-Za-z0-9,]/', '', html_entity_decode($yturbo_options['ytexcludetagslist2']));
|
155 |
+
$yturbo_options['ytexcludetagslist2'] = mb_strtolower($yturbo_options['ytexcludetagslist2']);
|
156 |
+
$a = explode(",", $yturbo_options['ytexcludetagslist2'] );
|
157 |
+
$a = array_diff($a, array(''));
|
158 |
+
$yturbo_options['ytexcludetagslist2'] = implode(",", $a );
|
159 |
+
// новый формат хранения удаляемых тегов end
|
160 |
+
|
161 |
+
if (!isset($yturbo_options['ytexcludeurls'])) {$yturbo_options['ytexcludeurls']='disabled';}
|
162 |
+
if (!isset($yturbo_options['ytexcludeurlslist'])) {$yturbo_options['ytexcludeurlslist']='';}
|
163 |
+
if (!isset($yturbo_options['ytdeltracking'])) {$yturbo_options['ytdeltracking']='disabled';}
|
164 |
+
|
165 |
+
|
166 |
+
$yturbo_options['version'] = '1.27';
|
167 |
update_option('yturbo_options', $yturbo_options);
|
168 |
}
|
169 |
//функция установки новых опций при обновлении плагина у пользователей end
|
171 |
//функция установки значений по умолчанию при активации плагина begin
|
172 |
function yturbo_init() {
|
173 |
$yturbo_options = array();
|
174 |
+
$yturbo_options['version'] = '1.27';
|
175 |
$yturbo_options['ytrssname'] = 'turbo';
|
176 |
$yturbo_options['yttitle'] = esc_html(yturbo_remove_emoji(strip_tags(get_bloginfo_rss('title'))));
|
177 |
$yturbo_options['ytlink'] = get_bloginfo_rss('url');
|
186 |
$yturbo_options['ytauthor'] = '';
|
187 |
$yturbo_options['ytthumbnail'] = 'enabled';
|
188 |
$yturbo_options['ytselectthumb'] = 'large';
|
189 |
+
$yturbo_options['ytexcludetags'] = 'enabled';
|
190 |
+
$yturbo_options['ytexcludetagslist'] = 'span';
|
191 |
+
$yturbo_options['ytexcludetags2'] = 'enabled';
|
192 |
+
$yturbo_options['ytexcludetagslist2'] = 'script,style';
|
193 |
$yturbo_options['ytexcludecontent'] = 'disabled';
|
194 |
$yturbo_options['ytexcludecontentlist'] = esc_textarea('<!--more-->\n<p></p>\n<p> </p>');
|
195 |
|
299 |
$yturbo_options['ytturbocolumn'] = 'enabled';
|
300 |
$yturbo_options['ytrelateddate'] = '12';
|
301 |
|
302 |
+
$yturbo_options['ytexcludeurls'] = 'disabled';
|
303 |
+
$yturbo_options['ytexcludeurlslist'] = '';
|
304 |
+
$yturbo_options['ytdeltracking'] = 'disabled';
|
305 |
+
|
306 |
$yturbo_options['required']='1.00';
|
307 |
|
308 |
add_option('yturbo_options', $yturbo_options);
|
334 |
function yturbo_on_uninstall() {
|
335 |
if ( ! current_user_can('activate_plugins') ) return;
|
336 |
delete_option('yturbo_options');
|
337 |
+
AdminNotice::cleanUpDatabase('yturbo-');
|
338 |
}
|
339 |
register_uninstall_hook( __FILE__, 'yturbo_on_uninstall' );
|
340 |
//функция при удалении плагина end
|
356 |
//функция загрузки скриптов и стилей плагина только в админке и только на странице настроек плагина begin
|
357 |
function yturbo_files_admin( $hook_suffix ) {
|
358 |
$purl = plugins_url('', __FILE__);
|
359 |
+
$yturbo_options = get_option('yturbo_options');
|
360 |
if ( $hook_suffix == 'settings_page_rss-for-yandex-turbo' ) {
|
361 |
+
wp_enqueue_script('jquery');
|
362 |
+
wp_enqueue_script('yturbo-tagify-js', $purl . '/inc/tagify.js', array(), $yturbo_options['version']);
|
363 |
+
wp_enqueue_style('yturbo-tagify-css', $purl . '/inc/tagify.css', array(), $yturbo_options['version']);
|
364 |
+
wp_enqueue_script('yturbo-script', $purl . '/inc/yturbo-script.js', array(), $yturbo_options['version']);
|
365 |
+
wp_enqueue_style('yturbo-css', $purl . '/inc/yturbo-css.css', array(), $yturbo_options['version']);
|
|
|
|
|
|
|
|
|
|
|
|
|
366 |
}
|
367 |
}
|
368 |
add_action( 'admin_enqueue_scripts', 'yturbo_files_admin' );
|
420 |
$yturbo_options['ytselectthumb'] = sanitize_text_field($_POST['ytselectthumb']);
|
421 |
|
422 |
if(isset($_POST['ytexcludetags'])){$yturbo_options['ytexcludetags'] = sanitize_text_field($_POST['ytexcludetags']);}else{$yturbo_options['ytexcludetags'] = 'disabled';}
|
423 |
+
$ytexcludetagslist = preg_replace('/[^A-Za-z0-9,]/', '', sanitize_text_field($_POST['ytexcludetagslist']));
|
424 |
+
$yturbo_options['ytexcludetagslist'] = $ytexcludetagslist;
|
|
|
425 |
|
426 |
if(isset($_POST['ytexcludetags2'])){$yturbo_options['ytexcludetags2'] = sanitize_text_field($_POST['ytexcludetags2']);}else{$yturbo_options['ytexcludetags2'] = 'disabled';}
|
427 |
+
$ytexcludetagslist2 = preg_replace('/[^A-Za-z0-9,]/', '', sanitize_text_field($_POST['ytexcludetagslist2']));
|
428 |
+
$yturbo_options['ytexcludetagslist2'] = $ytexcludetagslist2;
|
|
|
429 |
|
430 |
if(isset($_POST['ytexcludecontent'])){$yturbo_options['ytexcludecontent'] = sanitize_text_field($_POST['ytexcludecontent']);}else{$yturbo_options['ytexcludecontent'] = 'disabled';}
|
431 |
+
$lines = array_filter(explode("\n", trim(esc_textarea($_POST['ytexcludecontentlist']))));
|
432 |
+
$yturbo_options['ytexcludecontentlist'] = implode("\n", $lines);
|
433 |
|
434 |
+
if(isset($_POST['ytad1'])){$yturbo_options['ytad1'] = sanitize_text_field($_POST['ytad1']);}else{$yturbo_options['ytad1'] = 'disabled';}
|
435 |
$yturbo_options['ytad1set'] = sanitize_text_field($_POST['ytad1set']);
|
436 |
$yturbo_options['ytad1rsa'] = sanitize_text_field($_POST['ytad1rsa']);
|
437 |
$yturbo_options['ytadfox1'] = esc_html($_POST['ytadfox1']);
|
608 |
$yturbo_options['ytrelateddate'] = sanitize_text_field($_POST['ytrelateddate']);
|
609 |
}
|
610 |
|
611 |
+
if(isset($_POST['ytexcludeurls'])){$yturbo_options['ytexcludeurls'] = sanitize_text_field($_POST['ytexcludeurls']);}else{$yturbo_options['ytexcludeurls'] = 'disabled';}
|
612 |
+
$lines = array_filter(explode("\n", trim(esc_textarea($_POST['ytexcludeurlslist']))));
|
613 |
+
$yturbo_options['ytexcludeurlslist'] = implode("\n", $lines);
|
614 |
+
if(isset($_POST['ytdeltracking'])){$yturbo_options['ytdeltracking'] = sanitize_text_field($_POST['ytdeltracking']);}else{$yturbo_options['ytdeltracking'] = 'disabled';}
|
615 |
+
|
616 |
update_option('yturbo_options', $yturbo_options);
|
617 |
|
618 |
yturbo_clear_transients();
|
631 |
<?php endif; ?>
|
632 |
|
633 |
<div class="wrap foptions">
|
634 |
+
<h2><?php _e('Настройки плагина “Яндекс.Турбо“', 'rss-for-yandex-turbo'); ?> <span id="current-version">v<?php echo $yturbo_options['version']; ?></span><span id="restore-hide-blocks" class="dashicons dashicons-admin-generic hide" title="<?php _e('Восстановить скрытые блоки', 'rss-for-yandex-turbo'); ?>"></span></h2>
|
635 |
|
636 |
<div class="metabox-holder" id="poststuff">
|
637 |
<div class="meta-box-sortables">
|
644 |
document.getElementById('restore-hide-blocks').className = 'dashicons dashicons-admin-generic';
|
645 |
}
|
646 |
</script>
|
647 |
+
<h3 style="border-bottom: 1px solid #E1E1E1;background: #f7f7f7;"><?php _e('Вам нравится этот плагин ?', 'rss-for-yandex-turbo'); ?>
|
648 |
<span id="close-donat" class="dashicons dashicons-no-alt" title="<?php _e('Скрыть блок', 'rss-for-yandex-turbo'); ?>"></span></h3>
|
649 |
<div class="inside" style="display: block;margin-right: 12px;">
|
650 |
<img src="<?php echo $purl . '/img/icon_coffee.png'; ?>" title="<?php _e('Купить мне чашку кофе :)', 'rss-for-yandex-turbo'); ?>" style=" margin: 5px; float:left;" />
|
724 |
<br /><small><?php _e('Язык статей RSS-ленты в стандарте <a target="_blank" href="https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%B4%D1%8B_%D1%8F%D0%B7%D1%8B%D0%BA%D0%BE%D0%B2">ISO 639-1</a> (Россия - <strong>ru</strong>, Украина - <strong>uk</strong> и т.д.).', 'rss-for-yandex-turbo'); ?> </small>
|
725 |
</td>
|
726 |
</tr>
|
727 |
+
<tr class="trbordertop">
|
728 |
<th><?php _e('Количество записей:', 'rss-for-yandex-turbo'); ?></th>
|
729 |
<td>
|
730 |
<input style="max-width: 74px;" name="ytnumber" type="number" min="1" max="999999" step="1" value="<?php echo $yturbo_options['ytnumber']; ?>" />
|
753 |
</small>
|
754 |
</td>
|
755 |
</tr>
|
756 |
+
<tr class="ytexcludeurlstr trbordertop">
|
757 |
+
<th class="tdcheckbox"><?php _e('Выборочное отключение:', 'rss-for-yandex-turbo'); ?></th>
|
758 |
+
<td>
|
759 |
+
<label for="ytexcludeurls"><input type="checkbox" value="enabled" name="ytexcludeurls" id="ytexcludeurls" <?php if ($yturbo_options['ytexcludeurls'] == 'enabled') echo 'checked="checked"'; ?> /><?php _e('Удалить указанные турбо-страницы', 'rss-for-yandex-turbo'); ?></label>
|
760 |
+
<br /><small><?php _e('Если вы полностью удалили запись на сайте, то отключить ее турбо-страницу обычным способом не получится.', 'rss-for-yandex-turbo'); ?><br />
|
761 |
+
<?php _e('Эта опция позволит сформировать отдельную RSS-ленту с записями, которые Яндекс должен удалить.', 'rss-for-yandex-turbo'); ?><br />
|
762 |
+
</small>
|
763 |
+
</td>
|
764 |
+
</tr>
|
765 |
+
<tr class="ytexcludeurlslisttr" <?php if ($yturbo_options['ytexcludeurls'] == 'disabled') echo 'style="display:none;"'; ?>>
|
766 |
+
<th class="tdcheckbox"><?php _e('URL "мусорной" ленты:', 'rss-for-yandex-turbo'); ?></th>
|
767 |
+
<td>
|
768 |
+
<?php
|
769 |
+
if ( get_option('permalink_structure') ) {
|
770 |
+
echo '<a target="_blank" href="'.get_bloginfo("url").'/feed/'.$yturbo_options['ytrssname'].'/?lenta=trash'.'">'.get_bloginfo("url").'/feed/'.$yturbo_options['ytrssname'].'/?lenta=trash'.'</a>';
|
771 |
+
} else {
|
772 |
+
echo '<a target="_blank" href="'.get_bloginfo("url").'/?feed='.$yturbo_options['ytrssname'].'&lenta=trash">'.get_bloginfo("url").'/?feed='.$yturbo_options['ytrssname'].'&lenta=trash</a>';
|
773 |
+
}
|
774 |
+
?>
|
775 |
+
<br /><small><?php _e('Добавьте эту RSS-ленту в Яндекс.Вебмастер как обычную ленту.', 'rss-for-yandex-turbo'); ?><br />
|
776 |
+
</small>
|
777 |
+
</td>
|
778 |
+
</tr>
|
779 |
+
<tr class="ytexcludeurlslisttr" <?php if ($yturbo_options['ytexcludeurls'] == 'disabled') echo 'style="display:none;"'; ?>>
|
780 |
+
<th class="tdcheckbox"><?php _e('Отслеживание:', 'rss-for-yandex-turbo'); ?></th>
|
781 |
+
<td>
|
782 |
+
<label for="ytdeltracking"><input type="checkbox" value="enabled" name="ytdeltracking" id="ytdeltracking" <?php if ($yturbo_options['ytdeltracking'] == 'enabled') echo 'checked="checked"'; ?> /><?php _e('Следить за удаляемыми записями', 'rss-for-yandex-turbo'); ?></label>
|
783 |
+
<br /><small><?php _e('Плагин будет автоматически добавлять в список ниже ссылки на удаленные записи.', 'rss-for-yandex-turbo'); ?><br />
|
784 |
+
|
785 |
+
</small>
|
786 |
+
</td>
|
787 |
+
</tr>
|
788 |
+
<tr class="ytexcludeurlslisttr" <?php if ($yturbo_options['ytexcludeurls'] == 'disabled') echo 'style="display:none;"'; ?>>
|
789 |
+
<th><?php _e('Список удаляемых ссылок:', 'rss-for-yandex-turbo'); ?></th>
|
790 |
+
<td>
|
791 |
+
<textarea rows="8" cols="70" name="ytexcludeurlslist" id="ytexcludeurlslist"><?php echo stripcslashes($yturbo_options['ytexcludeurlslist']); ?></textarea>
|
792 |
+
<br /><small><?php _e('Каждая новая ссылка для удаления должна начинаться с новой строки.', 'rss-for-yandex-turbo'); ?><br />
|
793 |
+
</small>
|
794 |
+
</td>
|
795 |
+
</tr>
|
796 |
<tr class="trbordertop">
|
797 |
+
<th class="tdcheckbox"><?php _e('Полное отключение:', 'rss-for-yandex-turbo'); ?></th>
|
798 |
<td>
|
799 |
+
<label for="ytremoveturbo"><input type="checkbox" value="enabled" name="ytremoveturbo" id="ytremoveturbo" <?php if ($yturbo_options['ytremoveturbo'] == 'enabled') echo 'checked="checked"'; ?> /><?php _e('Удалить все турбо-страницы', 'rss-for-yandex-turbo'); ?></label>
|
800 |
<br /><small><?php _e('Эта опция добавит в RSS-ленту атрибут <tt>turbo="false"</tt> к тегу <tt><item></tt> для всех записей.', 'rss-for-yandex-turbo'); ?> <br />
|
801 |
<?php _e('Это единственный способ заставить Яндекс отключить турбо-страницы для вашего сайта.', 'rss-for-yandex-turbo'); ?><br />
|
802 |
<?php _e('Простое удаление плагина не поможет - необходимо, чтобы бот Яндекса "съел" ленту с <tt>turbo="false"</tt>.', 'rss-for-yandex-turbo'); ?><br />
|
1557 |
<div class="xyztabs__content<?php if($yturbo_options['yttab']=='Реклама'){echo ' active';} ?>"><!-- begin tab -->
|
1558 |
|
1559 |
<?php if ( yturbo_check_ads() == true ) echo '<div style="display:none;">'; ?>
|
1560 |
+
<p><?php _e('Реклама, установленная в Яндекс.Вебмастере, распределяется равномерно по тексту страницы (примерно каждые 2-3 экрана с общим ограничением в 10 рекламных блоков).', 'rss-for-yandex-turbo'); ?><br />
|
1561 |
+
<?php _e('Если у вас большие по размеру контента статьи или вас не устраивает частота, с которой Яндекс расставляет рекламу, то рекомендую попробовать плагин <a target="_blank" href="https://wpcase.ru/wpcase-turbo-ads/">WPCase: Turbo Ads</a>.', 'rss-for-yandex-turbo'); ?><br />
|
1562 |
+
<?php _e('В нем вы можете установить сколько угодно рекламных блоков и с той частотой, которая вам нужна (гибкие настройки вставки рекламных блоков).', 'rss-for-yandex-turbo'); ?><br /><br />
|
1563 |
+
<?php _e('Этот же плагин позволяет разместить максимально 5 рекламных блоков (только 3 в контенте статьи).', 'rss-for-yandex-turbo'); ?><br />
|
1564 |
<?php _e('При проблемах с настройкой рекламной сети ADFOX ознакомьтесь со справочными материалами: <a target="_blank" href="https://sites.help.adfox.ru/page/225">статья</a>, <a target="_blank" href="https://webmaster.yandex.ru/blog/videourok-kak-razmeschat-reklamu-na-turbo-stranitsakh-cherez-adfox">видеоурок</a>.', 'rss-for-yandex-turbo'); ?><br />
|
1565 |
</p>
|
1566 |
|
1874 |
|
1875 |
<p><?php _e('В шаблоне можно использовать шорткоды (убедитесь, что их вывод не содержит скрипты или css-код).', 'rss-for-yandex-turbo'); ?><br />
|
1876 |
<?php _e('В плагин встроено несколько собственных шорткодов, полный их список вы можете посмотреть <a target="_blank" href="https://ru.wordpress.org/plugins/rss-for-yandex-turbo/#%D0%BA%D0%B0%D0%BA%D0%B8%D0%B5%20%D1%88%D0%BE%D1%80%D1%82%D0%BA%D0%BE%D0%B4%D1%8B%20%D0%BC%D0%BE%D0%B6%D0%BD%D0%BE%20%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D1%8C%20%D0%B2%20%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%B0%D1%85%3F">здесь</a>.', 'rss-for-yandex-turbo'); ?></p>
|
1877 |
+
<p> <?php _e('<strong>Внимание!</strong> Произвольные поля плагина <strong>Advanced Custom Fields</strong> необходимо обрабатывать <a target="_blank" href="https://ru.wordpress.org/plugins/rss-for-yandex-turbo/#%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D1%8B%20%D0%B8%20%D0%BF%D0%BB%D0%B0%D0%B3%D0%B8%D0%BD%20advanced%20custom%20fields">фильтром</a>.', 'rss-for-yandex-turbo'); ?><br /><br />
|
1878 |
</p>
|
1879 |
|
1880 |
<table class="form-table">
|
1910 |
'toolbar1' => 'undo,redo,formatselect,bold,italic,underline,strikethrough,superscript,subscript,hr,blockquote,link,unlink,bullist,numlist,table,yablocks,',
|
1911 |
'toolbar2' => '',
|
1912 |
'toolbar3' => '',
|
1913 |
+
'content_css' => $purl . '/inc/editor.css?ver=' . $yturbo_options['version'],
|
1914 |
),
|
1915 |
'quicktags' => array(
|
1916 |
'id' => $editor_id,
|
1965 |
$ytshortcodes = explode(",", $yturbo_options['ytexcludeshortcodeslist']);
|
1966 |
$ytshortcodes = array_diff($ytshortcodes, array(''));
|
1967 |
|
1968 |
+
if ( ! empty($result) ) :
|
1969 |
+
|
1970 |
+
foreach ( $result as $shortcode ) { ?>
|
1971 |
<label class="shortcodes" for="<?php echo $shortcode; ?>"><input type="checkbox" value="<?php echo $shortcode; ?>" name="shortcodes[]" id="<?php echo $shortcode; ?>" <?php if (in_array($shortcode, $ytshortcodes)) echo 'checked="checked"'; ?> />[<?php echo $shortcode; ?>]</label>
|
1972 |
<?php } ?>
|
1973 |
<small><?php _e('В списке находятся все зарегистрированные на сайте шорткоды, кроме системных.', 'rss-for-yandex-turbo'); ?><br />
|
1974 |
</small>
|
1975 |
+
|
1976 |
+
<?php else : ?>
|
1977 |
+
<p style="margin-top: -5px;"><?php _e('Сторонних шорткодов не найдено.', 'rss-for-yandex-turbo'); ?></p>
|
1978 |
+
<?php endif; ?>
|
1979 |
</td>
|
1980 |
</tr>
|
1981 |
<tr class="ytexcludetagstr trbordertop">
|
1982 |
<th class="tdcheckbox"><?php _e('Фильтр тегов (без контента):', 'rss-for-yandex-turbo'); ?></th>
|
1983 |
<td>
|
1984 |
<label for="ytexcludetags"><input type="checkbox" value="enabled" name="ytexcludetags" id="ytexcludetags" <?php if ($yturbo_options['ytexcludetags'] == 'enabled') echo 'checked="checked"'; ?> /><?php _e('Удалить указанные html-теги', 'rss-for-yandex-turbo'); ?></label>
|
1985 |
+
<br /><small><?php _e('Из контента записей будут удалены все указанные html-теги (<strong>без контента этих тегов</strong>).', 'rss-for-yandex-turbo'); ?></small>
|
1986 |
+
|
1987 |
+
|
1988 |
</td>
|
1989 |
</tr>
|
1990 |
<tr class="ytexcludetagslisttr" <?php if ($yturbo_options['ytexcludetags'] == 'disabled') echo 'style="display:none;"'; ?>>
|
1991 |
+
<th style="padding-top: 5px;"><?php _e('Теги для удаления:', 'rss-for-yandex-turbo'); ?></th>
|
1992 |
+
<td style="padding-top: 5px;">
|
1993 |
+
<input style="display:none;" name="ytexcludetagslist-input" class="ytexcludetagslist-input" placeholder="" value="<?php echo stripslashes($yturbo_options['ytexcludetagslist']); ?>" />
|
1994 |
+
<input type="hidden" id="tags-list" value="<?php echo yturbo_tags_list(); ?>" />
|
1995 |
+
<input type="hidden" name="ytexcludetagslist" id="ytexcludetagslist" value="<?php echo stripslashes($yturbo_options['ytexcludetagslist']); ?>" />
|
1996 |
+
<small><?php _e('Список удаляемых html-тегов. Начните набирать нужный тег для подсказки.', 'rss-for-yandex-turbo'); ?><br />
|
1997 |
+
<?php _e('Самозакрывающиеся теги вроде <tt><br /></tt> этим фильтром удалить нельзя.', 'rss-for-yandex-turbo'); ?><br />
|
1998 |
+
<?php _e('Список возможных для удаления тегов можно <a target="_blank" href="https://ru.wordpress.org/plugins/rss-for-yandex-turbo/#%D0%BA%D0%B0%D0%BA%20%D0%BF%D0%B5%D1%80%D0%B5%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B8%D1%82%D1%8C%20%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA%20%D1%82%D0%B5%D0%B3%D0%BE%D0%B2%20%D0%B4%D0%BB%D1%8F%20%D1%83%D0%B4%D0%B0%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F%3F">переопределить</a>.', 'rss-for-yandex-turbo'); ?><br />
|
1999 |
</small>
|
2000 |
</td>
|
2001 |
</tr>
|
2003 |
<th class="tdcheckbox"><?php _e('Фильтр тегов (с контентом):', 'rss-for-yandex-turbo'); ?></th>
|
2004 |
<td>
|
2005 |
<label for="ytexcludetags2"><input type="checkbox" value="enabled" name="ytexcludetags2" id="ytexcludetags2" <?php if ($yturbo_options['ytexcludetags2'] == 'enabled') echo 'checked="checked"'; ?> /><?php _e('Удалить указанные html-теги', 'rss-for-yandex-turbo'); ?></label>
|
2006 |
+
<br /><small><?php _e('Из контента записей будут удалены все указанные html-теги (<strong>включая контент этих тегов</strong>).', 'rss-for-yandex-turbo'); ?></small>
|
2007 |
</td>
|
2008 |
</tr>
|
2009 |
<tr class="ytexcludetagslist2tr" <?php if ($yturbo_options['ytexcludetags2'] == 'disabled') echo 'style="display:none;"'; ?>>
|
2010 |
+
<th style="padding-top: 5px;"><?php _e('Теги для удаления:', 'rss-for-yandex-turbo'); ?></th>
|
2011 |
+
<td style="padding-top: 5px;">
|
2012 |
+
<input style="display:none;" name="ytexcludetagslist-input2" class="ytexcludetagslist-input2" placeholder="" value="<?php echo stripslashes($yturbo_options['ytexcludetagslist2']); ?>" />
|
2013 |
+
<input type="hidden" id="tags-list2" value="<?php echo yturbo_tags_list(); ?>" />
|
2014 |
+
<input type="hidden" name="ytexcludetagslist2" id="ytexcludetagslist2" value="<?php echo stripslashes($yturbo_options['ytexcludetagslist2']); ?>" />
|
2015 |
+
<small><?php _e('Список удаляемых html-тегов. Начните набирать нужный тег для подсказки.', 'rss-for-yandex-turbo'); ?><br />
|
2016 |
+
<?php _e('Самозакрывающиеся теги вроде <tt><br /></tt> этим фильтром удалить нельзя.', 'rss-for-yandex-turbo'); ?> <br />
|
2017 |
+
<?php _e('Список возможных для удаления тегов можно <a target="_blank" href="https://ru.wordpress.org/plugins/rss-for-yandex-turbo/#%D0%BA%D0%B0%D0%BA%20%D0%BF%D0%B5%D1%80%D0%B5%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B8%D1%82%D1%8C%20%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA%20%D1%82%D0%B5%D0%B3%D0%BE%D0%B2%20%D0%B4%D0%BB%D1%8F%20%D1%83%D0%B4%D0%B0%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F%3F">переопределить</a>.', 'rss-for-yandex-turbo'); ?><br />
|
2018 |
</small>
|
2019 |
</td>
|
2020 |
</tr>
|
2053 |
document.getElementById('restore-hide-blocks').className = 'dashicons dashicons-admin-generic';
|
2054 |
}
|
2055 |
</script>
|
2056 |
+
<h3 style="border-bottom: 1px solid #E1E1E1;background: #f7f7f7;"><?php _e('О плагине', 'rss-for-yandex-turbo'); ?>
|
2057 |
<span id="close-about" class="dashicons dashicons-no-alt" title="<?php _e('Скрыть блок', 'rss-for-yandex-turbo'); ?>"></span></h3>
|
2058 |
<div class="inside" style="padding-bottom:15px;display: block;">
|
2059 |
|
2069 |
<li><a target="_blank" href="https://ru.wordpress.org/plugins/today-yesterday-dates/">Today-Yesterday Dates</a> - <?php _e('относительные даты для записей за сегодня и вчера.', 'rss-for-yandex-turbo'); ?> </li>
|
2070 |
<li><a target="_blank" href="https://ru.wordpress.org/plugins/truncate-comments/">Truncate Comments</a> - <?php _e('плагин скрывает длинные комментарии js-скриптом (в стиле Яндекса или Амазона).', 'rss-for-yandex-turbo'); ?> </li>
|
2071 |
<li><a target="_blank" href="https://ru.wordpress.org/plugins/easy-yandex-share/">Easy Yandex Share</a> - <?php _e('продвинутый вывод блока “Яндекс.Поделиться”.', 'rss-for-yandex-turbo'); ?></li>
|
2072 |
+
<li><a target="_blank" href="https://ru.wordpress.org/plugins/hide-my-dates/">Hide My Dates</a> - <?php _e('плагин прячет от Гугла даты публикации записей и комментариев.', 'rss-for-yandex-turbo'); ?></li>
|
2073 |
<li style="margin: 3px 0px 3px 35px;"><a target="_blank" href="https://ru.wordpress.org/plugins/html5-cumulus/">HTML5 Cumulus</a> <span class="new">new</span> - <?php _e('современная (HTML5) версия классического плагина “WP-Cumulus”.', 'rss-for-yandex-turbo'); ?></li>
|
2074 |
|
2075 |
</ul>
|
2080 |
</form>
|
2081 |
</div>
|
2082 |
</div>
|
2083 |
+
</div>
|
2084 |
<?php
|
2085 |
}
|
2086 |
//функция вывода страницы настроек плагина end
|
2334 |
'toolbar1' => 'undo,redo,formatselect,bold,italic,underline,strikethrough,superscript,subscript,hr,blockquote,link,unlink,bullist,numlist,table,yablocks,',
|
2335 |
'toolbar2' => '',
|
2336 |
'toolbar3' => '',
|
2337 |
+
'content_css' => $purl . '/inc/editor.css?ver=' . $yturbo_options['version'],
|
2338 |
),
|
2339 |
'quicktags' => array(
|
2340 |
'id' => 'customtemplate',
|
2417 |
$ytadfox5 = html_entity_decode(stripcslashes($yturbo_options['ytadfox5']),ENT_QUOTES);
|
2418 |
|
2419 |
$ytexcludetags = $yturbo_options['ytexcludetags'];
|
2420 |
+
$ytexcludetagslist = $yturbo_options['ytexcludetagslist'];
|
2421 |
$ytexcludetags2 = $yturbo_options['ytexcludetags2'];
|
2422 |
+
$ytexcludetagslist2 = $yturbo_options['ytexcludetagslist2'];
|
2423 |
$ytexcludecontent = $yturbo_options['ytexcludecontent'];
|
2424 |
$ytexcludecontentlist = html_entity_decode($yturbo_options['ytexcludecontentlist']);
|
2425 |
$tax_query = array();
|
2504 |
if (isset($_GET['paged'])) {
|
2505 |
$paged = $_GET['paged'];
|
2506 |
} else {
|
|
|
|
|
|
|
|
|
2507 |
$paged = 1;
|
|
|
2508 |
}
|
2509 |
+
if ($paged == 0) {$paged = 1;}
|
|
|
|
|
2510 |
} else {
|
2511 |
+
$paged = 1;
|
2512 |
$ytrazbnumber = $ytnumber;
|
2513 |
}
|
2514 |
+
if ( isset($_GET['lenta']) && $_GET['lenta'] == 'trash' ) {
|
2515 |
+
if ( $yturbo_options['ytexcludeurls'] == 'enabled' ) {
|
2516 |
+
yturbo_lenta_trash();
|
2517 |
+
exit;
|
2518 |
+
}
|
2519 |
+
}
|
2520 |
+
|
2521 |
+
//если в настройках не выбраны типы записей, то отключаем дефолтный post_type равный 'post'
|
2522 |
+
if($yttype[0]==''){$yttype[0]='trulala';}
|
2523 |
+
|
2524 |
+
$args = array(
|
2525 |
+
'paged' => $paged,
|
2526 |
+
'ignore_sticky_posts' => 1,
|
2527 |
+
'post_type' => $yttype,
|
2528 |
+
'post_status' => 'publish',
|
2529 |
+
'posts_per_page' => $ytrazbnumber,
|
2530 |
+
'tax_query' => $tax_query,
|
2531 |
+
'meta_query' => array(
|
2532 |
+
'relation' => 'OR',
|
2533 |
+
array('key' => 'ytrssenabled_meta_value', 'compare' => 'NOT EXISTS',),
|
2534 |
+
array('key' => 'ytrssenabled_meta_value', 'value' => 'yes', 'compare' => '!=',),
|
2535 |
+
)
|
2536 |
+
);
|
2537 |
+
$args = apply_filters( 'yturbo_query_args', $args );
|
2538 |
$query = new WP_Query( $args );
|
2539 |
|
2540 |
header('Content-Type: ' . feed_content_type('rss2') . '; charset=' . get_option('blog_charset'), true);
|
2558 |
<?php if ($ytmediascope) { ?><turbo:analytics id="<?php echo $ytmediascope; ?>" type="Mediascope"></turbo:analytics><?php echo PHP_EOL; ?><?php } ?>
|
2559 |
<?php do_action( 'yturbo_ads_header' ); echo yturbo_turbo_ads(); ?>
|
2560 |
<language><?php echo $ytlanguage; ?></language>
|
2561 |
+
<generator>RSS for Yandex Turbo v<?php echo $yturbo_options['version']; ?> (https://wordpress.org/plugins/rss-for-yandex-turbo/)</generator>
|
2562 |
<?php do_action( 'yturbo_generator' ); ?>
|
2563 |
<?php while($query->have_posts()) : $query->the_post(); ?>
|
2564 |
<?php $ytremove = get_post_meta(get_the_ID(), 'ytremove_meta_value', true); ?>
|
2770 |
<?php if ($yturbo_options['ytsearch'] != 'disabled' && $yturbo_options['ytsearchmesto'] == 'В начале записи') {echo yturbo_search_widget();} ?>
|
2771 |
<?php if ($yturbo_options['ytfeedback'] != 'disabled' && $yturbo_options['ytfeedbackselect'] == 'false' && $yturbo_options['ytfeedbackselectmesto'] == 'В начале записи') {echo yturbo_widget_feedback();} ?>
|
2772 |
<?php
|
2773 |
+
$content = apply_filters('yturbo_before_ads', $content);
|
2774 |
+
$temp = apply_filters('yturbo_add_custom_ads', $content);
|
2775 |
if ( $temp != $content ) {
|
2776 |
echo $temp;
|
2777 |
} else {
|
2912 |
|
2913 |
//функция удаления тегов вместе с их контентом begin
|
2914 |
function yturbo_strip_tags_with_content( $text, $tags = '', $invert = FALSE ) {
|
2915 |
+
|
2916 |
+
// удаляем лишние символы, добавляем тегам символы <> begin
|
2917 |
+
$tags = preg_replace('/[^A-Za-z0-9,]/', '', $tags);
|
2918 |
+
$a = explode(",", $tags );
|
2919 |
+
$a = array_diff($a, array(''));
|
2920 |
+
array_walk($a, function(&$value, $key) { $value = '<'. $value . '>'; } );
|
2921 |
+
$tags = implode(",", $a );
|
2922 |
+
// удаляем лишние символы, добавляем тегам символы <> end
|
2923 |
+
|
2924 |
preg_match_all( '/<(.+?)[\s]*\/?[\s]*>/si', trim( $tags ), $tags_array );
|
2925 |
$tags_array = array_unique( $tags_array[1] );
|
2926 |
|
2950 |
//функция удаления тегов без их контента begin
|
2951 |
function yturbo_strip_tags_without_content( $text, $tags = '' ) {
|
2952 |
|
2953 |
+
// удаляем лишние символы, добавляем тегам символы <> begin
|
2954 |
+
$tags = preg_replace('/[^A-Za-z0-9,]/', '', $tags);
|
2955 |
+
$a = explode(",", $tags );
|
2956 |
+
$a = array_diff($a, array(''));
|
2957 |
+
array_walk($a, function(&$value, $key) { $value = '<'. $value . '>'; } );
|
2958 |
+
$tags = implode(",", $a );
|
2959 |
+
// удаляем лишние символы, добавляем тегам символы <> end
|
2960 |
+
|
2961 |
preg_match_all('/<(.+?)[\s]*\/?[\s]*>/si', trim($tags), $tags);
|
2962 |
$tags = array_unique($tags[1]);
|
2963 |
|
3154 |
$ads = PHP_EOL.'<figure data-turbo-ad-id="second_ad_place"></figure>';
|
3155 |
}
|
3156 |
|
3157 |
+
if (mb_strlen($tempcontent) > (int)$ytrazmer && mb_strlen($tempcontent) < 65000) {
|
3158 |
$content = preg_replace('~[^^]{'. $num .'}.*?(?:\r?\n\r?\n|</p>|</figure>|</ul>|</pre>|</table>|</ol>|</blockquote>)~su', "\${0}$ads", trim( $content ), 1);
|
3159 |
}
|
3160 |
|
3339 |
<?php if ($args['has_children'] && $ytcommentsdrevo=='enabled') { ?><?php echo '<div data-block="comments">'; ?><?php }
|
3340 |
}
|
3341 |
|
3342 |
+
function yturbo_comments_end( $comment, $args, $depth ) {
|
3343 |
$yturbo_options = get_option('yturbo_options');
|
3344 |
$ytcommentsdrevo = $yturbo_options['ytcommentsdrevo'];
|
3345 |
?>
|
3628 |
if ( ! in_array( get_post_type( get_the_ID() ), $types ) )
|
3629 |
return $content;
|
3630 |
|
3631 |
+
//подключение файла с классом YTurbo_Contents begin
|
3632 |
+
require_once dirname( __FILE__ ) . '/inc/Contents.php';
|
3633 |
+
//подключение файла с классом YTurbo_Contents end
|
|
|
|
|
3634 |
|
3635 |
$selectors = array();
|
3636 |
if ($yturbo_options['yttoch1']=='enabled'){array_push($selectors, 'h1');}
|
3650 |
'selectors' => $selectors,
|
3651 |
);
|
3652 |
|
3653 |
+
$contents = YTurbo_Contents::init( $args )->make_contents( $content );
|
3654 |
|
3655 |
$contents = str_replace("\n", '', $contents);
|
3656 |
$contents = trim(preg_replace('/\t+/', '', $contents));
|
3657 |
$contents = wpautop($contents);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3658 |
|
3659 |
if ( $yturbo_options['yttocmesto'] == 'В начале записи' ) {
|
3660 |
return PHP_EOL . $contents . $content;
|
3736 |
|
3737 |
//добавляем плагины в визуальный редактор begin
|
3738 |
function yturbo_add_plugins_tinymce( $plugins ) {
|
3739 |
+
$yturbo_options = get_option('yturbo_options');
|
3740 |
$purl = plugins_url('', __FILE__);
|
3741 |
+
$plugins['yablocks'] = $purl . '/inc/yablocks.js?ver=' . $yturbo_options['version'];
|
3742 |
+
$plugins['table'] = $purl . '/inc/table.js?ver=' . $yturbo_options['version'];
|
3743 |
return $plugins;
|
3744 |
}
|
3745 |
add_filter( 'mce_external_plugins', 'yturbo_add_plugins_tinymce' );
|
3903 |
return $protected;
|
3904 |
}
|
3905 |
add_filter( 'is_protected_meta', 'yturbo_hide_custom_fields', 10, 2 );
|
3906 |
+
//скрываем произвольные поля плагина end
|
3907 |
+
|
3908 |
+
//функция определения доступных для удаления тегов begin
|
3909 |
+
function yturbo_tags_list() {
|
3910 |
+
|
3911 |
+
$tags_list = 'abbr,acronym,address,applet,area,article,aside,audio,base,basefont,bb,bdo,big,body,button,canvas,caption,center,cite,code,col,colgroup,command,datagrid,datalist,dd,del,details,dfn,dialog,dir,div,dl,dt,embed,eventsource,fieldset,font,footer,form,frame,frameset,head,header,hgroup,html,ins,isindex,kbd,keygen,label,legend,main,map,mark,menu,meter,nav,noframes,noscript,object,optgroup,option,output,param,pre,progress,q,rp,rt,ruby,samp,script,section,svg,select,small,span,style,time,title,tt,var,wbr,sidebar';
|
3912 |
+
$tags_list = apply_filters( 'yturbo_tags_list', $tags_list );
|
3913 |
+
|
3914 |
+
return $tags_list;
|
3915 |
+
}
|
3916 |
+
//функция определения доступных для удаления тегов end
|
3917 |
+
|
3918 |
+
//функция вывода мусорной ленты begin
|
3919 |
+
function yturbo_lenta_trash() {
|
3920 |
+
$yturbo_options = get_option('yturbo_options');
|
3921 |
+
|
3922 |
+
header('Content-Type: ' . feed_content_type('rss2') . '; charset=' . get_option('blog_charset'), true);
|
3923 |
+
echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>'.PHP_EOL;
|
3924 |
+
?>
|
3925 |
+
<rss
|
3926 |
+
xmlns:yandex="http://news.yandex.ru"
|
3927 |
+
xmlns:media="http://search.yahoo.com/mrss/"
|
3928 |
+
xmlns:turbo="http://turbo.yandex.ru"
|
3929 |
+
version="2.0">
|
3930 |
+
<channel>
|
3931 |
+
<turbo:cms_plugin>C125AEEC6018B4A0EF9BF40E6615DD17</turbo:cms_plugin>
|
3932 |
+
<title><?php echo stripslashes($yturbo_options['yttitle']); ?></title>
|
3933 |
+
<link><?php echo esc_html($yturbo_options['ytlink']); ?></link>
|
3934 |
+
<description><?php echo stripslashes($yturbo_options['ytdescription']); ?></description>
|
3935 |
+
<language><?php echo $yturbo_options['ytlanguage']; ?></language>
|
3936 |
+
<generator>RSS for Yandex Turbo v<?php echo $yturbo_options['version']; ?> (https://wordpress.org/plugins/rss-for-yandex-turbo/)</generator>
|
3937 |
+
<?php if ( $yturbo_options['ytexcludeurlslist'] ) {
|
3938 |
+
$textAr = explode("\n", str_replace(array("\r\n", "\r"), "\n", $yturbo_options['ytexcludeurlslist']));
|
3939 |
+
$i = 0;
|
3940 |
+
foreach ($textAr as $line) {
|
3941 |
+
$line = stripcslashes($line);
|
3942 |
+
$line = '<item turbo="false"><link>' . $line . '</link></item>' . PHP_EOL;
|
3943 |
+
if ($i > 0) echo ' ';
|
3944 |
+
echo $line;
|
3945 |
+
$i++;
|
3946 |
+
}
|
3947 |
+
} else {
|
3948 |
+
//чтобы яндекс не ругался на пустую ленту, если на удалении нет записей
|
3949 |
+
echo '<item turbo="false"><link>' . get_bloginfo_rss('url') . '/musor-page/</link></item>' . PHP_EOL;
|
3950 |
+
}
|
3951 |
+
?>
|
3952 |
+
</channel>
|
3953 |
+
</rss>
|
3954 |
+
<?php }
|
3955 |
+
//функция вывода мусорной ленты end
|
3956 |
+
|
3957 |
+
//функция отслеживания урлов удаляемых записей begin
|
3958 |
+
function yturbo_trash_tracking( $post_id ) {
|
3959 |
+
|
3960 |
+
$yturbo_options = get_option('yturbo_options');
|
3961 |
+
|
3962 |
+
if ( $yturbo_options['ytexcludeurls'] == 'disabled' )
|
3963 |
+
return;
|
3964 |
+
|
3965 |
+
if ( $yturbo_options['ytdeltracking'] == 'disabled' )
|
3966 |
+
return;
|
3967 |
+
|
3968 |
+
$yttype = explode(",", $yturbo_options['yttype']);
|
3969 |
+
$yttype = array_diff($yttype, array(''));
|
3970 |
+
|
3971 |
+
if ( ! in_array(get_post_type($post_id), $yttype) )
|
3972 |
+
return;
|
3973 |
+
|
3974 |
+
$delpermalink = PHP_EOL . esc_url( apply_filters( 'the_permalink_rss', get_permalink($post_id) ) );
|
3975 |
+
$yturbo_options['ytexcludeurlslist'] .= $delpermalink;
|
3976 |
+
$lines = array_filter(explode("\n", trim($yturbo_options['ytexcludeurlslist'])));
|
3977 |
+
$yturbo_options['ytexcludeurlslist'] = implode("\n", $lines);
|
3978 |
+
|
3979 |
+
update_option('yturbo_options', $yturbo_options);
|
3980 |
+
}
|
3981 |
+
add_action( 'wp_trash_post', 'yturbo_trash_tracking' );
|
3982 |
+
//функция отслеживания урлов удаляемых записей end
|
3983 |
+
|
3984 |
+
//функция отслеживания урлов восстанавливаемых записей begin
|
3985 |
+
function yturbo_untrash_tracking( $post_id ) {
|
3986 |
+
|
3987 |
+
$yturbo_options = get_option('yturbo_options');
|
3988 |
+
|
3989 |
+
if ( $yturbo_options['ytexcludeurls'] == 'disabled' )
|
3990 |
+
return;
|
3991 |
+
|
3992 |
+
if ( $yturbo_options['ytdeltracking'] == 'disabled' )
|
3993 |
+
return;
|
3994 |
+
|
3995 |
+
$yttype = explode(",", $yturbo_options['yttype']);
|
3996 |
+
$yttype = array_diff($yttype, array(''));
|
3997 |
+
|
3998 |
+
if ( ! in_array(get_post_type($post_id), $yttype) )
|
3999 |
+
return;
|
4000 |
+
|
4001 |
+
$restorepermalink = esc_url( apply_filters( 'the_permalink_rss', get_permalink($post_id) ) );
|
4002 |
+
$yturbo_options['ytexcludeurlslist'] = str_replace($restorepermalink, '', $yturbo_options['ytexcludeurlslist']);
|
4003 |
+
$lines = array_filter(explode("\n", trim($yturbo_options['ytexcludeurlslist'])));
|
4004 |
+
$yturbo_options['ytexcludeurlslist'] = implode("\n", $lines);
|
4005 |
+
|
4006 |
+
update_option('yturbo_options', $yturbo_options);
|
4007 |
+
}
|
4008 |
+
add_action( 'untrashed_post', 'yturbo_untrash_tracking' );
|
4009 |
+
//функция отслеживания урлов восстанавливаемых записей end
|
4010 |
+
|
4011 |
+
|