Version Description
(2018-08-16) =
Release Notes: click here
-
New Features
- Added a startup wizard to assist new users with new installs.
- Introduced the WordPress activity log levels.
- New search filters in the WordPress activity log viewer.
- Added a new test button to all external database connections, including those for WordPress activity log archiving and mirroring.
- Added several new settings to purge the WordPress activity log and reset plugin settings to default.
-
Improvements
- Performance improvement: optimized the logic of the plugin sensors to load only required ones during user action.
- Redesigned all the settings pages and included more help text, making them more user friendly.
- Added links to plugin knowledge base where possible in the plugin settings.
- Improved the WordPress activity log pruning setting so now it is possible to configure retention based on a period of time.
- Database improvement: changed the option_value column in the plugin tables to long text.
- WordPress website file changes results are now stored in the plugin's options table.
- Improved the list of excluded file extensions in the WordPress file changes scanner.
- Added sorting in the logged in WordPress users view.
- Added more checks to ensure opt-in and other plugin messages are shown when needed only.
- Removed affiliate network message in plugin.
-
Bug Fixes
- Fixed an issue where stored passwords might have been changed because of change from Mcrypt to OpenSSL.
- Fixed an issue in which retention settings were reset when moved to archiving settings.
Download this release
Release Info
Developer | WPWhiteSecurity |
Plugin | WP Security Audit Log |
Version | 3.2.3 |
Comparing to | |
See all releases |
Code changes from version 3.2.2.2 to 3.2.3
- classes/AbstractSensor.php +20 -6
- classes/Adapters/MySQL/ActiveRecordAdapter.php +19 -7
- classes/AlertManager.php +13 -8
- classes/AuditLogListView.php +231 -72
- classes/Connector/ConnectorFactory.php +1 -1
- classes/Connector/MySQLDB.php +34 -5
- classes/SensorManager.php +142 -4
- classes/Sensors/BBPress.php +0 -5
- classes/Sensors/FileChanges.php +19 -19
- classes/Sensors/MetaData.php +41 -11
- classes/Sensors/Multisite.php +11 -13
- classes/Sensors/PluginsThemes.php +53 -23
- classes/Sensors/UserProfile.php +16 -12
- classes/Sensors/WooCommerce.php +0 -5
- classes/Sensors/YoastSEO.php +7 -12
- classes/Settings.php +165 -16
- classes/ViewManager.php +53 -7
- classes/Views/AuditLog.php +211 -69
- classes/Views/Help.php +43 -17
- classes/Views/Settings.php +1691 -1187
- classes/Views/SetupWizard.php +765 -0
- classes/Views/ToggleAlerts.php +56 -5
- css/auditlog.css +5 -6
- css/dist/wsal-wizard.build.css +169 -0
- css/settings.css +22 -3
- css/src/common.scss +0 -0
- css/src/wsal-wizard.scss +182 -0
- defaults.php +63 -58
- img/wsal-logo-full.png +0 -0
- img/wsal-logo-full@2x.png +0 -0
- js/auditlog.js +5 -4
- js/dist/wsal-wizard.js +10592 -0
- js/dist/wsal-wizard.min.js +39 -0
- js/settings.js +168 -111
- js/src/wsal-wizard.js +102 -0
- readme.txt +24 -40
- sdk/freemius/assets/css/admin/common.css +1 -1
- sdk/freemius/assets/scss/admin/common.scss +1 -1
- sdk/freemius/includes/class-freemius.php +126 -51
- sdk/freemius/includes/class-fs-api.php +1 -1
- sdk/freemius/includes/class-fs-plugin-updater.php +177 -0
- sdk/freemius/includes/customizer/class-fs-customizer-upsell-control.php +1 -1
- sdk/freemius/includes/fs-plugin-info-dialog.php +11 -8
- sdk/freemius/languages/freemius-da_DK.mo +0 -0
- sdk/freemius/languages/freemius-da_DK.po +9 -2296
- sdk/freemius/languages/freemius-he_IL.mo +0 -0
- sdk/freemius/languages/freemius-he_IL.po +50 -50
- sdk/freemius/languages/freemius-it_IT.mo +0 -0
- sdk/freemius/languages/freemius-it_IT.po +15 -15
- sdk/freemius/languages/freemius.pot +169 -169
- sdk/freemius/start.php +11 -1
- sdk/freemius/templates/account.php +5 -1
- sdk/freemius/templates/account/partials/addon.php +2 -2
- sdk/freemius/templates/add-ons.php +5 -1
- sdk/freemius/templates/checkout.php +2 -2
- sdk/freemius/templates/connect.php +16 -2
- sdk/freemius/templates/contact.php +1 -1
- sdk/freemius/templates/pricing.php +1 -1
- sdk/freemius/templates/tabs.php +5 -1
- sdk/wsal-freemius.php +19 -14
- wp-security-audit-log.php +140 -54
classes/AbstractSensor.php
CHANGED
@@ -1,4 +1,18 @@
|
|
1 |
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
/**
|
3 |
* Abstract class used in all the sensors.
|
4 |
*
|
@@ -40,9 +54,9 @@ abstract class WSAL_AbstractSensor {
|
|
40 |
/**
|
41 |
* Method: Log the message for sensor.
|
42 |
*
|
43 |
-
* @param int $type
|
44 |
* @param string $message - Alert message.
|
45 |
-
* @param mix $args
|
46 |
*/
|
47 |
protected function Log( $type, $message, $args ) {
|
48 |
$this->plugin->alerts->Trigger(
|
@@ -58,7 +72,7 @@ abstract class WSAL_AbstractSensor {
|
|
58 |
* Method: Log error message for sensor.
|
59 |
*
|
60 |
* @param string $message - Alert message.
|
61 |
-
* @param mix $args
|
62 |
*/
|
63 |
protected function LogError( $message, $args ) {
|
64 |
$this->Log( 0001, $message, $args );
|
@@ -68,7 +82,7 @@ abstract class WSAL_AbstractSensor {
|
|
68 |
* Method: Log warning message for sensor.
|
69 |
*
|
70 |
* @param string $message - Alert message.
|
71 |
-
* @param mix $args
|
72 |
*/
|
73 |
protected function LogWarn( $message, $args ) {
|
74 |
$this->Log( 0002, $message, $args );
|
@@ -78,14 +92,14 @@ abstract class WSAL_AbstractSensor {
|
|
78 |
* Method: Log info message for sensor.
|
79 |
*
|
80 |
* @param string $message - Alert message.
|
81 |
-
* @param mix $args
|
82 |
*/
|
83 |
protected function LogInfo( $message, $args ) {
|
84 |
$this->Log( 0003, $message, $args );
|
85 |
}
|
86 |
|
87 |
/**
|
88 |
-
* Check to see whether or not the specified directory is accessible
|
89 |
*
|
90 |
* @param string $dir_path - Directory path.
|
91 |
* @return boolean
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Abstract Class: Sensor
|
4 |
+
*
|
5 |
+
* Abstract sensor class file.
|
6 |
+
*
|
7 |
+
* @since 1.0.0
|
8 |
+
* @package Wsal
|
9 |
+
*/
|
10 |
+
|
11 |
+
// Exit if accessed directly.
|
12 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
13 |
+
exit;
|
14 |
+
}
|
15 |
+
|
16 |
/**
|
17 |
* Abstract class used in all the sensors.
|
18 |
*
|
54 |
/**
|
55 |
* Method: Log the message for sensor.
|
56 |
*
|
57 |
+
* @param int $type - Type of alert.
|
58 |
* @param string $message - Alert message.
|
59 |
+
* @param mix $args - Message arguments.
|
60 |
*/
|
61 |
protected function Log( $type, $message, $args ) {
|
62 |
$this->plugin->alerts->Trigger(
|
72 |
* Method: Log error message for sensor.
|
73 |
*
|
74 |
* @param string $message - Alert message.
|
75 |
+
* @param mix $args - Message arguments.
|
76 |
*/
|
77 |
protected function LogError( $message, $args ) {
|
78 |
$this->Log( 0001, $message, $args );
|
82 |
* Method: Log warning message for sensor.
|
83 |
*
|
84 |
* @param string $message - Alert message.
|
85 |
+
* @param mix $args - Message arguments.
|
86 |
*/
|
87 |
protected function LogWarn( $message, $args ) {
|
88 |
$this->Log( 0002, $message, $args );
|
92 |
* Method: Log info message for sensor.
|
93 |
*
|
94 |
* @param string $message - Alert message.
|
95 |
+
* @param mix $args - Message arguments.
|
96 |
*/
|
97 |
protected function LogInfo( $message, $args ) {
|
98 |
$this->Log( 0003, $message, $args );
|
99 |
}
|
100 |
|
101 |
/**
|
102 |
+
* Check to see whether or not the specified directory is accessible.
|
103 |
*
|
104 |
* @param string $dir_path - Directory path.
|
105 |
* @return boolean
|
classes/Adapters/MySQL/ActiveRecordAdapter.php
CHANGED
@@ -377,12 +377,11 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
|
|
377 |
* @return string - Must return SQL for creating table.
|
378 |
*/
|
379 |
protected function _GetInstallQuery( $prefix = false ) {
|
380 |
-
$_wpdb
|
381 |
-
|
382 |
-
$
|
383 |
-
$
|
384 |
-
$
|
385 |
-
$sql = 'CREATE TABLE IF NOT EXISTS ' . $table_name . ' (' . PHP_EOL;
|
386 |
|
387 |
foreach ( $this->GetColumns() as $key ) {
|
388 |
$sql .= ' ';
|
@@ -401,7 +400,7 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
|
|
401 |
if ( property_exists( $class, $maxlength ) ) {
|
402 |
$sql .= $key . ' VARCHAR(' . intval( $class::$$maxlength ) . ') NOT NULL,' . PHP_EOL;
|
403 |
} else {
|
404 |
-
$sql .= $key . '
|
405 |
}
|
406 |
break;
|
407 |
case is_bool( $copy->$key ):
|
@@ -425,6 +424,19 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
|
|
425 |
return $sql;
|
426 |
}
|
427 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
428 |
/**
|
429 |
* Must return SQL for removing table (at a minimum, it should be ` 'DROP TABLE ' . $this->_table `).
|
430 |
*
|
377 |
* @return string - Must return SQL for creating table.
|
378 |
*/
|
379 |
protected function _GetInstallQuery( $prefix = false ) {
|
380 |
+
$_wpdb = $this->connection;
|
381 |
+
$class = get_class( $this );
|
382 |
+
$copy = new $class( $this->connection );
|
383 |
+
$table_name = ( $prefix ) ? $this->GetWPTable() : $this->GetTable();
|
384 |
+
$sql = 'CREATE TABLE IF NOT EXISTS ' . $table_name . ' (' . PHP_EOL;
|
|
|
385 |
|
386 |
foreach ( $this->GetColumns() as $key ) {
|
387 |
$sql .= ' ';
|
400 |
if ( property_exists( $class, $maxlength ) ) {
|
401 |
$sql .= $key . ' VARCHAR(' . intval( $class::$$maxlength ) . ') NOT NULL,' . PHP_EOL;
|
402 |
} else {
|
403 |
+
$sql .= $key . ' LONGTEXT NOT NULL,' . PHP_EOL;
|
404 |
}
|
405 |
break;
|
406 |
case is_bool( $copy->$key ):
|
424 |
return $sql;
|
425 |
}
|
426 |
|
427 |
+
/**
|
428 |
+
* Update `option_value` column of the Options table
|
429 |
+
* of WSAL to LONGTEXT.
|
430 |
+
*
|
431 |
+
* @since 3.2.3
|
432 |
+
*/
|
433 |
+
public function update_value_column() {
|
434 |
+
global $wpdb;
|
435 |
+
$sql = 'ALTER TABLE ' . $this->GetTable();
|
436 |
+
$sql .= ' MODIFY COLUMN option_value LONGTEXT NOT NULL';
|
437 |
+
$wpdb->query( $sql );
|
438 |
+
}
|
439 |
+
|
440 |
/**
|
441 |
* Must return SQL for removing table (at a minimum, it should be ` 'DROP TABLE ' . $this->_table `).
|
442 |
*
|
classes/AlertManager.php
CHANGED
@@ -133,9 +133,9 @@ final class WSAL_AlertManager {
|
|
133 |
/**
|
134 |
* Trigger an alert.
|
135 |
*
|
136 |
-
* @param integer $type Alert type.
|
137 |
-
* @param array $data Alert data.
|
138 |
-
* @param
|
139 |
*/
|
140 |
public function Trigger( $type, $data = array(), $delayed = false ) {
|
141 |
// Get buffer use option.
|
@@ -208,7 +208,7 @@ final class WSAL_AlertManager {
|
|
208 |
*/
|
209 |
public function TriggerIf( $type, $data, $cond = null ) {
|
210 |
$username = wp_get_current_user()->user_login;
|
211 |
-
$roles
|
212 |
|
213 |
if ( $this->CheckEnableUserRoles( $username, $roles ) ) {
|
214 |
$this->_pipeline[] = array(
|
@@ -228,7 +228,7 @@ final class WSAL_AlertManager {
|
|
228 |
* @param bool $_retry - Retry.
|
229 |
* @internal
|
230 |
*
|
231 |
-
* @throws
|
232 |
*/
|
233 |
protected function _CommitItem( $type, $data, $cond, $_retry = true ) {
|
234 |
if ( ! $cond || ! ! call_user_func( $cond, $this ) ) {
|
@@ -243,7 +243,8 @@ final class WSAL_AlertManager {
|
|
243 |
return $this->_CommitItem( $type, $data, $cond, false );
|
244 |
} else {
|
245 |
// In general this shouldn't happen, but it could, so we handle it here.
|
246 |
-
|
|
|
247 |
}
|
248 |
}
|
249 |
}
|
@@ -476,9 +477,10 @@ final class WSAL_AlertManager {
|
|
476 |
/**
|
477 |
* Returns all supported alerts.
|
478 |
*
|
|
|
479 |
* @return array
|
480 |
*/
|
481 |
-
public function GetCategorizedAlerts() {
|
482 |
$result = array();
|
483 |
foreach ( $this->_alerts as $alert ) {
|
484 |
if ( ! isset( $result[ $alert->catg ] ) ) {
|
@@ -489,7 +491,10 @@ final class WSAL_AlertManager {
|
|
489 |
}
|
490 |
$result[ $alert->catg ][ $alert->subcatg ][] = $alert;
|
491 |
}
|
492 |
-
|
|
|
|
|
|
|
493 |
return $result;
|
494 |
}
|
495 |
|
133 |
/**
|
134 |
* Trigger an alert.
|
135 |
*
|
136 |
+
* @param integer $type - Alert type.
|
137 |
+
* @param array $data - Alert data.
|
138 |
+
* @param mix $delayed - False if delayed, function if not.
|
139 |
*/
|
140 |
public function Trigger( $type, $data = array(), $delayed = false ) {
|
141 |
// Get buffer use option.
|
208 |
*/
|
209 |
public function TriggerIf( $type, $data, $cond = null ) {
|
210 |
$username = wp_get_current_user()->user_login;
|
211 |
+
$roles = $this->plugin->settings->GetCurrentUserRoles();
|
212 |
|
213 |
if ( $this->CheckEnableUserRoles( $username, $roles ) ) {
|
214 |
$this->_pipeline[] = array(
|
228 |
* @param bool $_retry - Retry.
|
229 |
* @internal
|
230 |
*
|
231 |
+
* @throws Exception - Error if alert is not registered.
|
232 |
*/
|
233 |
protected function _CommitItem( $type, $data, $cond, $_retry = true ) {
|
234 |
if ( ! $cond || ! ! call_user_func( $cond, $this ) ) {
|
243 |
return $this->_CommitItem( $type, $data, $cond, false );
|
244 |
} else {
|
245 |
// In general this shouldn't happen, but it could, so we handle it here.
|
246 |
+
/* translators: Event ID */
|
247 |
+
throw new Exception( sprintf( esc_html__( 'Event with code %d has not be registered.', 'wp-security-audit-log' ), $type ) );
|
248 |
}
|
249 |
}
|
250 |
}
|
477 |
/**
|
478 |
* Returns all supported alerts.
|
479 |
*
|
480 |
+
* @param bool $sorted – Sort the alerts array or not.
|
481 |
* @return array
|
482 |
*/
|
483 |
+
public function GetCategorizedAlerts( $sorted = true ) {
|
484 |
$result = array();
|
485 |
foreach ( $this->_alerts as $alert ) {
|
486 |
if ( ! isset( $result[ $alert->catg ] ) ) {
|
491 |
}
|
492 |
$result[ $alert->catg ][ $alert->subcatg ][] = $alert;
|
493 |
}
|
494 |
+
|
495 |
+
if ( $sorted ) {
|
496 |
+
ksort( $result );
|
497 |
+
}
|
498 |
return $result;
|
499 |
}
|
500 |
|
classes/AuditLogListView.php
CHANGED
@@ -13,8 +13,8 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|
13 |
exit;
|
14 |
}
|
15 |
|
16 |
-
require_once
|
17 |
-
require_once
|
18 |
|
19 |
/**
|
20 |
* This view is included in Audit Log Viewer Page.
|
@@ -57,18 +57,30 @@ class WSAL_AuditLogListView extends WP_List_Table {
|
|
57 |
$this->_plugin = $plugin;
|
58 |
|
59 |
$timezone = $this->_plugin->settings->GetTimezone();
|
60 |
-
|
61 |
-
|
62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
$this->_gmt_offset_sec = date( 'Z' );
|
|
|
|
|
64 |
}
|
65 |
|
66 |
parent::__construct(
|
67 |
array(
|
68 |
-
'singular'
|
69 |
-
'plural'
|
70 |
-
'ajax'
|
71 |
-
'screen'
|
72 |
)
|
73 |
);
|
74 |
}
|
@@ -81,33 +93,68 @@ class WSAL_AuditLogListView extends WP_List_Table {
|
|
81 |
}
|
82 |
|
83 |
/**
|
84 |
-
*
|
85 |
*
|
86 |
-
* @
|
|
|
87 |
*/
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
$items = array( 5, 10, 15, 30, 50 );
|
92 |
-
if ( ! in_array( $p, $items ) ) {
|
93 |
-
$items[] = $p;
|
94 |
}
|
95 |
?>
|
96 |
-
<div class="
|
97 |
-
<?php
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
|
|
|
|
|
|
|
|
|
|
108 |
</div>
|
109 |
-
|
110 |
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
111 |
// Show site alerts widget.
|
112 |
if ( $this->is_multisite() && $this->is_main_blog() ) {
|
113 |
$curr = $this->get_view_site_id();
|
@@ -115,7 +162,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
|
|
115 |
<div class="wsal-ssa wsal-ssa-<?php echo esc_attr( $which ); ?>">
|
116 |
<?php if ( $this->get_site_count() > 15 ) { ?>
|
117 |
<?php $curr = $curr ? get_blog_details( $curr ) : null; ?>
|
118 |
-
<?php $curr = $curr ? ($curr->blogname . ' (' . $curr->domain . ')') : 'All Sites'; ?>
|
119 |
<input type="text" class="wsal-ssas" value="<?php echo esc_attr( $curr ); ?>"/>
|
120 |
<?php } else { ?>
|
121 |
<select class="wsal-ssas" onchange="WsalSsasChange(value);">
|
@@ -134,7 +181,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
|
|
134 |
|
135 |
// Switch to live or archive DB.
|
136 |
if ( $this->_plugin->settings->IsArchivingEnabled() ) {
|
137 |
-
$selected
|
138 |
$selected_db = get_transient( 'wsal_wp_selected_db' );
|
139 |
if ( $selected_db && 'archive' == $selected_db ) {
|
140 |
$selected = 'archive';
|
@@ -197,12 +244,15 @@ class WSAL_AuditLogListView extends WP_List_Table {
|
|
197 |
* @return array
|
198 |
*/
|
199 |
public function get_columns() {
|
|
|
200 |
$type_name = $this->_plugin->settings->get_type_username();
|
201 |
-
if ( 'display_name' === $type_name ) {
|
202 |
$name_column = __( 'User', 'wp-security-audit-log' );
|
203 |
} elseif ( 'username' === $type_name ) {
|
204 |
$name_column = __( 'Username', 'wp-security-audit-log' );
|
205 |
}
|
|
|
|
|
206 |
$cols = array(
|
207 |
'type' => __( 'Event ID', 'wp-security-audit-log' ),
|
208 |
'code' => __( 'Severity', 'wp-security-audit-log' ),
|
@@ -210,11 +260,18 @@ class WSAL_AuditLogListView extends WP_List_Table {
|
|
210 |
'user' => $name_column,
|
211 |
'scip' => __( 'Source IP', 'wp-security-audit-log' ),
|
212 |
);
|
|
|
|
|
213 |
if ( $this->is_multisite() && $this->is_main_blog() && ! $this->is_specific_view() ) {
|
214 |
$cols['site'] = __( 'Site', 'wp-security-audit-log' );
|
215 |
}
|
|
|
216 |
$cols['mesg'] = __( 'Message', 'wp-security-audit-log' );
|
|
|
|
|
217 |
$sel_columns = $this->_plugin->settings->GetColumnsSelected();
|
|
|
|
|
218 |
if ( ! empty( $sel_columns ) ) {
|
219 |
unset( $cols );
|
220 |
$sel_columns = (array) json_decode( $sel_columns );
|
@@ -255,8 +312,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
|
|
255 |
* @return string
|
256 |
*/
|
257 |
public function column_cb( $item ) {
|
258 |
-
return '<input type="checkbox" value="' . $item->id . '" '
|
259 |
-
. 'name="' . esc_attr( $this->_args['singular'] ) . '[]"/>';
|
260 |
}
|
261 |
|
262 |
/**
|
@@ -290,12 +346,12 @@ class WSAL_AuditLogListView extends WP_List_Table {
|
|
290 |
switch ( $column_name ) {
|
291 |
case 'read':
|
292 |
return '<span class="log-read log-read-'
|
293 |
-
. ($item->is_read ? 'old' : 'new')
|
294 |
. '" title="' . __( 'Click to toggle.', 'wp-security-audit-log' ) . '"></span>';
|
295 |
case 'type':
|
296 |
-
$code
|
297 |
-
$extra_msg
|
298 |
-
$data_link
|
299 |
$modification_alerts = array( 1002, 1003, 6007, 6023 );
|
300 |
if ( in_array( $item->alert_id, $modification_alerts, true ) ) {
|
301 |
$extra_msg = '. Modify this alert.';
|
@@ -313,23 +369,22 @@ class WSAL_AuditLogListView extends WP_List_Table {
|
|
313 |
return '<span class="log-disable" data-disable-alert-nonce="' . wp_create_nonce( 'disable-alert-nonce' . $item->alert_id ) . '" data-tooltip="' . __( 'Disable this type of events.', 'wp-security-audit-log' ) . '<br>' . $item->alert_id . ' - ' . esc_html( $code->desc ) . $extra_msg . '" data-alert-id="' . $item->alert_id . '" ' . esc_attr( 'data-link=' . $data_link ) . ' >'
|
314 |
. str_pad( $item->alert_id, 4, '0', STR_PAD_LEFT ) . ' </span>';
|
315 |
case 'code':
|
316 |
-
$code
|
317 |
-
$code
|
318 |
$const = (object) array(
|
319 |
-
'name'
|
320 |
-
'value'
|
321 |
'description' => __( 'Unknown error code.', 'wp-security-audit-log' ),
|
322 |
);
|
323 |
$const = $this->_plugin->constants->GetConstantBy( 'value', $code, $const );
|
324 |
-
if ( 'E_CRITICAL'
|
325 |
-
$const->name = 'Critical';
|
326 |
-
} elseif ( 'E_WARNING'
|
327 |
-
$const->name = 'Warning';
|
328 |
-
} elseif ( 'E_NOTICE'
|
329 |
-
$const->name = 'Notification';
|
330 |
}
|
331 |
-
return '<a class="tooltip" href="#" data-tooltip="' . esc_html( $const->name ) . '"><span class="log-type log-type-' . $const->value
|
332 |
-
. '"></span></a>';
|
333 |
case 'crtd':
|
334 |
return $item->created_on ? (
|
335 |
str_replace(
|
@@ -337,16 +392,24 @@ class WSAL_AuditLogListView extends WP_List_Table {
|
|
337 |
substr( number_format( fmod( $item->created_on + $this->_gmt_offset_sec, 1 ), 3 ), 2 ),
|
338 |
date( $datetime_format, $item->created_on + $this->_gmt_offset_sec )
|
339 |
)
|
340 |
-
) : '<i>
|
341 |
case 'user':
|
342 |
-
$username
|
343 |
-
$type_name
|
344 |
-
$user
|
345 |
|
346 |
// Check if the username and user exists.
|
347 |
if ( $username && $user ) {
|
|
|
348 |
$image = get_avatar( $user->ID, 32 );
|
349 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
350 |
$display_name = $user->first_name . ' ' . $user->last_name;
|
351 |
} else {
|
352 |
$display_name = $user->user_login;
|
@@ -419,7 +482,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
|
|
419 |
if ( class_exists( 'WSAL_SearchExtension' ) ) {
|
420 |
$tooltip = esc_attr__( 'Show me all activity originating from this IP Address', 'wp-security-audit-log' );
|
421 |
|
422 |
-
$html
|
423 |
foreach ( $oips as $ip ) {
|
424 |
if ( $scip != $ip ) {
|
425 |
$html .= '<div>' . $ip . '</div>';
|
@@ -428,7 +491,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
|
|
428 |
$html .= '</div>';
|
429 |
return $html;
|
430 |
} else {
|
431 |
-
$html
|
432 |
foreach ( $oips as $ip ) {
|
433 |
if ( $scip != $ip ) {
|
434 |
$html .= '<div>' . $ip . '</div>';
|
@@ -440,12 +503,12 @@ class WSAL_AuditLogListView extends WP_List_Table {
|
|
440 |
|
441 |
case 'site':
|
442 |
$info = get_blog_details( $item->site_id, true );
|
443 |
-
return ! $info ? ('Unknown Site ' . $item->site_id)
|
444 |
-
: ('<a href="' . esc_attr( $info->siteurl ) . '">' . esc_html( $info->blogname ) . '</a>');
|
445 |
case 'mesg':
|
446 |
return '<div id="Event' . $item->id . '">' . $item->GetMessage( array( $this, 'meta_formatter' ) ) . '</div>';
|
447 |
case 'data':
|
448 |
-
$url
|
449 |
$tooltip = esc_attr__( 'View all details of this change', 'wp-security-audit-log' );
|
450 |
return '<a class="more-info thickbox" data-tooltip="' . $tooltip . '" title="' . __( 'Alert Data Inspector', 'wp-security-audit-log' ) . '"'
|
451 |
. ' href="' . $url . '&TB_iframe=true&width=600&height=550">…</a>';
|
@@ -535,7 +598,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
|
|
535 |
|
536 |
case in_array( $name, array( '%MetaValue%', '%MetaValueOld%', '%MetaValueNew%' ) ):
|
537 |
return '<strong>' . (
|
538 |
-
strlen( $value ) > 50 ? (esc_html( substr( $value, 0, 50 ) ) . '…') : esc_html( $value )
|
539 |
) . '</strong>';
|
540 |
|
541 |
case '%ClientIP%' == $name:
|
@@ -547,7 +610,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
|
|
547 |
|
548 |
case '%LinkFile%' === $name:
|
549 |
if ( 'NULL' != $value ) {
|
550 |
-
$site_id
|
551 |
return '<a href="javascript:;" onclick="download_404_log( this )" data-log-file="' . esc_attr( $value ) . '" data-site-id="' . esc_attr( $site_id ) . '" data-nonce-404="' . esc_attr( wp_create_nonce( 'wsal-download-404-log-' . $value ) ) . '" title="' . esc_html__( 'Download the log file', 'wp-security-audit-log' ) . '">' . esc_html__( 'Download the log file', 'wp-security-audit-log' ) . '</a>';
|
552 |
} else {
|
553 |
return 'Click <a href="' . esc_url( admin_url( 'admin.php?page=wsal-togglealerts#tab-system-activity' ) ) . '">here</a> to log such requests to file';
|
@@ -628,10 +691,10 @@ class WSAL_AuditLogListView extends WP_List_Table {
|
|
628 |
* @return bool
|
629 |
*/
|
630 |
protected function is_specific_view() {
|
631 |
-
// Filter $
|
632 |
-
$
|
633 |
|
634 |
-
return isset( $
|
635 |
}
|
636 |
|
637 |
/**
|
@@ -640,10 +703,10 @@ class WSAL_AuditLogListView extends WP_List_Table {
|
|
640 |
* @return int
|
641 |
*/
|
642 |
protected function get_specific_view() {
|
643 |
-
// Filter $
|
644 |
-
$
|
645 |
|
646 |
-
return isset( $
|
647 |
}
|
648 |
|
649 |
/**
|
@@ -682,8 +745,8 @@ class WSAL_AuditLogListView extends WP_List_Table {
|
|
682 |
|
683 |
$per_page = $this->_plugin->settings->GetViewPerPage();
|
684 |
|
685 |
-
$columns
|
686 |
-
$hidden
|
687 |
$sortable = $this->get_sortable_columns();
|
688 |
|
689 |
$this->_column_headers = array( $columns, $hidden, $sortable );
|
@@ -739,7 +802,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
|
|
739 |
// @todo Modify $query instead
|
740 |
// @deprecated
|
741 |
// $data = array_slice($data, ($this->get_pagenum() - 1) * $per_page, $per_page);
|
742 |
-
$query->setOffset( ($this->get_pagenum() - 1) * $per_page );
|
743 |
$query->setLimit( $per_page );
|
744 |
|
745 |
$this->items = $query->getAdapter()->Execute( $query );
|
@@ -767,4 +830,100 @@ class WSAL_AuditLogListView extends WP_List_Table {
|
|
767 |
parent::single_row( $item );
|
768 |
}
|
769 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
770 |
}
|
13 |
exit;
|
14 |
}
|
15 |
|
16 |
+
require_once ABSPATH . 'wp-admin/includes/admin.php';
|
17 |
+
require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
|
18 |
|
19 |
/**
|
20 |
* This view is included in Audit Log Viewer Page.
|
57 |
$this->_plugin = $plugin;
|
58 |
|
59 |
$timezone = $this->_plugin->settings->GetTimezone();
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Transform timezone values.
|
63 |
+
*
|
64 |
+
* @since 3.2.3
|
65 |
+
*/
|
66 |
+
if ( '0' === $timezone ) {
|
67 |
+
$timezone = 'utc';
|
68 |
+
} elseif ( '1' === $timezone ) {
|
69 |
+
$timezone = 'wp';
|
70 |
+
}
|
71 |
+
|
72 |
+
if ( 'utc' === $timezone ) {
|
73 |
$this->_gmt_offset_sec = date( 'Z' );
|
74 |
+
} else {
|
75 |
+
$this->_gmt_offset_sec = get_option( 'gmt_offset' ) * HOUR_IN_SECONDS;
|
76 |
}
|
77 |
|
78 |
parent::__construct(
|
79 |
array(
|
80 |
+
'singular' => 'log',
|
81 |
+
'plural' => 'logs',
|
82 |
+
'ajax' => true,
|
83 |
+
'screen' => 'interval-list',
|
84 |
)
|
85 |
);
|
86 |
}
|
93 |
}
|
94 |
|
95 |
/**
|
96 |
+
* Generate the table navigation above or below the table
|
97 |
*
|
98 |
+
* @since 3.2.3
|
99 |
+
* @param string $which – Position of the nav.
|
100 |
*/
|
101 |
+
protected function display_tablenav( $which ) {
|
102 |
+
if ( 'top' === $which ) {
|
103 |
+
wp_nonce_field( 'bulk-' . $this->_args['plural'] );
|
|
|
|
|
|
|
104 |
}
|
105 |
?>
|
106 |
+
<div class="tablenav <?php echo esc_attr( $which ); ?>">
|
107 |
+
<?php
|
108 |
+
$this->extra_tablenav( $which );
|
109 |
+
|
110 |
+
/**
|
111 |
+
* Action: `wsal_search_filters_list`
|
112 |
+
*
|
113 |
+
* Display list of search filters of WSAL.
|
114 |
+
*
|
115 |
+
* @param string $which – Navigation position; value is either top or bottom.
|
116 |
+
* @since 3.2.3
|
117 |
+
*/
|
118 |
+
do_action( 'wsal_search_filters_list', $which );
|
119 |
+
|
120 |
+
$this->pagination( $which );
|
121 |
+
?>
|
122 |
+
<br class="clear" />
|
123 |
</div>
|
|
|
124 |
<?php
|
125 |
+
}
|
126 |
+
|
127 |
+
/**
|
128 |
+
* Table navigation.
|
129 |
+
*
|
130 |
+
* @param string $which - Position of the nav.
|
131 |
+
*/
|
132 |
+
public function extra_tablenav( $which ) {
|
133 |
+
// If the position is not top then render.
|
134 |
+
if ( 'top' !== $which ) :
|
135 |
+
// Items-per-page widget.
|
136 |
+
$p = $this->_plugin->settings->GetViewPerPage();
|
137 |
+
$items = array( 5, 10, 15, 30, 50 );
|
138 |
+
if ( ! in_array( $p, $items ) ) {
|
139 |
+
$items[] = $p;
|
140 |
+
}
|
141 |
+
?>
|
142 |
+
<div class="wsal-ipp wsal-ipp-<?php echo esc_attr( $which ); ?>">
|
143 |
+
<?php esc_html_e( 'Show ', 'wp-security-audit-log' ); ?>
|
144 |
+
<select class="wsal-ipps" onfocus="WsalIppsFocus(value);" onchange="WsalIppsChange(value);">
|
145 |
+
<?php foreach ( $items as $item ) { ?>
|
146 |
+
<option
|
147 |
+
value="<?php echo is_string( $item ) ? '' : esc_attr( $item ); ?>"
|
148 |
+
<?php echo ( $item == $p ) ? 'selected="selected"' : false; ?>>
|
149 |
+
<?php echo esc_html( $item ); ?>
|
150 |
+
</option>
|
151 |
+
<?php } ?>
|
152 |
+
</select>
|
153 |
+
<?php esc_html_e( ' Items', 'wp-security-audit-log' ); ?>
|
154 |
+
</div>
|
155 |
+
<?php
|
156 |
+
endif;
|
157 |
+
|
158 |
// Show site alerts widget.
|
159 |
if ( $this->is_multisite() && $this->is_main_blog() ) {
|
160 |
$curr = $this->get_view_site_id();
|
162 |
<div class="wsal-ssa wsal-ssa-<?php echo esc_attr( $which ); ?>">
|
163 |
<?php if ( $this->get_site_count() > 15 ) { ?>
|
164 |
<?php $curr = $curr ? get_blog_details( $curr ) : null; ?>
|
165 |
+
<?php $curr = $curr ? ( $curr->blogname . ' (' . $curr->domain . ')' ) : 'All Sites'; ?>
|
166 |
<input type="text" class="wsal-ssas" value="<?php echo esc_attr( $curr ); ?>"/>
|
167 |
<?php } else { ?>
|
168 |
<select class="wsal-ssas" onchange="WsalSsasChange(value);">
|
181 |
|
182 |
// Switch to live or archive DB.
|
183 |
if ( $this->_plugin->settings->IsArchivingEnabled() ) {
|
184 |
+
$selected = 'live';
|
185 |
$selected_db = get_transient( 'wsal_wp_selected_db' );
|
186 |
if ( $selected_db && 'archive' == $selected_db ) {
|
187 |
$selected = 'archive';
|
244 |
* @return array
|
245 |
*/
|
246 |
public function get_columns() {
|
247 |
+
// Get user information from settings.
|
248 |
$type_name = $this->_plugin->settings->get_type_username();
|
249 |
+
if ( 'display_name' === $type_name || 'first_last_name' === $type_name ) {
|
250 |
$name_column = __( 'User', 'wp-security-audit-log' );
|
251 |
} elseif ( 'username' === $type_name ) {
|
252 |
$name_column = __( 'Username', 'wp-security-audit-log' );
|
253 |
}
|
254 |
+
|
255 |
+
// Audit log columns.
|
256 |
$cols = array(
|
257 |
'type' => __( 'Event ID', 'wp-security-audit-log' ),
|
258 |
'code' => __( 'Severity', 'wp-security-audit-log' ),
|
260 |
'user' => $name_column,
|
261 |
'scip' => __( 'Source IP', 'wp-security-audit-log' ),
|
262 |
);
|
263 |
+
|
264 |
+
// If multisite then add "Site" column to the view.
|
265 |
if ( $this->is_multisite() && $this->is_main_blog() && ! $this->is_specific_view() ) {
|
266 |
$cols['site'] = __( 'Site', 'wp-security-audit-log' );
|
267 |
}
|
268 |
+
|
269 |
$cols['mesg'] = __( 'Message', 'wp-security-audit-log' );
|
270 |
+
|
271 |
+
// Get selected columns from settings.
|
272 |
$sel_columns = $this->_plugin->settings->GetColumnsSelected();
|
273 |
+
|
274 |
+
// If selected columns are not empty, then unset default columns.
|
275 |
if ( ! empty( $sel_columns ) ) {
|
276 |
unset( $cols );
|
277 |
$sel_columns = (array) json_decode( $sel_columns );
|
312 |
* @return string
|
313 |
*/
|
314 |
public function column_cb( $item ) {
|
315 |
+
return '<input type="checkbox" value="' . $item->id . '" name="' . esc_attr( $this->_args['singular'] ) . '[]" />';
|
|
|
316 |
}
|
317 |
|
318 |
/**
|
346 |
switch ( $column_name ) {
|
347 |
case 'read':
|
348 |
return '<span class="log-read log-read-'
|
349 |
+
. ( $item->is_read ? 'old' : 'new' )
|
350 |
. '" title="' . __( 'Click to toggle.', 'wp-security-audit-log' ) . '"></span>';
|
351 |
case 'type':
|
352 |
+
$code = $this->_plugin->alerts->GetAlert( $item->alert_id );
|
353 |
+
$extra_msg = '';
|
354 |
+
$data_link = '';
|
355 |
$modification_alerts = array( 1002, 1003, 6007, 6023 );
|
356 |
if ( in_array( $item->alert_id, $modification_alerts, true ) ) {
|
357 |
$extra_msg = '. Modify this alert.';
|
369 |
return '<span class="log-disable" data-disable-alert-nonce="' . wp_create_nonce( 'disable-alert-nonce' . $item->alert_id ) . '" data-tooltip="' . __( 'Disable this type of events.', 'wp-security-audit-log' ) . '<br>' . $item->alert_id . ' - ' . esc_html( $code->desc ) . $extra_msg . '" data-alert-id="' . $item->alert_id . '" ' . esc_attr( 'data-link=' . $data_link ) . ' >'
|
370 |
. str_pad( $item->alert_id, 4, '0', STR_PAD_LEFT ) . ' </span>';
|
371 |
case 'code':
|
372 |
+
$code = $this->_plugin->alerts->GetAlert( $item->alert_id );
|
373 |
+
$code = $code ? $code->code : 0;
|
374 |
$const = (object) array(
|
375 |
+
'name' => 'E_UNKNOWN',
|
376 |
+
'value' => 0,
|
377 |
'description' => __( 'Unknown error code.', 'wp-security-audit-log' ),
|
378 |
);
|
379 |
$const = $this->_plugin->constants->GetConstantBy( 'value', $code, $const );
|
380 |
+
if ( 'E_CRITICAL' === $const->name ) {
|
381 |
+
$const->name = __( 'Critical', 'wp-security-audit-log' );
|
382 |
+
} elseif ( 'E_WARNING' === $const->name ) {
|
383 |
+
$const->name = __( 'Warning', 'wp-security-audit-log' );
|
384 |
+
} elseif ( 'E_NOTICE' === $const->name ) {
|
385 |
+
$const->name = __( 'Notification', 'wp-security-audit-log' );
|
386 |
}
|
387 |
+
return '<a class="tooltip" href="#" data-tooltip="' . esc_html( $const->name ) . '"><span class="log-type log-type-' . $const->value . '"></span></a>';
|
|
|
388 |
case 'crtd':
|
389 |
return $item->created_on ? (
|
390 |
str_replace(
|
392 |
substr( number_format( fmod( $item->created_on + $this->_gmt_offset_sec, 1 ), 3 ), 2 ),
|
393 |
date( $datetime_format, $item->created_on + $this->_gmt_offset_sec )
|
394 |
)
|
395 |
+
) : '<i>' . __( 'Unknown', 'wp-security-audit-log' ) . '</i>';
|
396 |
case 'user':
|
397 |
+
$username = $item->GetUsername(); // Get username.
|
398 |
+
$type_name = $this->_plugin->settings->get_type_username(); // Get the data to display.
|
399 |
+
$user = get_user_by( 'login', $username ); // Get user.
|
400 |
|
401 |
// Check if the username and user exists.
|
402 |
if ( $username && $user ) {
|
403 |
+
// Get user avatar.
|
404 |
$image = get_avatar( $user->ID, 32 );
|
405 |
+
|
406 |
+
// Checks for display name.
|
407 |
+
if ( 'display_name' === $type_name && ! empty( $user->display_name ) ) {
|
408 |
+
$display_name = $user->display_name;
|
409 |
+
} elseif (
|
410 |
+
'first_last_name' === $type_name
|
411 |
+
&& ( ! empty( $user->first_name ) || ! empty( $user->last_name ) )
|
412 |
+
) {
|
413 |
$display_name = $user->first_name . ' ' . $user->last_name;
|
414 |
} else {
|
415 |
$display_name = $user->user_login;
|
482 |
if ( class_exists( 'WSAL_SearchExtension' ) ) {
|
483 |
$tooltip = esc_attr__( 'Show me all activity originating from this IP Address', 'wp-security-audit-log' );
|
484 |
|
485 |
+
$html = "<a class='search-ip' data-tooltip='$tooltip' data-ip='$scip' target='_blank' href='https://whatismyipaddress.com/ip/$scip'>" . esc_html( $scip ) . '</a> <a href="javascript:;" onclick="jQuery(this).hide().next().show();">(more…)</a><div style="display: none;">';
|
486 |
foreach ( $oips as $ip ) {
|
487 |
if ( $scip != $ip ) {
|
488 |
$html .= '<div>' . $ip . '</div>';
|
491 |
$html .= '</div>';
|
492 |
return $html;
|
493 |
} else {
|
494 |
+
$html = "<a target='_blank' href='https://whatismyipaddress.com/ip/$scip'>" . esc_html( $scip ) . '</a> <a href="javascript:;" onclick="jQuery(this).hide().next().show();">(more…)</a><div style="display: none;">';
|
495 |
foreach ( $oips as $ip ) {
|
496 |
if ( $scip != $ip ) {
|
497 |
$html .= '<div>' . $ip . '</div>';
|
503 |
|
504 |
case 'site':
|
505 |
$info = get_blog_details( $item->site_id, true );
|
506 |
+
return ! $info ? ( 'Unknown Site ' . $item->site_id )
|
507 |
+
: ( '<a href="' . esc_attr( $info->siteurl ) . '">' . esc_html( $info->blogname ) . '</a>' );
|
508 |
case 'mesg':
|
509 |
return '<div id="Event' . $item->id . '">' . $item->GetMessage( array( $this, 'meta_formatter' ) ) . '</div>';
|
510 |
case 'data':
|
511 |
+
$url = admin_url( 'admin-ajax.php' ) . '?action=AjaxInspector&occurrence=' . $item->id;
|
512 |
$tooltip = esc_attr__( 'View all details of this change', 'wp-security-audit-log' );
|
513 |
return '<a class="more-info thickbox" data-tooltip="' . $tooltip . '" title="' . __( 'Alert Data Inspector', 'wp-security-audit-log' ) . '"'
|
514 |
. ' href="' . $url . '&TB_iframe=true&width=600&height=550">…</a>';
|
598 |
|
599 |
case in_array( $name, array( '%MetaValue%', '%MetaValueOld%', '%MetaValueNew%' ) ):
|
600 |
return '<strong>' . (
|
601 |
+
strlen( $value ) > 50 ? ( esc_html( substr( $value, 0, 50 ) ) . '…' ) : esc_html( $value )
|
602 |
) . '</strong>';
|
603 |
|
604 |
case '%ClientIP%' == $name:
|
610 |
|
611 |
case '%LinkFile%' === $name:
|
612 |
if ( 'NULL' != $value ) {
|
613 |
+
$site_id = $this->get_view_site_id(); // Site id for multisite.
|
614 |
return '<a href="javascript:;" onclick="download_404_log( this )" data-log-file="' . esc_attr( $value ) . '" data-site-id="' . esc_attr( $site_id ) . '" data-nonce-404="' . esc_attr( wp_create_nonce( 'wsal-download-404-log-' . $value ) ) . '" title="' . esc_html__( 'Download the log file', 'wp-security-audit-log' ) . '">' . esc_html__( 'Download the log file', 'wp-security-audit-log' ) . '</a>';
|
615 |
} else {
|
616 |
return 'Click <a href="' . esc_url( admin_url( 'admin.php?page=wsal-togglealerts#tab-system-activity' ) ) . '">here</a> to log such requests to file';
|
691 |
* @return bool
|
692 |
*/
|
693 |
protected function is_specific_view() {
|
694 |
+
// Filter $_GET array for security.
|
695 |
+
$get_array = filter_input_array( INPUT_GET );
|
696 |
|
697 |
+
return isset( $get_array['wsal-cbid'] ) && '0' != $get_array['wsal-cbid'];
|
698 |
}
|
699 |
|
700 |
/**
|
703 |
* @return int
|
704 |
*/
|
705 |
protected function get_specific_view() {
|
706 |
+
// Filter $_GET array for security.
|
707 |
+
$get_array = filter_input_array( INPUT_GET );
|
708 |
|
709 |
+
return isset( $get_array['wsal-cbid'] ) ? (int) $get_array['wsal-cbid'] : 0;
|
710 |
}
|
711 |
|
712 |
/**
|
745 |
|
746 |
$per_page = $this->_plugin->settings->GetViewPerPage();
|
747 |
|
748 |
+
$columns = $this->get_columns();
|
749 |
+
$hidden = array();
|
750 |
$sortable = $this->get_sortable_columns();
|
751 |
|
752 |
$this->_column_headers = array( $columns, $hidden, $sortable );
|
802 |
// @todo Modify $query instead
|
803 |
// @deprecated
|
804 |
// $data = array_slice($data, ($this->get_pagenum() - 1) * $per_page, $per_page);
|
805 |
+
$query->setOffset( ( $this->get_pagenum() - 1 ) * $per_page );
|
806 |
$query->setLimit( $per_page );
|
807 |
|
808 |
$this->items = $query->getAdapter()->Execute( $query );
|
830 |
parent::single_row( $item );
|
831 |
}
|
832 |
}
|
833 |
+
|
834 |
+
/**
|
835 |
+
* Print column headers, accounting for hidden and sortable columns.
|
836 |
+
*
|
837 |
+
* @static var int $cb_counter
|
838 |
+
*
|
839 |
+
* @param bool $with_id – Whether to set the id attribute or not.
|
840 |
+
* @since 3.2.3
|
841 |
+
*/
|
842 |
+
public function print_column_headers( $with_id = true ) {
|
843 |
+
list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
|
844 |
+
|
845 |
+
$current_url = set_url_scheme( esc_url_raw( wp_unslash( $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ) ) );
|
846 |
+
$current_url = remove_query_arg( 'paged', $current_url );
|
847 |
+
|
848 |
+
// Get $_GET global array.
|
849 |
+
$get_array = filter_input_array( INPUT_GET );
|
850 |
+
if ( isset( $get_array['orderby'] ) ) {
|
851 |
+
$current_orderby = sanitize_text_field( $get_array['orderby'] );
|
852 |
+
} else {
|
853 |
+
$current_orderby = '';
|
854 |
+
}
|
855 |
+
|
856 |
+
if ( isset( $get_array['order'] ) && 'desc' === $get_array['order'] ) {
|
857 |
+
$current_order = 'desc';
|
858 |
+
} else {
|
859 |
+
$current_order = 'asc';
|
860 |
+
}
|
861 |
+
|
862 |
+
if ( ! empty( $columns['cb'] ) ) {
|
863 |
+
static $cb_counter = 1;
|
864 |
+
$columns['cb'] = '<label class="screen-reader-text" for="cb-select-all-' . $cb_counter . '">' . __( 'Select All' ) . '</label>'
|
865 |
+
. '<input id="cb-select-all-' . $cb_counter . '" type="checkbox" />';
|
866 |
+
$cb_counter++;
|
867 |
+
}
|
868 |
+
|
869 |
+
foreach ( $columns as $column_key => $column_display_name ) {
|
870 |
+
$class = array( 'manage-column', "column-$column_key" );
|
871 |
+
|
872 |
+
if ( in_array( $column_key, $hidden ) ) {
|
873 |
+
$class[] = 'hidden';
|
874 |
+
}
|
875 |
+
|
876 |
+
if ( 'cb' === $column_key ) {
|
877 |
+
$class[] = 'check-column';
|
878 |
+
} elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ) ) ) {
|
879 |
+
$class[] = 'num';
|
880 |
+
}
|
881 |
+
|
882 |
+
if ( $column_key === $primary ) {
|
883 |
+
$class[] = 'column-primary';
|
884 |
+
}
|
885 |
+
|
886 |
+
if ( isset( $sortable[ $column_key ] ) ) {
|
887 |
+
list( $orderby, $desc_first ) = $sortable[ $column_key ];
|
888 |
+
|
889 |
+
if ( $current_orderby === $orderby ) {
|
890 |
+
$order = 'asc' === $current_order ? 'desc' : 'asc';
|
891 |
+
$class[] = 'sorted';
|
892 |
+
$class[] = $current_order;
|
893 |
+
} else {
|
894 |
+
$order = $desc_first ? 'desc' : 'asc';
|
895 |
+
$class[] = 'sortable';
|
896 |
+
$class[] = $desc_first ? 'asc' : 'desc';
|
897 |
+
}
|
898 |
+
|
899 |
+
$column_display_name = '<a href="' . esc_url( add_query_arg( compact( 'orderby', 'order' ), $current_url ) ) . '"><span>' . $column_display_name . '</span><span class="sorting-indicator"></span></a>';
|
900 |
+
}
|
901 |
+
|
902 |
+
$tag = ( 'cb' === $column_key ) ? 'td' : 'th';
|
903 |
+
$scope = ( 'th' === $tag ) ? 'scope="col"' : '';
|
904 |
+
$id = $with_id ? "id='$column_key'" : '';
|
905 |
+
|
906 |
+
if ( ! empty( $class ) ) {
|
907 |
+
$class = "class='" . join( ' ', $class ) . "'";
|
908 |
+
}
|
909 |
+
|
910 |
+
echo "<$tag $scope $id $class>";
|
911 |
+
|
912 |
+
echo $column_display_name;
|
913 |
+
|
914 |
+
if ( $with_id ) {
|
915 |
+
/**
|
916 |
+
* Action: `wsal_audit_log_column_header`
|
917 |
+
*
|
918 |
+
* Action hook to add search filters in the audit log
|
919 |
+
* column headers.
|
920 |
+
*
|
921 |
+
* @param string $column_key – Column key.
|
922 |
+
*/
|
923 |
+
do_action( 'wsal_audit_log_column_header', $column_key );
|
924 |
+
}
|
925 |
+
|
926 |
+
echo "</$tag>";
|
927 |
+
}
|
928 |
+
}
|
929 |
}
|
classes/Connector/ConnectorFactory.php
CHANGED
@@ -127,7 +127,7 @@ abstract class WSAL_Connector_ConnectorFactory {
|
|
127 |
// TO DO: Add other connectors.
|
128 |
case 'mysql':
|
129 |
default:
|
130 |
-
$test
|
131 |
$result = $test->TestConnection();
|
132 |
}
|
133 |
return $result;
|
127 |
// TO DO: Add other connectors.
|
128 |
case 'mysql':
|
129 |
default:
|
130 |
+
$test = new WSAL_Connector_MySQLDB( $config );
|
131 |
$result = $test->TestConnection();
|
132 |
}
|
133 |
return $result;
|
classes/Connector/MySQLDB.php
CHANGED
@@ -43,16 +43,19 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
|
|
43 |
* Test the connection.
|
44 |
*
|
45 |
* @throws Exception - Connection failed.
|
|
|
46 |
*/
|
47 |
public function TestConnection() {
|
48 |
-
error_reporting( E_ALL ^ (E_NOTICE | E_WARNING | E_DEPRECATED) );
|
49 |
$connection_config = $this->connectionConfig;
|
50 |
-
$password
|
51 |
-
$new_wpdb
|
52 |
|
53 |
// Database Error.
|
54 |
if ( ! $new_wpdb->has_connected ) {
|
55 |
throw new Exception( 'Connection failed. Please check your connection details.' );
|
|
|
|
|
56 |
}
|
57 |
}
|
58 |
|
@@ -65,8 +68,8 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
|
|
65 |
if ( ! empty( $this->connectionConfig ) ) {
|
66 |
// TO DO: Use the provided connection config.
|
67 |
$connection_config = $this->connectionConfig;
|
68 |
-
$password
|
69 |
-
$new_wpdb
|
70 |
$new_wpdb->set_prefix( $connection_config['base_prefix'] );
|
71 |
return $new_wpdb;
|
72 |
} else {
|
@@ -685,4 +688,30 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
|
|
685 |
return $secret_openssl_iv;
|
686 |
}
|
687 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
688 |
}
|
43 |
* Test the connection.
|
44 |
*
|
45 |
* @throws Exception - Connection failed.
|
46 |
+
* @return bool
|
47 |
*/
|
48 |
public function TestConnection() {
|
49 |
+
error_reporting( E_ALL ^ ( E_NOTICE | E_WARNING | E_DEPRECATED ) );
|
50 |
$connection_config = $this->connectionConfig;
|
51 |
+
$password = $this->decryptString( $connection_config['password'] );
|
52 |
+
$new_wpdb = new wpdbCustom( $connection_config['user'], $password, $connection_config['name'], $connection_config['hostname'], $connection_config['is_ssl'], $connection_config['is_cc'], $connection_config['ssl_ca'], $connection_config['ssl_cert'], $connection_config['ssl_key'], true );
|
53 |
|
54 |
// Database Error.
|
55 |
if ( ! $new_wpdb->has_connected ) {
|
56 |
throw new Exception( 'Connection failed. Please check your connection details.' );
|
57 |
+
} else {
|
58 |
+
return true;
|
59 |
}
|
60 |
}
|
61 |
|
68 |
if ( ! empty( $this->connectionConfig ) ) {
|
69 |
// TO DO: Use the provided connection config.
|
70 |
$connection_config = $this->connectionConfig;
|
71 |
+
$password = $this->decryptString( $connection_config['password'] );
|
72 |
+
$new_wpdb = new wpdbCustom( $connection_config['user'], $password, $connection_config['name'], $connection_config['hostname'], $connection_config['is_ssl'], $connection_config['is_cc'], $connection_config['ssl_ca'], $connection_config['ssl_cert'], $connection_config['ssl_key'] );
|
73 |
$new_wpdb->set_prefix( $connection_config['base_prefix'] );
|
74 |
return $new_wpdb;
|
75 |
} else {
|
688 |
return $secret_openssl_iv;
|
689 |
}
|
690 |
}
|
691 |
+
|
692 |
+
/**
|
693 |
+
* Purge plugin occurrence & meta tables.
|
694 |
+
*
|
695 |
+
* @return bool
|
696 |
+
*/
|
697 |
+
public function purge_activity() {
|
698 |
+
// Get connection.
|
699 |
+
$wpdb = $this->getConnection();
|
700 |
+
|
701 |
+
// Get occurrence model.
|
702 |
+
$occ = new WSAL_Adapters_MySQL_Occurrence( $wpdb );
|
703 |
+
$sql = 'TRUNCATE ' . $occ->GetTable();
|
704 |
+
$query_occ = $wpdb->query( $sql );
|
705 |
+
|
706 |
+
// Get meta model.
|
707 |
+
$meta = new WSAL_Adapters_MySQL_Meta( $wpdb );
|
708 |
+
$sql = 'TRUNCATE ' . $meta->GetTable();
|
709 |
+
$query_meta = $wpdb->query( $sql );
|
710 |
+
|
711 |
+
// If both queries are successful, then return true.
|
712 |
+
if ( $query_occ && $query_meta ) {
|
713 |
+
return true;
|
714 |
+
}
|
715 |
+
return false;
|
716 |
+
}
|
717 |
}
|
classes/SensorManager.php
CHANGED
@@ -37,6 +37,9 @@ final class WSAL_SensorManager extends WSAL_AbstractSensor {
|
|
37 |
public function __construct( WpSecurityAuditLog $plugin ) {
|
38 |
parent::__construct( $plugin );
|
39 |
|
|
|
|
|
|
|
40 |
foreach ( glob( dirname( __FILE__ ) . '/Sensors/*.php' ) as $file ) {
|
41 |
$this->AddFromFile( $file );
|
42 |
}
|
@@ -44,15 +47,15 @@ final class WSAL_SensorManager extends WSAL_AbstractSensor {
|
|
44 |
/**
|
45 |
* Load Custom Sensor files from /wp-content/uploads/wp-security-audit-log/custom-sensors/
|
46 |
*/
|
47 |
-
$upload_dir
|
48 |
$uploads_dir_path = trailingslashit( $upload_dir['basedir'] ) . 'wp-security-audit-log' . DIRECTORY_SEPARATOR . 'custom-sensors' . DIRECTORY_SEPARATOR;
|
49 |
|
50 |
// Check directory.
|
51 |
if ( is_dir( $uploads_dir_path ) && is_readable( $uploads_dir_path ) ) {
|
52 |
foreach ( glob( $uploads_dir_path . '*.php' ) as $file ) {
|
53 |
// Include custom sensor file.
|
54 |
-
require_once
|
55 |
-
$file
|
56 |
$sensor = str_replace( $uploads_dir_path, '', $file );
|
57 |
|
58 |
// Skip if the file is index.php for security.
|
@@ -89,7 +92,20 @@ final class WSAL_SensorManager extends WSAL_AbstractSensor {
|
|
89 |
* @param string $file Path to file.
|
90 |
*/
|
91 |
public function AddFromFile( $file ) {
|
92 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
93 |
}
|
94 |
|
95 |
/**
|
@@ -109,4 +125,126 @@ final class WSAL_SensorManager extends WSAL_AbstractSensor {
|
|
109 |
public function AddInstance( WSAL_AbstractSensor $sensor ) {
|
110 |
$this->sensors[] = $sensor;
|
111 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
112 |
}
|
37 |
public function __construct( WpSecurityAuditLog $plugin ) {
|
38 |
parent::__construct( $plugin );
|
39 |
|
40 |
+
// Check sensors before loading for optimization.
|
41 |
+
add_filter( 'wsal_before_sensor_load', array( $this, 'check_sensor_before_load' ), 10, 2 );
|
42 |
+
|
43 |
foreach ( glob( dirname( __FILE__ ) . '/Sensors/*.php' ) as $file ) {
|
44 |
$this->AddFromFile( $file );
|
45 |
}
|
47 |
/**
|
48 |
* Load Custom Sensor files from /wp-content/uploads/wp-security-audit-log/custom-sensors/
|
49 |
*/
|
50 |
+
$upload_dir = wp_upload_dir();
|
51 |
$uploads_dir_path = trailingslashit( $upload_dir['basedir'] ) . 'wp-security-audit-log' . DIRECTORY_SEPARATOR . 'custom-sensors' . DIRECTORY_SEPARATOR;
|
52 |
|
53 |
// Check directory.
|
54 |
if ( is_dir( $uploads_dir_path ) && is_readable( $uploads_dir_path ) ) {
|
55 |
foreach ( glob( $uploads_dir_path . '*.php' ) as $file ) {
|
56 |
// Include custom sensor file.
|
57 |
+
require_once $file;
|
58 |
+
$file = substr( $file, 0, -4 );
|
59 |
$sensor = str_replace( $uploads_dir_path, '', $file );
|
60 |
|
61 |
// Skip if the file is index.php for security.
|
92 |
* @param string $file Path to file.
|
93 |
*/
|
94 |
public function AddFromFile( $file ) {
|
95 |
+
/**
|
96 |
+
* Filter: `wsal_before_sensor_load`
|
97 |
+
*
|
98 |
+
* Check to see if sensor is to be initiaited or not.
|
99 |
+
*
|
100 |
+
* @param bool $load_sensor – Set to true if sensor is to be loaded.
|
101 |
+
* @param string $file – File path.
|
102 |
+
*/
|
103 |
+
$load_sensor = apply_filters( 'wsal_before_sensor_load', true, $file );
|
104 |
+
|
105 |
+
// Initiate the sensor if $load_sensor is true.
|
106 |
+
if ( $load_sensor ) {
|
107 |
+
$this->AddFromClass( $this->plugin->GetClassFileClassName( $file ) );
|
108 |
+
}
|
109 |
}
|
110 |
|
111 |
/**
|
125 |
public function AddInstance( WSAL_AbstractSensor $sensor ) {
|
126 |
$this->sensors[] = $sensor;
|
127 |
}
|
128 |
+
|
129 |
+
/**
|
130 |
+
* Check sensor before loading.
|
131 |
+
*
|
132 |
+
* @param bool $load_sensor – Whether to load sensor or not.
|
133 |
+
* @param string $filepath – File path.
|
134 |
+
* @return bool
|
135 |
+
*/
|
136 |
+
public function check_sensor_before_load( $load_sensor, $filepath ) {
|
137 |
+
global $pagenow;
|
138 |
+
|
139 |
+
// WSAL views array.
|
140 |
+
$wsal_views = array(
|
141 |
+
'wsal-auditlog',
|
142 |
+
'wsal-togglealerts',
|
143 |
+
'wsal-settings',
|
144 |
+
'wsal-emailnotifications',
|
145 |
+
'wsal-loginusers',
|
146 |
+
'wsal-reports',
|
147 |
+
'wsal-search',
|
148 |
+
'wsal-externaldb',
|
149 |
+
'wsal-user-management-views',
|
150 |
+
'wsal-rep-views-main',
|
151 |
+
'wsal-np-notifications',
|
152 |
+
'wsal-np-addnotification',
|
153 |
+
'wsal-np-editnotification',
|
154 |
+
'wsal-ext-settings',
|
155 |
+
'wsal-help',
|
156 |
+
'wsal-auditlog-account',
|
157 |
+
'wsal-auditlog-contact',
|
158 |
+
'wsal-auditlog-pricing',
|
159 |
+
);
|
160 |
+
|
161 |
+
// Get current page query argument via $_GET array.
|
162 |
+
$current_page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
|
163 |
+
|
164 |
+
// Check these conditions before loading sensors.
|
165 |
+
if (
|
166 |
+
is_admin()
|
167 |
+
&& (
|
168 |
+
in_array( $current_page, $wsal_views, true ) // WSAL Views.
|
169 |
+
|| 'index.php' === $pagenow // Dashboard.
|
170 |
+
|| 'tools.php' === $pagenow // Tools page.
|
171 |
+
|| 'export.php' === $pagenow // Export page.
|
172 |
+
|| 'import.php' === $pagenow // Import page.
|
173 |
+
)
|
174 |
+
) {
|
175 |
+
return false;
|
176 |
+
}
|
177 |
+
|
178 |
+
// Get file name.
|
179 |
+
$filename = basename( $filepath, '.php' );
|
180 |
+
|
181 |
+
// If filename exists then continue.
|
182 |
+
if ( $filename ) {
|
183 |
+
// Conditional loading based on filename.
|
184 |
+
switch ( $filename ) {
|
185 |
+
case 'BBPress':
|
186 |
+
// Check if BBPress plugin exists.
|
187 |
+
if ( ! is_plugin_active( 'bbpress/bbpress.php' ) ) {
|
188 |
+
$load_sensor = false;
|
189 |
+
}
|
190 |
+
break;
|
191 |
+
|
192 |
+
case 'WooCommerce':
|
193 |
+
// Check if WooCommerce plugin exists.
|
194 |
+
if ( ! is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
|
195 |
+
$load_sensor = false;
|
196 |
+
}
|
197 |
+
break;
|
198 |
+
|
199 |
+
case 'YoastSEO':
|
200 |
+
// Check if Yoast SEO plugin exists.
|
201 |
+
if ( ! is_plugin_active( 'wordpress-seo/wp-seo.php' ) ) {
|
202 |
+
$load_sensor = false;
|
203 |
+
}
|
204 |
+
break;
|
205 |
+
|
206 |
+
case 'Multisite':
|
207 |
+
// If site is not multisite then don't load it.
|
208 |
+
if ( ! $this->plugin->IsMultisite() ) {
|
209 |
+
$load_sensor = false;
|
210 |
+
}
|
211 |
+
break;
|
212 |
+
|
213 |
+
case 'Menus':
|
214 |
+
// If the current page is not Menus page in themes tab or customizer then don't load menu sensor.
|
215 |
+
if ( 'nav-menus.php' === $pagenow || 'customize.php' === $pagenow ) {
|
216 |
+
$load_sensor = true;
|
217 |
+
} else {
|
218 |
+
$load_sensor = false;
|
219 |
+
}
|
220 |
+
break;
|
221 |
+
|
222 |
+
case 'Widgets':
|
223 |
+
// If the current page is not Widgets page in themes tab or customizer then don't load menu sensor.
|
224 |
+
if ( 'widgets.php' === $pagenow || 'customize.php' === $pagenow || 'admin-ajax.php' === $pagenow ) {
|
225 |
+
$load_sensor = true;
|
226 |
+
} else {
|
227 |
+
$load_sensor = false;
|
228 |
+
}
|
229 |
+
break;
|
230 |
+
|
231 |
+
case 'FileChanges':
|
232 |
+
// If file changes is disabled then don't load file changes sensor.
|
233 |
+
if ( 'enable' !== $this->plugin->GetGlobalOption( 'scan-file-changes', 'enable' ) ) {
|
234 |
+
$load_sensor = false;
|
235 |
+
|
236 |
+
// Clear scheduled hook if there is any hook scheduled.
|
237 |
+
if ( wp_next_scheduled( WSAL_Sensors_FileChanges::$schedule_hook ) ) {
|
238 |
+
wp_clear_scheduled_hook( WSAL_Sensors_FileChanges::$schedule_hook );
|
239 |
+
}
|
240 |
+
}
|
241 |
+
break;
|
242 |
+
|
243 |
+
default:
|
244 |
+
break;
|
245 |
+
}
|
246 |
+
}
|
247 |
+
|
248 |
+
return $load_sensor;
|
249 |
+
}
|
250 |
}
|
classes/Sensors/BBPress.php
CHANGED
@@ -52,11 +52,6 @@ class WSAL_Sensors_BBPress extends WSAL_AbstractSensor {
|
|
52 |
* Listening to events using WP hooks.
|
53 |
*/
|
54 |
public function HookEvents() {
|
55 |
-
// Check if BBPress plugin exists.
|
56 |
-
if ( ! is_plugin_active( 'bbpress/bbpress.php' ) ) {
|
57 |
-
return false;
|
58 |
-
}
|
59 |
-
|
60 |
if ( current_user_can( 'edit_posts' ) ) {
|
61 |
add_action( 'admin_init', array( $this, 'EventAdminInit' ) );
|
62 |
}
|
52 |
* Listening to events using WP hooks.
|
53 |
*/
|
54 |
public function HookEvents() {
|
|
|
|
|
|
|
|
|
|
|
55 |
if ( current_user_can( 'edit_posts' ) ) {
|
56 |
add_action( 'admin_init', array( $this, 'EventAdminInit' ) );
|
57 |
}
|
classes/Sensors/FileChanges.php
CHANGED
@@ -71,7 +71,7 @@ class WSAL_Sensors_FileChanges extends WSAL_AbstractSensor {
|
|
71 |
*
|
72 |
* @var string
|
73 |
*/
|
74 |
-
|
75 |
|
76 |
/**
|
77 |
* Scan files counter during a scan.
|
@@ -90,9 +90,9 @@ class WSAL_Sensors_FileChanges extends WSAL_AbstractSensor {
|
|
90 |
/**
|
91 |
* Class constants.
|
92 |
*/
|
93 |
-
const SCAN_DAILY
|
94 |
-
const SCAN_WEEKLY
|
95 |
-
const SCAN_MONTHLY
|
96 |
const SCAN_FILE_LIMIT = 1000000;
|
97 |
|
98 |
/**
|
@@ -161,7 +161,7 @@ class WSAL_Sensors_FileChanges extends WSAL_AbstractSensor {
|
|
161 |
'scan_date' => $this->plugin->GetGlobalOption( 'scan-date', '10' ),
|
162 |
'scan_directories' => $this->plugin->GetGlobalOption( 'scan-directories', $default_scan_dirs ),
|
163 |
'excluded_dirs' => $this->plugin->GetGlobalOption( 'scan-excluded-directories', array() ),
|
164 |
-
'excluded_extensions' => $this->plugin->GetGlobalOption( 'scan-excluded-extensions', array( 'jpg', 'jpeg', 'png', 'bmp', 'pdf', 'txt', 'log', 'mo', 'po', 'mp3', 'wav' ) ),
|
165 |
'excluded_files' => $this->plugin->GetGlobalOption( 'scan_excluded_files', array() ),
|
166 |
'last_scanned' => $this->plugin->GetGlobalOption( 'last-scanned', false ),
|
167 |
);
|
@@ -169,8 +169,8 @@ class WSAL_Sensors_FileChanges extends WSAL_AbstractSensor {
|
|
169 |
// Set the scan hours.
|
170 |
if ( ! empty( $this->scan_settings['scan_hour'] ) ) {
|
171 |
$saved_hour = (int) $this->scan_settings['scan_hour'];
|
172 |
-
$next_hour
|
173 |
-
$hours
|
174 |
foreach ( $hours as $hour ) {
|
175 |
$daily_hour[] = str_pad( $hour, 2, '0', STR_PAD_LEFT );
|
176 |
}
|
@@ -258,7 +258,7 @@ class WSAL_Sensors_FileChanges extends WSAL_AbstractSensor {
|
|
258 |
}
|
259 |
|
260 |
// Set the options name for file list.
|
261 |
-
$file_list = "
|
262 |
|
263 |
// Prepare directories array.
|
264 |
// @todo Store this in transient to cache the value. We don't need to load it every time.
|
@@ -277,7 +277,7 @@ class WSAL_Sensors_FileChanges extends WSAL_AbstractSensor {
|
|
277 |
|
278 |
// Prepare directories path.
|
279 |
foreach ( $server_dirs as $index => $server_dir ) {
|
280 |
-
$server_dir
|
281 |
$server_dirs[ $index ] = preg_replace( '/^' . preg_quote( ABSPATH, '/' ) . '/', '', $server_dir );
|
282 |
}
|
283 |
|
@@ -291,7 +291,7 @@ class WSAL_Sensors_FileChanges extends WSAL_AbstractSensor {
|
|
291 |
$this->excludes = $server_dirs;
|
292 |
|
293 |
// Get list of files to scan from DB.
|
294 |
-
$stored_files =
|
295 |
|
296 |
/**
|
297 |
* `Filter`: Stored files filter.
|
@@ -341,10 +341,10 @@ class WSAL_Sensors_FileChanges extends WSAL_AbstractSensor {
|
|
341 |
do_action( 'wsal_after_file_scan', $path_to_scan );
|
342 |
|
343 |
// Get initial scan setting.
|
344 |
-
$initial_scan =
|
345 |
|
346 |
// If the scan is not initial then.
|
347 |
-
if (
|
348 |
// Compare the results to find out about file added and removed.
|
349 |
$files_added = array_diff_key( $filtered_scanned_files, $filtered_stored_files );
|
350 |
$files_removed = array_diff_key( $filtered_stored_files, $filtered_scanned_files );
|
@@ -483,11 +483,11 @@ class WSAL_Sensors_FileChanges extends WSAL_AbstractSensor {
|
|
483 |
*/
|
484 |
do_action( 'wsal_last_scanned_directory', $next_to_scan );
|
485 |
} else {
|
486 |
-
|
487 |
}
|
488 |
|
489 |
// Store scanned files list.
|
490 |
-
|
491 |
|
492 |
if ( ! $manual ) {
|
493 |
$this->plugin->SetGlobalOption( 'scanned_dirs', $scanned_dirs );
|
@@ -527,7 +527,7 @@ class WSAL_Sensors_FileChanges extends WSAL_AbstractSensor {
|
|
527 |
|
528 |
// Set the directory path.
|
529 |
$dir_path = $this->root_path . $path;
|
530 |
-
$files
|
531 |
|
532 |
// Open directory.
|
533 |
$dir_handle = @opendir( $dir_path );
|
@@ -537,7 +537,7 @@ class WSAL_Sensors_FileChanges extends WSAL_AbstractSensor {
|
|
537 |
|
538 |
// Multsite checks.
|
539 |
$is_multisite = is_multisite();
|
540 |
-
$directories
|
541 |
|
542 |
// Scan the directory for files.
|
543 |
while ( false !== ( $item = @readdir( $dir_handle ) ) ) {
|
@@ -840,8 +840,8 @@ class WSAL_Sensors_FileChanges extends WSAL_AbstractSensor {
|
|
840 |
* Scan start checks:
|
841 |
* 1. Check frequency is not empty.
|
842 |
* 2. Check if there is any directory left to scan.
|
843 |
-
*
|
844 |
-
*
|
845 |
* 3. Check frequency of the scan set by user and decide to start the scan or not.
|
846 |
*
|
847 |
* @param string $frequency - Frequency of the scan.
|
@@ -892,7 +892,7 @@ class WSAL_Sensors_FileChanges extends WSAL_AbstractSensor {
|
|
892 |
break;
|
893 |
case self::SCAN_WEEKLY: // Weekly scan.
|
894 |
$weekly_day = $this->calculate_weekly_day();
|
895 |
-
$scan
|
896 |
break;
|
897 |
case self::SCAN_MONTHLY: // Monthly scan.
|
898 |
$str_date = $this->calculate_monthly_day();
|
71 |
*
|
72 |
* @var string
|
73 |
*/
|
74 |
+
public static $schedule_hook = 'wsal_detect_file_changes';
|
75 |
|
76 |
/**
|
77 |
* Scan files counter during a scan.
|
90 |
/**
|
91 |
* Class constants.
|
92 |
*/
|
93 |
+
const SCAN_DAILY = 'daily';
|
94 |
+
const SCAN_WEEKLY = 'weekly';
|
95 |
+
const SCAN_MONTHLY = 'monthly';
|
96 |
const SCAN_FILE_LIMIT = 1000000;
|
97 |
|
98 |
/**
|
161 |
'scan_date' => $this->plugin->GetGlobalOption( 'scan-date', '10' ),
|
162 |
'scan_directories' => $this->plugin->GetGlobalOption( 'scan-directories', $default_scan_dirs ),
|
163 |
'excluded_dirs' => $this->plugin->GetGlobalOption( 'scan-excluded-directories', array() ),
|
164 |
+
'excluded_extensions' => $this->plugin->GetGlobalOption( 'scan-excluded-extensions', array( 'jpg', 'jpeg', 'png', 'bmp', 'pdf', 'txt', 'log', 'mo', 'po', 'mp3', 'wav', 'gif', 'ico', 'jpe', 'psd', 'raw', 'svg', 'tif', 'tiff', 'aif', 'flac', 'm4a', 'oga', 'ogg', 'ra', 'wma', 'asf', 'avi', 'mkv', 'mov', 'mp4', 'mpe', 'mpeg', 'mpg', 'ogv', 'qt', 'rm', 'vob', 'webm', 'wm', 'wmv' ) ),
|
165 |
'excluded_files' => $this->plugin->GetGlobalOption( 'scan_excluded_files', array() ),
|
166 |
'last_scanned' => $this->plugin->GetGlobalOption( 'last-scanned', false ),
|
167 |
);
|
169 |
// Set the scan hours.
|
170 |
if ( ! empty( $this->scan_settings['scan_hour'] ) ) {
|
171 |
$saved_hour = (int) $this->scan_settings['scan_hour'];
|
172 |
+
$next_hour = $saved_hour + 1;
|
173 |
+
$hours = array( $saved_hour, $next_hour );
|
174 |
foreach ( $hours as $hour ) {
|
175 |
$daily_hour[] = str_pad( $hour, 2, '0', STR_PAD_LEFT );
|
176 |
}
|
258 |
}
|
259 |
|
260 |
// Set the options name for file list.
|
261 |
+
$file_list = "local_files_$next_to_scan";
|
262 |
|
263 |
// Prepare directories array.
|
264 |
// @todo Store this in transient to cache the value. We don't need to load it every time.
|
277 |
|
278 |
// Prepare directories path.
|
279 |
foreach ( $server_dirs as $index => $server_dir ) {
|
280 |
+
$server_dir = untrailingslashit( $server_dir );
|
281 |
$server_dirs[ $index ] = preg_replace( '/^' . preg_quote( ABSPATH, '/' ) . '/', '', $server_dir );
|
282 |
}
|
283 |
|
291 |
$this->excludes = $server_dirs;
|
292 |
|
293 |
// Get list of files to scan from DB.
|
294 |
+
$stored_files = $this->plugin->GetGlobalOption( $file_list, array() );
|
295 |
|
296 |
/**
|
297 |
* `Filter`: Stored files filter.
|
341 |
do_action( 'wsal_after_file_scan', $path_to_scan );
|
342 |
|
343 |
// Get initial scan setting.
|
344 |
+
$initial_scan = $this->plugin->GetGlobalOption( "is_initial_scan_$next_to_scan", 'yes' );
|
345 |
|
346 |
// If the scan is not initial then.
|
347 |
+
if ( 'yes' !== $initial_scan ) {
|
348 |
// Compare the results to find out about file added and removed.
|
349 |
$files_added = array_diff_key( $filtered_scanned_files, $filtered_stored_files );
|
350 |
$files_removed = array_diff_key( $filtered_stored_files, $filtered_scanned_files );
|
483 |
*/
|
484 |
do_action( 'wsal_last_scanned_directory', $next_to_scan );
|
485 |
} else {
|
486 |
+
$this->plugin->SetGlobalOption( "is_initial_scan_$next_to_scan", 'no' ); // Initial scan check set to false.
|
487 |
}
|
488 |
|
489 |
// Store scanned files list.
|
490 |
+
$this->plugin->SetGlobalOption( $file_list, $scanned_files );
|
491 |
|
492 |
if ( ! $manual ) {
|
493 |
$this->plugin->SetGlobalOption( 'scanned_dirs', $scanned_dirs );
|
527 |
|
528 |
// Set the directory path.
|
529 |
$dir_path = $this->root_path . $path;
|
530 |
+
$files = array(); // Array of files to return.
|
531 |
|
532 |
// Open directory.
|
533 |
$dir_handle = @opendir( $dir_path );
|
537 |
|
538 |
// Multsite checks.
|
539 |
$is_multisite = is_multisite();
|
540 |
+
$directories = $this->scan_settings['scan_directories']; // Get directories to be scanned.
|
541 |
|
542 |
// Scan the directory for files.
|
543 |
while ( false !== ( $item = @readdir( $dir_handle ) ) ) {
|
840 |
* Scan start checks:
|
841 |
* 1. Check frequency is not empty.
|
842 |
* 2. Check if there is any directory left to scan.
|
843 |
+
* 2a. If there is a directory left, then proceed to check frequency.
|
844 |
+
* 2b. Else check if 24 hrs limit is passed or not.
|
845 |
* 3. Check frequency of the scan set by user and decide to start the scan or not.
|
846 |
*
|
847 |
* @param string $frequency - Frequency of the scan.
|
892 |
break;
|
893 |
case self::SCAN_WEEKLY: // Weekly scan.
|
894 |
$weekly_day = $this->calculate_weekly_day();
|
895 |
+
$scan = ( self::$weekly_day === $weekly_day ) ? true : false;
|
896 |
break;
|
897 |
case self::SCAN_MONTHLY: // Monthly scan.
|
898 |
$str_date = $this->calculate_monthly_day();
|
classes/Sensors/MetaData.php
CHANGED
@@ -466,12 +466,14 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
|
|
466 |
|
467 |
// If update action is set then trigger the alert.
|
468 |
if ( isset( $post_array['action'] ) && ( 'update' == $post_array['action'] || 'createuser' == $post_array['action'] ) ) {
|
469 |
-
$this->plugin->alerts->
|
470 |
-
4016,
|
|
|
471 |
'TargetUsername' => $user->user_login,
|
472 |
'custom_field_name' => $meta_key,
|
473 |
'new_value' => $meta_value,
|
474 |
-
)
|
|
|
475 |
);
|
476 |
}
|
477 |
}
|
@@ -485,8 +487,11 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
|
|
485 |
*/
|
486 |
public function event_user_meta_updating( $meta_id, $object_id, $meta_key ) {
|
487 |
static $meta_type = 'user';
|
|
|
|
|
|
|
488 |
$this->old_meta[ $meta_id ] = (object) array(
|
489 |
-
'key' => ( $meta
|
490 |
'val' => get_metadata( $meta_type, $object_id, $meta_key, true ),
|
491 |
);
|
492 |
}
|
@@ -534,14 +539,16 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
|
|
534 |
if ( isset( $this->old_meta[ $meta_id ] ) && ! in_array( $meta_key, $username_meta, true ) ) {
|
535 |
// Check change in meta value.
|
536 |
if ( $this->old_meta[ $meta_id ]->val != $meta_value ) {
|
537 |
-
$this->plugin->alerts->
|
538 |
-
4015,
|
|
|
539 |
'TargetUsername' => $user->user_login,
|
540 |
'custom_field_name' => $meta_key,
|
541 |
-
'new_value'
|
542 |
-
'old_value'
|
543 |
-
'ReportText'
|
544 |
-
)
|
|
|
545 |
);
|
546 |
}
|
547 |
// Remove old meta update data.
|
@@ -604,7 +611,7 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
|
|
604 |
$old_display_name = $old_user_data->display_name;
|
605 |
|
606 |
// Get user's current data.
|
607 |
-
$new_userdata
|
608 |
$new_display_name = $new_userdata->display_name;
|
609 |
|
610 |
// Alert if display name is changed.
|
@@ -617,6 +624,29 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
|
|
617 |
)
|
618 |
);
|
619 |
}
|
|
|
620 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
621 |
}
|
622 |
}
|
466 |
|
467 |
// If update action is set then trigger the alert.
|
468 |
if ( isset( $post_array['action'] ) && ( 'update' == $post_array['action'] || 'createuser' == $post_array['action'] ) ) {
|
469 |
+
$this->plugin->alerts->TriggerIf(
|
470 |
+
4016,
|
471 |
+
array(
|
472 |
'TargetUsername' => $user->user_login,
|
473 |
'custom_field_name' => $meta_key,
|
474 |
'new_value' => $meta_value,
|
475 |
+
),
|
476 |
+
array( $this, 'must_not_contain_new_user_alert' )
|
477 |
);
|
478 |
}
|
479 |
}
|
487 |
*/
|
488 |
public function event_user_meta_updating( $meta_id, $object_id, $meta_key ) {
|
489 |
static $meta_type = 'user';
|
490 |
+
$meta = get_metadata_by_mid( $meta_type, $meta_id );
|
491 |
+
|
492 |
+
// Set old meta array.
|
493 |
$this->old_meta[ $meta_id ] = (object) array(
|
494 |
+
'key' => ( $meta ) ? $meta->meta_key : $meta_key,
|
495 |
'val' => get_metadata( $meta_type, $object_id, $meta_key, true ),
|
496 |
);
|
497 |
}
|
539 |
if ( isset( $this->old_meta[ $meta_id ] ) && ! in_array( $meta_key, $username_meta, true ) ) {
|
540 |
// Check change in meta value.
|
541 |
if ( $this->old_meta[ $meta_id ]->val != $meta_value ) {
|
542 |
+
$this->plugin->alerts->TriggerIf(
|
543 |
+
4015,
|
544 |
+
array(
|
545 |
'TargetUsername' => $user->user_login,
|
546 |
'custom_field_name' => $meta_key,
|
547 |
+
'new_value' => $meta_value,
|
548 |
+
'old_value' => $this->old_meta[ $meta_id ]->val,
|
549 |
+
'ReportText' => $this->old_meta[ $meta_id ]->val . '|' . $meta_value,
|
550 |
+
),
|
551 |
+
array( $this, 'must_not_contain_role_changes' )
|
552 |
);
|
553 |
}
|
554 |
// Remove old meta update data.
|
611 |
$old_display_name = $old_user_data->display_name;
|
612 |
|
613 |
// Get user's current data.
|
614 |
+
$new_userdata = get_userdata( $user_id );
|
615 |
$new_display_name = $new_userdata->display_name;
|
616 |
|
617 |
// Alert if display name is changed.
|
624 |
)
|
625 |
);
|
626 |
}
|
627 |
+
}
|
628 |
|
629 |
+
/**
|
630 |
+
* Method: This function make sures that alert 4002
|
631 |
+
* has not been triggered before updating user meta.
|
632 |
+
*
|
633 |
+
* @param WSAL_AlertManager $manager - WSAL Alert Manager.
|
634 |
+
* @return bool
|
635 |
+
* @since 3.2.3
|
636 |
+
*/
|
637 |
+
public function must_not_contain_role_changes( WSAL_AlertManager $manager ) {
|
638 |
+
return ! $manager->WillOrHasTriggered( 4002 );
|
639 |
+
}
|
640 |
+
|
641 |
+
/**
|
642 |
+
* Method: This function make sures that alert 4001
|
643 |
+
* has not been triggered before creating user meta.
|
644 |
+
*
|
645 |
+
* @param WSAL_AlertManager $manager - WSAL Alert Manager.
|
646 |
+
* @return bool
|
647 |
+
* @since 3.2.3
|
648 |
+
*/
|
649 |
+
public function must_not_contain_new_user_alert( WSAL_AlertManager $manager ) {
|
650 |
+
return ! $manager->WillOrHasTriggered( 4001 );
|
651 |
}
|
652 |
}
|
classes/Sensors/Multisite.php
CHANGED
@@ -44,20 +44,18 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
|
|
44 |
* Listening to events using WP hooks.
|
45 |
*/
|
46 |
public function HookEvents() {
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
add_action( 'shutdown', array( $this, 'EventAdminShutdown' ) );
|
51 |
-
}
|
52 |
-
add_action( 'wpmu_new_blog', array( $this, 'EventNewBlog' ), 10, 1 );
|
53 |
-
add_action( 'archive_blog', array( $this, 'EventArchiveBlog' ) );
|
54 |
-
add_action( 'unarchive_blog', array( $this, 'EventUnarchiveBlog' ) );
|
55 |
-
add_action( 'activate_blog', array( $this, 'EventActivateBlog' ) );
|
56 |
-
add_action( 'deactivate_blog', array( $this, 'EventDeactivateBlog' ) );
|
57 |
-
add_action( 'delete_blog', array( $this, 'EventDeleteBlog' ) );
|
58 |
-
add_action( 'add_user_to_blog', array( $this, 'EventUserAddedToBlog' ), 10, 3 );
|
59 |
-
add_action( 'remove_user_from_blog', array( $this, 'EventUserRemovedFromBlog' ), 10, 2 );
|
60 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
}
|
62 |
|
63 |
/**
|
44 |
* Listening to events using WP hooks.
|
45 |
*/
|
46 |
public function HookEvents() {
|
47 |
+
add_action( 'admin_init', array( $this, 'EventAdminInit' ) );
|
48 |
+
if ( current_user_can( 'switch_themes' ) ) {
|
49 |
+
add_action( 'shutdown', array( $this, 'EventAdminShutdown' ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
}
|
51 |
+
add_action( 'wpmu_new_blog', array( $this, 'EventNewBlog' ), 10, 1 );
|
52 |
+
add_action( 'archive_blog', array( $this, 'EventArchiveBlog' ) );
|
53 |
+
add_action( 'unarchive_blog', array( $this, 'EventUnarchiveBlog' ) );
|
54 |
+
add_action( 'activate_blog', array( $this, 'EventActivateBlog' ) );
|
55 |
+
add_action( 'deactivate_blog', array( $this, 'EventDeactivateBlog' ) );
|
56 |
+
add_action( 'delete_blog', array( $this, 'EventDeleteBlog' ) );
|
57 |
+
add_action( 'add_user_to_blog', array( $this, 'EventUserAddedToBlog' ), 10, 3 );
|
58 |
+
add_action( 'remove_user_from_blog', array( $this, 'EventUserRemovedFromBlog' ), 10, 2 );
|
59 |
}
|
60 |
|
61 |
/**
|
classes/Sensors/PluginsThemes.php
CHANGED
@@ -548,33 +548,38 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
|
|
548 |
*/
|
549 |
public function EventPluginPostCreate( $post_id, $post ) {
|
550 |
// Filter $_REQUEST array for security.
|
551 |
-
$get_array
|
552 |
$post_array = filter_input_array( INPUT_POST );
|
553 |
|
554 |
$wp_actions = array( 'editpost', 'heartbeat', 'inline-save', 'trash', 'untrash' );
|
555 |
if ( isset( $get_array['action'] ) && ! in_array( $get_array['action'], $wp_actions ) ) {
|
556 |
-
if (
|
557 |
-
|
|
|
|
|
|
|
|
|
|
|
558 |
// If the plugin modify the post.
|
559 |
if ( false !== strpos( $get_array['action'], 'edit' ) ) {
|
560 |
-
$editor_link = $this->GetEditorLink( $post );
|
561 |
$this->plugin->alerts->Trigger(
|
562 |
2106, array(
|
563 |
-
'PostID'
|
564 |
-
'PostType'
|
565 |
-
'PostTitle'
|
566 |
-
'PostStatus'
|
567 |
-
'PostUrl'
|
568 |
$editor_link['name'] => $editor_link['value'],
|
569 |
)
|
570 |
);
|
571 |
} else {
|
572 |
$this->plugin->alerts->Trigger(
|
573 |
5019, array(
|
574 |
-
'PostID'
|
575 |
-
'PostType'
|
576 |
-
'PostTitle'
|
577 |
-
'Username'
|
|
|
578 |
)
|
579 |
);
|
580 |
}
|
@@ -588,13 +593,13 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
|
|
588 |
) {
|
589 |
// If the plugin modify the post.
|
590 |
if ( false !== strpos( $post_array['action'], 'edit' ) ) {
|
591 |
-
$event
|
592 |
$editor_link = $this->GetEditorLink( $post );
|
593 |
$this->plugin->alerts->Trigger(
|
594 |
$event, array(
|
595 |
-
'PostID'
|
596 |
-
'PostType'
|
597 |
-
'PostTitle'
|
598 |
$editor_link['name'] => $editor_link['value'],
|
599 |
)
|
600 |
);
|
@@ -608,13 +613,15 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
|
|
608 |
// Ignore WooCommerce Bulk Stock Management page.
|
609 |
// OR MainWP plugin requests.
|
610 |
} else {
|
611 |
-
$event
|
|
|
612 |
$this->plugin->alerts->Trigger(
|
613 |
$event, array(
|
614 |
-
'PostID'
|
615 |
-
'PostType'
|
616 |
-
'PostTitle'
|
617 |
-
'Username'
|
|
|
618 |
)
|
619 |
);
|
620 |
}
|
@@ -881,6 +888,8 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
|
|
881 |
if (
|
882 |
isset( $post_array['mainwpsignature'] ) // Check MainWP signature.
|
883 |
&& isset( $post_array['action'] ) // Check if action is set.
|
|
|
|
|
884 |
&& in_array( $plugin, $wp_plugins, true ) // Check if plugin being activate/deactivate is in the list of plugins from MainWP.
|
885 |
) {
|
886 |
if ( 'activate' === $post_array['action'] ) {
|
@@ -889,7 +898,7 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
|
|
889 |
$event = 5002;
|
890 |
}
|
891 |
|
892 |
-
$plugin
|
893 |
$plugin_data = get_plugin_data( $plugin, false, true );
|
894 |
$this->plugin->alerts->Trigger(
|
895 |
$event, array(
|
@@ -903,6 +912,27 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
|
|
903 |
),
|
904 |
)
|
905 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
906 |
}
|
907 |
}
|
908 |
|
548 |
*/
|
549 |
public function EventPluginPostCreate( $post_id, $post ) {
|
550 |
// Filter $_REQUEST array for security.
|
551 |
+
$get_array = filter_input_array( INPUT_GET );
|
552 |
$post_array = filter_input_array( INPUT_POST );
|
553 |
|
554 |
$wp_actions = array( 'editpost', 'heartbeat', 'inline-save', 'trash', 'untrash' );
|
555 |
if ( isset( $get_array['action'] ) && ! in_array( $get_array['action'], $wp_actions ) ) {
|
556 |
+
if (
|
557 |
+
! in_array( $post->post_type, array( 'attachment', 'revision', 'nav_menu_item', 'customize_changeset', 'custom_css' ) )
|
558 |
+
|| ! empty( $post->post_title )
|
559 |
+
) {
|
560 |
+
// Get post editor link.
|
561 |
+
$editor_link = $this->GetEditorLink( $post );
|
562 |
+
|
563 |
// If the plugin modify the post.
|
564 |
if ( false !== strpos( $get_array['action'], 'edit' ) ) {
|
|
|
565 |
$this->plugin->alerts->Trigger(
|
566 |
2106, array(
|
567 |
+
'PostID' => $post->ID,
|
568 |
+
'PostType' => $post->post_type,
|
569 |
+
'PostTitle' => $post->post_title,
|
570 |
+
'PostStatus' => $post->post_status,
|
571 |
+
'PostUrl' => get_permalink( $post->ID ),
|
572 |
$editor_link['name'] => $editor_link['value'],
|
573 |
)
|
574 |
);
|
575 |
} else {
|
576 |
$this->plugin->alerts->Trigger(
|
577 |
5019, array(
|
578 |
+
'PostID' => $post->ID,
|
579 |
+
'PostType' => $post->post_type,
|
580 |
+
'PostTitle' => $post->post_title,
|
581 |
+
'Username' => 'Plugins',
|
582 |
+
$editor_link['name'] => $editor_link['value'],
|
583 |
)
|
584 |
);
|
585 |
}
|
593 |
) {
|
594 |
// If the plugin modify the post.
|
595 |
if ( false !== strpos( $post_array['action'], 'edit' ) ) {
|
596 |
+
$event = $this->GetEventTypeForPostType( $post, 2106, 2107, 2108 );
|
597 |
$editor_link = $this->GetEditorLink( $post );
|
598 |
$this->plugin->alerts->Trigger(
|
599 |
$event, array(
|
600 |
+
'PostID' => $post->ID,
|
601 |
+
'PostType' => $post->post_type,
|
602 |
+
'PostTitle' => $post->post_title,
|
603 |
$editor_link['name'] => $editor_link['value'],
|
604 |
)
|
605 |
);
|
613 |
// Ignore WooCommerce Bulk Stock Management page.
|
614 |
// OR MainWP plugin requests.
|
615 |
} else {
|
616 |
+
$event = $this->GetEventTypeForPostType( $post, 5019, 5020, 5021 );
|
617 |
+
$editor_link = $this->GetEditorLink( $post );
|
618 |
$this->plugin->alerts->Trigger(
|
619 |
$event, array(
|
620 |
+
'PostID' => $post->ID,
|
621 |
+
'PostType' => $post->post_type,
|
622 |
+
'PostTitle' => $post->post_title,
|
623 |
+
'Username' => 'Plugins',
|
624 |
+
$editor_link['name'] => $editor_link['value'],
|
625 |
)
|
626 |
);
|
627 |
}
|
888 |
if (
|
889 |
isset( $post_array['mainwpsignature'] ) // Check MainWP signature.
|
890 |
&& isset( $post_array['action'] ) // Check if action is set.
|
891 |
+
&& isset( $post_array['function'] ) // Check if function is set.
|
892 |
+
&& 'plugin_action' === $post_array['function']
|
893 |
&& in_array( $plugin, $wp_plugins, true ) // Check if plugin being activate/deactivate is in the list of plugins from MainWP.
|
894 |
) {
|
895 |
if ( 'activate' === $post_array['action'] ) {
|
898 |
$event = 5002;
|
899 |
}
|
900 |
|
901 |
+
$plugin = WP_PLUGIN_DIR . '/' . $plugin;
|
902 |
$plugin_data = get_plugin_data( $plugin, false, true );
|
903 |
$this->plugin->alerts->Trigger(
|
904 |
$event, array(
|
912 |
),
|
913 |
)
|
914 |
);
|
915 |
+
} elseif (
|
916 |
+
isset( $post_array['mainwpsignature'] ) // Check MainWP signature.
|
917 |
+
&& isset( $post_array['function'] ) // Check if function is set.
|
918 |
+
&& 'installplugintheme' === $post_array['function']
|
919 |
+
&& isset( $post_array['type'] ) // Check if type is set.
|
920 |
+
&& 'plugin' === $post_array['type']
|
921 |
+
) {
|
922 |
+
$plugin = WP_PLUGIN_DIR . '/' . $plugin;
|
923 |
+
$plugin_data = get_plugin_data( $plugin, false, true );
|
924 |
+
$this->plugin->alerts->Trigger(
|
925 |
+
5001, array(
|
926 |
+
'PluginFile' => $plugin,
|
927 |
+
'PluginData' => (object) array(
|
928 |
+
'Name' => $plugin_data['Name'],
|
929 |
+
'PluginURI' => $plugin_data['PluginURI'],
|
930 |
+
'Version' => $plugin_data['Version'],
|
931 |
+
'Author' => $plugin_data['Author'],
|
932 |
+
'Network' => $plugin_data['Network'] ? 'True' : 'False',
|
933 |
+
),
|
934 |
+
)
|
935 |
+
);
|
936 |
}
|
937 |
}
|
938 |
|
classes/Sensors/UserProfile.php
CHANGED
@@ -118,8 +118,9 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
|
|
118 |
return false;
|
119 |
}
|
120 |
|
121 |
-
$user
|
122 |
$bbpress_roles = array( 'bbp_spectator', 'bbp_moderator', 'bbp_participant', 'bbp_keymaster', 'bbp_blocked' );
|
|
|
123 |
// Remove any BBPress roles.
|
124 |
if ( is_array( $old_roles ) ) {
|
125 |
foreach ( $old_roles as $value ) {
|
@@ -152,13 +153,15 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
|
|
152 |
// Alert if roles are changed.
|
153 |
if ( $old_role != $new_role ) {
|
154 |
$this->plugin->alerts->TriggerIf(
|
155 |
-
4002,
|
156 |
-
|
|
|
157 |
'TargetUsername' => $user->user_login,
|
158 |
-
'OldRole'
|
159 |
-
'NewRole'
|
160 |
'multisite_text' => $this->plugin->IsMultisite() ? $site_id : false,
|
161 |
-
),
|
|
|
162 |
);
|
163 |
}
|
164 |
}
|
@@ -298,12 +301,13 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
|
|
298 |
* @param WSAL_AlertManager $mgr - Instance of WSAL_AlertManager.
|
299 |
*/
|
300 |
public function MustNotContainUserChanges( WSAL_AlertManager $mgr ) {
|
301 |
-
return ! (
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
)
|
|
|
307 |
}
|
308 |
|
309 |
/**
|
118 |
return false;
|
119 |
}
|
120 |
|
121 |
+
$user = get_userdata( $user_id );
|
122 |
$bbpress_roles = array( 'bbp_spectator', 'bbp_moderator', 'bbp_participant', 'bbp_keymaster', 'bbp_blocked' );
|
123 |
+
|
124 |
// Remove any BBPress roles.
|
125 |
if ( is_array( $old_roles ) ) {
|
126 |
foreach ( $old_roles as $value ) {
|
153 |
// Alert if roles are changed.
|
154 |
if ( $old_role != $new_role ) {
|
155 |
$this->plugin->alerts->TriggerIf(
|
156 |
+
4002,
|
157 |
+
array(
|
158 |
+
'TargetUserID' => $user_id,
|
159 |
'TargetUsername' => $user->user_login,
|
160 |
+
'OldRole' => $old_role,
|
161 |
+
'NewRole' => $new_role,
|
162 |
'multisite_text' => $this->plugin->IsMultisite() ? $site_id : false,
|
163 |
+
),
|
164 |
+
array( $this, 'MustNotContainUserChanges' )
|
165 |
);
|
166 |
}
|
167 |
}
|
301 |
* @param WSAL_AlertManager $mgr - Instance of WSAL_AlertManager.
|
302 |
*/
|
303 |
public function MustNotContainUserChanges( WSAL_AlertManager $mgr ) {
|
304 |
+
return ! (
|
305 |
+
$mgr->WillOrHasTriggered( 4010 )
|
306 |
+
|| $mgr->WillOrHasTriggered( 4011 )
|
307 |
+
|| $mgr->WillOrHasTriggered( 4012 )
|
308 |
+
|| $mgr->WillOrHasTriggered( 4000 )
|
309 |
+
|| $mgr->WillOrHasTriggered( 4001 )
|
310 |
+
);
|
311 |
}
|
312 |
|
313 |
/**
|
classes/Sensors/WooCommerce.php
CHANGED
@@ -115,11 +115,6 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
|
|
115 |
* Listening to events using WP hooks.
|
116 |
*/
|
117 |
public function HookEvents() {
|
118 |
-
// Check if WooCommerce plugin exists.
|
119 |
-
if ( ! is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
|
120 |
-
return false;
|
121 |
-
}
|
122 |
-
|
123 |
if ( current_user_can( 'edit_posts' ) ) {
|
124 |
add_action( 'admin_init', array( $this, 'EventAdminInit' ) );
|
125 |
}
|
115 |
* Listening to events using WP hooks.
|
116 |
*/
|
117 |
public function HookEvents() {
|
|
|
|
|
|
|
|
|
|
|
118 |
if ( current_user_can( 'edit_posts' ) ) {
|
119 |
add_action( 'admin_init', array( $this, 'EventAdminInit' ) );
|
120 |
}
|
classes/Sensors/YoastSEO.php
CHANGED
@@ -41,25 +41,20 @@ class WSAL_Sensors_YoastSEO extends WSAL_AbstractSensor {
|
|
41 |
* @var array
|
42 |
*/
|
43 |
private $post_seo_data = array(
|
44 |
-
'_yoast_wpseo_title'
|
45 |
-
'_yoast_wpseo_metadesc'
|
46 |
-
'_yoast_wpseo_focuskw'
|
47 |
-
'_yst_is_cornerstone'
|
48 |
-
'_yoast_wpseo_meta-robots-noindex'
|
49 |
'_yoast_wpseo_meta-robots-nofollow' => '',
|
50 |
-
'_yoast_wpseo_meta-robots-adv'
|
51 |
-
'_yoast_wpseo_canonical'
|
52 |
);
|
53 |
|
54 |
/**
|
55 |
* Listening to events using hooks.
|
56 |
*/
|
57 |
public function HookEvents() {
|
58 |
-
// Check if Yoast SEO plugin exists.
|
59 |
-
if ( ! is_plugin_active( 'wordpress-seo/wp-seo.php' ) ) {
|
60 |
-
return false;
|
61 |
-
}
|
62 |
-
|
63 |
// If user can edit post then hook this function.
|
64 |
if ( current_user_can( 'edit_posts' ) ) {
|
65 |
add_action( 'admin_init', array( $this, 'event_admin_init' ) );
|
41 |
* @var array
|
42 |
*/
|
43 |
private $post_seo_data = array(
|
44 |
+
'_yoast_wpseo_title' => '',
|
45 |
+
'_yoast_wpseo_metadesc' => '',
|
46 |
+
'_yoast_wpseo_focuskw' => '',
|
47 |
+
'_yst_is_cornerstone' => '',
|
48 |
+
'_yoast_wpseo_meta-robots-noindex' => '',
|
49 |
'_yoast_wpseo_meta-robots-nofollow' => '',
|
50 |
+
'_yoast_wpseo_meta-robots-adv' => '',
|
51 |
+
'_yoast_wpseo_canonical' => '',
|
52 |
);
|
53 |
|
54 |
/**
|
55 |
* Listening to events using hooks.
|
56 |
*/
|
57 |
public function HookEvents() {
|
|
|
|
|
|
|
|
|
|
|
58 |
// If user can edit post then hook this function.
|
59 |
if ( current_user_can( 'edit_posts' ) ) {
|
60 |
add_action( 'admin_init', array( $this, 'event_admin_init' ) );
|
classes/Settings.php
CHANGED
@@ -118,6 +118,13 @@ class WSAL_Settings {
|
|
118 |
*/
|
119 |
protected $excluded_urls = array();
|
120 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
121 |
/**
|
122 |
* Method: Constructor.
|
123 |
*
|
@@ -127,6 +134,22 @@ class WSAL_Settings {
|
|
127 |
$this->_plugin = $plugin;
|
128 |
}
|
129 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
/**
|
131 |
* Return array of developer options to be enabled by default.
|
132 |
*
|
@@ -290,7 +313,7 @@ class WSAL_Settings {
|
|
290 |
* @return string
|
291 |
*/
|
292 |
public function GetDefaultPruningDate() {
|
293 |
-
return '
|
294 |
}
|
295 |
|
296 |
/**
|
@@ -320,6 +343,24 @@ class WSAL_Settings {
|
|
320 |
}
|
321 |
}
|
322 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
323 |
/**
|
324 |
* Maximum number of alerts to keep.
|
325 |
*
|
@@ -460,11 +501,19 @@ class WSAL_Settings {
|
|
460 |
return $this->_plugin->SetGlobalOption( 'delete-data', $enabled );
|
461 |
}
|
462 |
|
|
|
|
|
|
|
|
|
|
|
463 |
public function SetAllowedPluginViewers( $users_or_roles ) {
|
464 |
$this->_viewers = $users_or_roles;
|
465 |
$this->_plugin->SetGlobalOption( 'plugin-viewers', implode( ',', $this->_viewers ) );
|
466 |
}
|
467 |
|
|
|
|
|
|
|
468 |
public function GetAllowedPluginViewers() {
|
469 |
if ( is_null( $this->_viewers ) ) {
|
470 |
$this->_viewers = array_unique( array_filter( explode( ',', $this->_plugin->GetGlobalOption( 'plugin-viewers' ) ) ) );
|
@@ -472,11 +521,19 @@ class WSAL_Settings {
|
|
472 |
return $this->_viewers;
|
473 |
}
|
474 |
|
|
|
|
|
|
|
|
|
|
|
475 |
public function SetAllowedPluginEditors( $users_or_roles ) {
|
476 |
$this->_editors = $users_or_roles;
|
477 |
$this->_plugin->SetGlobalOption( 'plugin-editors', implode( ',', $this->_editors ) );
|
478 |
}
|
479 |
|
|
|
|
|
|
|
480 |
public function GetAllowedPluginEditors() {
|
481 |
if ( is_null( $this->_editors ) ) {
|
482 |
$this->_editors = array_unique( array_filter( explode( ',', $this->_plugin->GetGlobalOption( 'plugin-editors' ) ) ) );
|
@@ -484,6 +541,29 @@ class WSAL_Settings {
|
|
484 |
return $this->_editors;
|
485 |
}
|
486 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
487 |
public function SetViewPerPage( $newvalue ) {
|
488 |
$this->_perpage = max( $newvalue, 1 );
|
489 |
$this->_plugin->SetGlobalOption( 'items-per-page', $this->_perpage );
|
@@ -549,6 +629,7 @@ class WSAL_Settings {
|
|
549 |
* Returns access tokens for a particular action.
|
550 |
*
|
551 |
* @param string $action - Type of action.
|
|
|
552 |
* @return string[] List of tokens (usernames, roles etc).
|
553 |
*/
|
554 |
public function GetAccessTokens( $action ) {
|
@@ -900,9 +981,9 @@ class WSAL_Settings {
|
|
900 |
*/
|
901 |
public function GetDateFormat() {
|
902 |
$wp_date_format = get_option( 'date_format' );
|
903 |
-
$search
|
904 |
-
$replace
|
905 |
-
$date_format
|
906 |
return $date_format;
|
907 |
}
|
908 |
|
@@ -923,7 +1004,7 @@ class WSAL_Settings {
|
|
923 |
* Server's timezone or WordPress' timezone.
|
924 |
*/
|
925 |
public function GetTimezone() {
|
926 |
-
return $this->_plugin->GetGlobalOption( 'timezone',
|
927 |
}
|
928 |
|
929 |
public function SetTimezone( $newvalue ) {
|
@@ -958,11 +1039,11 @@ class WSAL_Settings {
|
|
958 |
public function GetColumns() {
|
959 |
$columns = array(
|
960 |
'alert_code' => '1',
|
961 |
-
'type'
|
962 |
-
'date'
|
963 |
-
'username'
|
964 |
-
'source_ip'
|
965 |
-
'message'
|
966 |
);
|
967 |
if ( $this->_plugin->IsMultisite() ) {
|
968 |
$columns = array_slice( $columns, 0, 5, true ) + array(
|
@@ -973,11 +1054,11 @@ class WSAL_Settings {
|
|
973 |
if ( ! empty( $selected ) ) {
|
974 |
$columns = array(
|
975 |
'alert_code' => '0',
|
976 |
-
'type'
|
977 |
-
'date'
|
978 |
-
'username'
|
979 |
-
'source_ip'
|
980 |
-
'message'
|
981 |
);
|
982 |
if ( $this->_plugin->IsMultisite() ) {
|
983 |
$columns = array_slice( $columns, 0, 5, true ) + array(
|
@@ -1008,6 +1089,24 @@ class WSAL_Settings {
|
|
1008 |
return $this->_plugin->SetGlobalOption( 'wp-backend', $enabled );
|
1009 |
}
|
1010 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1011 |
public function SetFromEmail( $email_address ) {
|
1012 |
return $this->_plugin->SetGlobalOption( 'from-email', trim( $email_address ) );
|
1013 |
}
|
@@ -1117,7 +1216,7 @@ class WSAL_Settings {
|
|
1117 |
$archive_ssl_ca = $this->_plugin->GetGlobalOption( 'archive-ssl-ca', false );
|
1118 |
$archive_ssl_cert = $this->_plugin->GetGlobalOption( 'archive-ssl-cert', false );
|
1119 |
$archive_ssl_key = $this->_plugin->GetGlobalOption( 'archive-ssl-key', false );
|
1120 |
-
$config
|
1121 |
$this->_plugin->getConnector( $config )->getAdapter( 'Occurrence' );
|
1122 |
}
|
1123 |
}
|
@@ -1206,4 +1305,54 @@ class WSAL_Settings {
|
|
1206 |
}
|
1207 |
return ($result > 0);
|
1208 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1209 |
}
|
118 |
*/
|
119 |
protected $excluded_urls = array();
|
120 |
|
121 |
+
/**
|
122 |
+
* Alerts enabled in Geek mode.
|
123 |
+
*
|
124 |
+
* @var array
|
125 |
+
*/
|
126 |
+
public $geek_alerts = array( 1004, 1005, 1006, 1007, 2023, 2024, 2053, 2054, 2055, 2062, 2100, 2106, 2111, 2112, 2124, 2125, 2094, 2095, 2043, 2071, 2082, 2083, 2085, 2089, 4014, 4015, 4016, 5010, 5011, 5012, 5019, 5025, 5013, 5014, 5015, 5016, 5017, 5018, 6001, 6002, 6007, 6008, 6010, 6011, 6012, 6013, 6014, 6015, 6016, 6017, 6018, 6023, 6024, 6025 );
|
127 |
+
|
128 |
/**
|
129 |
* Method: Constructor.
|
130 |
*
|
134 |
$this->_plugin = $plugin;
|
135 |
}
|
136 |
|
137 |
+
/**
|
138 |
+
* Enable Basic Mode.
|
139 |
+
*/
|
140 |
+
public function set_basic_mode() {
|
141 |
+
// Disable alerts of geek mode.
|
142 |
+
$this->SetDisabledAlerts( $this->geek_alerts );
|
143 |
+
}
|
144 |
+
|
145 |
+
/**
|
146 |
+
* Enable Geek Mode.
|
147 |
+
*/
|
148 |
+
public function set_geek_mode() {
|
149 |
+
// Disable alerts of geek mode.
|
150 |
+
$this->SetDisabledAlerts( array() );
|
151 |
+
}
|
152 |
+
|
153 |
/**
|
154 |
* Return array of developer options to be enabled by default.
|
155 |
*
|
313 |
* @return string
|
314 |
*/
|
315 |
public function GetDefaultPruningDate() {
|
316 |
+
return '6 months';
|
317 |
}
|
318 |
|
319 |
/**
|
343 |
}
|
344 |
}
|
345 |
|
346 |
+
/**
|
347 |
+
* Return current pruning unit.
|
348 |
+
*
|
349 |
+
* @return string
|
350 |
+
*/
|
351 |
+
public function get_pruning_unit() {
|
352 |
+
return $this->_plugin->GetGlobalOption( 'pruning-unit', 'months' );
|
353 |
+
}
|
354 |
+
|
355 |
+
/**
|
356 |
+
* Set current pruning unit.
|
357 |
+
*
|
358 |
+
* @param string $newvalue – New value of pruning unit.
|
359 |
+
*/
|
360 |
+
public function set_pruning_unit( $newvalue ) {
|
361 |
+
$this->_plugin->SetGlobalOption( 'pruning-unit', $newvalue );
|
362 |
+
}
|
363 |
+
|
364 |
/**
|
365 |
* Maximum number of alerts to keep.
|
366 |
*
|
501 |
return $this->_plugin->SetGlobalOption( 'delete-data', $enabled );
|
502 |
}
|
503 |
|
504 |
+
/**
|
505 |
+
* Set Plugin Viewers.
|
506 |
+
*
|
507 |
+
* @param array $users_or_roles – Users/Roles.
|
508 |
+
*/
|
509 |
public function SetAllowedPluginViewers( $users_or_roles ) {
|
510 |
$this->_viewers = $users_or_roles;
|
511 |
$this->_plugin->SetGlobalOption( 'plugin-viewers', implode( ',', $this->_viewers ) );
|
512 |
}
|
513 |
|
514 |
+
/**
|
515 |
+
* Get Plugin Viewers.
|
516 |
+
*/
|
517 |
public function GetAllowedPluginViewers() {
|
518 |
if ( is_null( $this->_viewers ) ) {
|
519 |
$this->_viewers = array_unique( array_filter( explode( ',', $this->_plugin->GetGlobalOption( 'plugin-viewers' ) ) ) );
|
521 |
return $this->_viewers;
|
522 |
}
|
523 |
|
524 |
+
/**
|
525 |
+
* Set Plugin Editors.
|
526 |
+
*
|
527 |
+
* @param array $users_or_roles – Users/Roles.
|
528 |
+
*/
|
529 |
public function SetAllowedPluginEditors( $users_or_roles ) {
|
530 |
$this->_editors = $users_or_roles;
|
531 |
$this->_plugin->SetGlobalOption( 'plugin-editors', implode( ',', $this->_editors ) );
|
532 |
}
|
533 |
|
534 |
+
/**
|
535 |
+
* Get Plugin Editors.
|
536 |
+
*/
|
537 |
public function GetAllowedPluginEditors() {
|
538 |
if ( is_null( $this->_editors ) ) {
|
539 |
$this->_editors = array_unique( array_filter( explode( ',', $this->_plugin->GetGlobalOption( 'plugin-editors' ) ) ) );
|
541 |
return $this->_editors;
|
542 |
}
|
543 |
|
544 |
+
/**
|
545 |
+
* Set restrict plugin setting.
|
546 |
+
*
|
547 |
+
* @param string $setting – Setting.
|
548 |
+
* @since 3.2.3
|
549 |
+
*/
|
550 |
+
public function set_restrict_plugin_setting( $setting ) {
|
551 |
+
$this->_plugin->SetGlobalOption( 'restrict-plugin-settings', $setting );
|
552 |
+
}
|
553 |
+
|
554 |
+
/**
|
555 |
+
* Get restrict plugin setting.
|
556 |
+
*
|
557 |
+
* @since 3.2.3
|
558 |
+
*/
|
559 |
+
public function get_restrict_plugin_setting() {
|
560 |
+
$default_value = 'only_admins';
|
561 |
+
if ( $this->IsRestrictAdmins() ) {
|
562 |
+
$default_value = 'only_me';
|
563 |
+
}
|
564 |
+
return $this->_plugin->GetGlobalOption( 'restrict-plugin-settings', $default_value );
|
565 |
+
}
|
566 |
+
|
567 |
public function SetViewPerPage( $newvalue ) {
|
568 |
$this->_perpage = max( $newvalue, 1 );
|
569 |
$this->_plugin->SetGlobalOption( 'items-per-page', $this->_perpage );
|
629 |
* Returns access tokens for a particular action.
|
630 |
*
|
631 |
* @param string $action - Type of action.
|
632 |
+
* @throws Exception - Unknown action exception.
|
633 |
* @return string[] List of tokens (usernames, roles etc).
|
634 |
*/
|
635 |
public function GetAccessTokens( $action ) {
|
981 |
*/
|
982 |
public function GetDateFormat() {
|
983 |
$wp_date_format = get_option( 'date_format' );
|
984 |
+
$search = array( 'F', 'M', 'n', 'j', ' ', '/', 'y', 'S', ',', 'l', 'D' );
|
985 |
+
$replace = array( 'm', 'm', 'm', 'd', '-', '-', 'Y', '', '', '', '' );
|
986 |
+
$date_format = str_replace( $search, $replace, $wp_date_format );
|
987 |
return $date_format;
|
988 |
}
|
989 |
|
1004 |
* Server's timezone or WordPress' timezone.
|
1005 |
*/
|
1006 |
public function GetTimezone() {
|
1007 |
+
return $this->_plugin->GetGlobalOption( 'timezone', 'wp' );
|
1008 |
}
|
1009 |
|
1010 |
public function SetTimezone( $newvalue ) {
|
1039 |
public function GetColumns() {
|
1040 |
$columns = array(
|
1041 |
'alert_code' => '1',
|
1042 |
+
'type' => '1',
|
1043 |
+
'date' => '1',
|
1044 |
+
'username' => '1',
|
1045 |
+
'source_ip' => '1',
|
1046 |
+
'message' => '1',
|
1047 |
);
|
1048 |
if ( $this->_plugin->IsMultisite() ) {
|
1049 |
$columns = array_slice( $columns, 0, 5, true ) + array(
|
1054 |
if ( ! empty( $selected ) ) {
|
1055 |
$columns = array(
|
1056 |
'alert_code' => '0',
|
1057 |
+
'type' => '0',
|
1058 |
+
'date' => '0',
|
1059 |
+
'username' => '0',
|
1060 |
+
'source_ip' => '0',
|
1061 |
+
'message' => '0',
|
1062 |
);
|
1063 |
if ( $this->_plugin->IsMultisite() ) {
|
1064 |
$columns = array_slice( $columns, 0, 5, true ) + array(
|
1089 |
return $this->_plugin->SetGlobalOption( 'wp-backend', $enabled );
|
1090 |
}
|
1091 |
|
1092 |
+
/**
|
1093 |
+
* Set use email setting.
|
1094 |
+
*
|
1095 |
+
* @param string $use – Setting value.
|
1096 |
+
*/
|
1097 |
+
public function set_use_email( $use ) {
|
1098 |
+
return $this->_plugin->SetGlobalOption( 'use-email', $use );
|
1099 |
+
}
|
1100 |
+
|
1101 |
+
/**
|
1102 |
+
* Get use email setting.
|
1103 |
+
*
|
1104 |
+
* @return string
|
1105 |
+
*/
|
1106 |
+
public function get_use_email() {
|
1107 |
+
return $this->_plugin->GetGlobalOption( 'use-email', 'default_email' );
|
1108 |
+
}
|
1109 |
+
|
1110 |
public function SetFromEmail( $email_address ) {
|
1111 |
return $this->_plugin->SetGlobalOption( 'from-email', trim( $email_address ) );
|
1112 |
}
|
1216 |
$archive_ssl_ca = $this->_plugin->GetGlobalOption( 'archive-ssl-ca', false );
|
1217 |
$archive_ssl_cert = $this->_plugin->GetGlobalOption( 'archive-ssl-cert', false );
|
1218 |
$archive_ssl_key = $this->_plugin->GetGlobalOption( 'archive-ssl-key', false );
|
1219 |
+
$config = WSAL_Connector_ConnectorFactory::GetConfigArray( $archive_type, $archive_user, $password, $archive_name, $archive_hostname, $archive_baseprefix, $archive_ssl, $archive_cc, $archive_ssl_ca, $archive_ssl_cert, $archive_ssl_key );
|
1220 |
$this->_plugin->getConnector( $config )->getAdapter( 'Occurrence' );
|
1221 |
}
|
1222 |
}
|
1305 |
}
|
1306 |
return ($result > 0);
|
1307 |
}
|
1308 |
+
|
1309 |
+
/**
|
1310 |
+
* Method: Get Token Type.
|
1311 |
+
*
|
1312 |
+
* @param string $token - Token type.
|
1313 |
+
* @since 3.2.3
|
1314 |
+
*/
|
1315 |
+
public function get_token_type( $token ) {
|
1316 |
+
// Get users.
|
1317 |
+
$users = array();
|
1318 |
+
foreach ( get_users( 'blog_id=0&fields[]=user_login' ) as $obj ) {
|
1319 |
+
$users[] = $obj->user_login;
|
1320 |
+
}
|
1321 |
+
|
1322 |
+
// Get user roles.
|
1323 |
+
$roles = array_keys( get_editable_roles() );
|
1324 |
+
|
1325 |
+
// Get custom post types.
|
1326 |
+
$post_types = get_post_types( array(), 'names', 'and' );
|
1327 |
+
|
1328 |
+
// Check if the token matched users.
|
1329 |
+
if ( in_array( $token, $users ) ) {
|
1330 |
+
return 'user';
|
1331 |
+
}
|
1332 |
+
|
1333 |
+
// Check if the token matched user roles.
|
1334 |
+
if ( in_array( $token, $roles ) ) {
|
1335 |
+
return 'role';
|
1336 |
+
}
|
1337 |
+
|
1338 |
+
// Check if the token matched post types.
|
1339 |
+
if ( in_array( $token, $post_types ) ) {
|
1340 |
+
return 'cpts';
|
1341 |
+
}
|
1342 |
+
|
1343 |
+
// Check if the token matches a URL.
|
1344 |
+
if ( ( false !== strpos( $token, home_url() ) ) && filter_var( $token, FILTER_VALIDATE_URL ) ) {
|
1345 |
+
return 'urls';
|
1346 |
+
}
|
1347 |
+
|
1348 |
+
// Check if the token matches an IP address.
|
1349 |
+
if (
|
1350 |
+
filter_var( $token, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) // Validate IPv4.
|
1351 |
+
|| filter_var( $token, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) // Validate IPv6.
|
1352 |
+
) {
|
1353 |
+
return 'ip';
|
1354 |
+
}
|
1355 |
+
|
1356 |
+
return 'other';
|
1357 |
+
}
|
1358 |
}
|
classes/ViewManager.php
CHANGED
@@ -1,8 +1,22 @@
|
|
1 |
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
/**
|
3 |
* View Manager.
|
4 |
*
|
5 |
-
* This
|
6 |
* It creates also the menu items.
|
7 |
*
|
8 |
* @package Wsal
|
@@ -40,18 +54,39 @@ class WSAL_ViewManager {
|
|
40 |
public function __construct( WpSecurityAuditLog $plugin ) {
|
41 |
$this->_plugin = $plugin;
|
42 |
|
|
|
43 |
$skip_views = array();
|
44 |
|
45 |
// Array of views to skip for premium version.
|
46 |
if ( wsal_freemius()->can_use_premium_code() || wsal_freemius()->is_plan__premium_only( 'starter' ) ) {
|
47 |
-
$skip_views[] =
|
48 |
-
$skip_views[] =
|
49 |
-
$skip_views[] =
|
50 |
-
$skip_views[] =
|
51 |
-
$skip_views[] =
|
52 |
-
$skip_views[] =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
}
|
54 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
// Load views.
|
56 |
foreach ( glob( dirname( __FILE__ ) . '/Views/*.php' ) as $file ) {
|
57 |
if ( empty( $skip_views ) || ! in_array( $file, $skip_views ) ) {
|
@@ -71,6 +106,14 @@ class WSAL_ViewManager {
|
|
71 |
|
72 |
// Render footer.
|
73 |
add_action( 'admin_footer', array( $this, 'RenderViewFooter' ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
}
|
75 |
|
76 |
/**
|
@@ -266,6 +309,8 @@ class WSAL_ViewManager {
|
|
266 |
*/
|
267 |
public function RenderViewBody() {
|
268 |
$view = $this->GetActiveView();
|
|
|
|
|
269 |
?>
|
270 |
<div class="wrap">
|
271 |
<?php
|
@@ -275,6 +320,7 @@ class WSAL_ViewManager {
|
|
275 |
?>
|
276 |
</div>
|
277 |
<?php
|
|
|
278 |
}
|
279 |
|
280 |
/**
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* Manager: View
|
4 |
+
*
|
5 |
+
* View manager class file.
|
6 |
+
*
|
7 |
+
* @since 1.0.0
|
8 |
+
* @package Wsal
|
9 |
+
*/
|
10 |
+
|
11 |
+
// Exit if accessed directly.
|
12 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
13 |
+
exit;
|
14 |
+
}
|
15 |
+
|
16 |
/**
|
17 |
* View Manager.
|
18 |
*
|
19 |
+
* This class includes all the views, initialize them and shows the active one.
|
20 |
* It creates also the menu items.
|
21 |
*
|
22 |
* @package Wsal
|
54 |
public function __construct( WpSecurityAuditLog $plugin ) {
|
55 |
$this->_plugin = $plugin;
|
56 |
|
57 |
+
// Skipped views array.
|
58 |
$skip_views = array();
|
59 |
|
60 |
// Array of views to skip for premium version.
|
61 |
if ( wsal_freemius()->can_use_premium_code() || wsal_freemius()->is_plan__premium_only( 'starter' ) ) {
|
62 |
+
$skip_views[] = $this->_plugin->GetBaseDir() . 'classes/Views/EmailNotifications.php';
|
63 |
+
$skip_views[] = $this->_plugin->GetBaseDir() . 'classes/Views/ExternalDB.php';
|
64 |
+
$skip_views[] = $this->_plugin->GetBaseDir() . 'classes/Views/Licensing.php';
|
65 |
+
$skip_views[] = $this->_plugin->GetBaseDir() . 'classes/Views/LogInUsers.php';
|
66 |
+
$skip_views[] = $this->_plugin->GetBaseDir() . 'classes/Views/Reports.php';
|
67 |
+
$skip_views[] = $this->_plugin->GetBaseDir() . 'classes/Views/Search.php';
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Add setup wizard page to skip views. It will only be initialized
|
72 |
+
* one time.
|
73 |
+
*
|
74 |
+
* @since 3.2.3
|
75 |
+
*/
|
76 |
+
if ( file_exists( $this->_plugin->GetBaseDir() . 'classes/Views/SetupWizard.php' ) ) {
|
77 |
+
$skip_views[] = $this->_plugin->GetBaseDir() . 'classes/Views/SetupWizard.php';
|
78 |
}
|
79 |
|
80 |
+
/**
|
81 |
+
* Skipped Views.
|
82 |
+
*
|
83 |
+
* Array of views which are skipped before plugin views are initialized.
|
84 |
+
*
|
85 |
+
* @param array $skip_views - Skipped views.
|
86 |
+
* @since 3.2.3
|
87 |
+
*/
|
88 |
+
$skip_views = apply_filters( 'wsal_skip_views', $skip_views );
|
89 |
+
|
90 |
// Load views.
|
91 |
foreach ( glob( dirname( __FILE__ ) . '/Views/*.php' ) as $file ) {
|
92 |
if ( empty( $skip_views ) || ! in_array( $file, $skip_views ) ) {
|
106 |
|
107 |
// Render footer.
|
108 |
add_action( 'admin_footer', array( $this, 'RenderViewFooter' ) );
|
109 |
+
|
110 |
+
// Initialize setup wizard.
|
111 |
+
if (
|
112 |
+
'no' === $this->_plugin->GetGlobalOption( 'wsal-setup-complete', 'no' )
|
113 |
+
|| 'no' === $this->_plugin->GetGlobalOption( 'wsal-setup-modal-dismissed', 'no' )
|
114 |
+
) {
|
115 |
+
new WSAL_Views_SetupWizard( $plugin );
|
116 |
+
}
|
117 |
}
|
118 |
|
119 |
/**
|
309 |
*/
|
310 |
public function RenderViewBody() {
|
311 |
$view = $this->GetActiveView();
|
312 |
+
|
313 |
+
if ( $view && $view instanceof WSAL_AbstractView ) :
|
314 |
?>
|
315 |
<div class="wrap">
|
316 |
<?php
|
320 |
?>
|
321 |
</div>
|
322 |
<?php
|
323 |
+
endif;
|
324 |
}
|
325 |
|
326 |
/**
|
classes/Views/AuditLog.php
CHANGED
@@ -13,7 +13,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|
13 |
exit;
|
14 |
}
|
15 |
|
16 |
-
require_once
|
17 |
|
18 |
/**
|
19 |
* Audit Log Viewer Page
|
@@ -56,6 +56,7 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
|
|
56 |
add_action( 'all_admin_notices', array( $this, 'AdminNoticesPremium' ) );
|
57 |
add_action( 'admin_enqueue_scripts', array( $this, 'load_pointers' ), 1000 );
|
58 |
add_filter( 'wsal_pointers_toplevel_page_wsal-auditlog', array( $this, 'register_privacy_pointer' ), 10, 1 );
|
|
|
59 |
|
60 |
// Check plugin version for to dismiss the notice only until upgrade.
|
61 |
$this->_version = WSAL_VERSION;
|
@@ -103,9 +104,9 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
|
|
103 |
|
104 |
$more_info = add_query_arg(
|
105 |
array(
|
106 |
-
'utm_source'
|
107 |
-
'utm_medium'
|
108 |
-
'utm_content'
|
109 |
'utm_campaign' => 'upgrade+premium',
|
110 |
),
|
111 |
'https://www.wpsecurityauditlog.com/premium-features/'
|
@@ -236,41 +237,135 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
|
|
236 |
return $this->_listview;
|
237 |
}
|
238 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
239 |
/**
|
240 |
* Render view table of Audit Log.
|
241 |
*
|
242 |
-
* @since
|
243 |
*/
|
244 |
public function Render() {
|
245 |
if ( ! $this->_plugin->settings->CurrentUserCan( 'view' ) ) {
|
246 |
wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'wp-security-audit-log' ) );
|
247 |
}
|
248 |
|
249 |
-
// Filter $_POST array for security.
|
250 |
-
$post_array = filter_input_array( INPUT_POST );
|
251 |
-
|
252 |
// Verify nonce for security.
|
253 |
-
if ( isset( $
|
254 |
-
|
255 |
}
|
256 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
257 |
$this->GetListView()->prepare_items();
|
258 |
$occ = new WSAL_Models_Occurrence();
|
259 |
|
260 |
?>
|
261 |
-
<form id="audit-log-viewer" method="
|
262 |
<div id="audit-log-viewer-content">
|
263 |
-
<input type="hidden" name="page" value="<?php echo
|
264 |
-
<input type="hidden" id="wsal-cbid" name="wsal-cbid" value="<?php echo esc_attr(
|
265 |
<?php do_action( 'wsal_auditlog_before_view', $this->GetListView() ); ?>
|
266 |
<?php $this->GetListView()->display(); ?>
|
267 |
<?php do_action( 'wsal_auditlog_after_view', $this->GetListView() ); ?>
|
268 |
</div>
|
269 |
</form>
|
270 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
271 |
<?php
|
272 |
if ( class_exists( 'WSAL_SearchExtension' ) &&
|
273 |
-
(
|
274 |
?>
|
275 |
<script type="text/javascript">
|
276 |
jQuery(document).ready( function() {
|
@@ -278,15 +373,15 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
|
|
278 |
<?php
|
279 |
echo json_encode(
|
280 |
array(
|
281 |
-
'ajaxurl'
|
282 |
-
'tr8n'
|
283 |
'numofitems' => __( 'Please enter the number of alerts you would like to see on one page:', 'wp-security-audit-log' ),
|
284 |
'searchback' => __( 'All Sites', 'wp-security-audit-log' ),
|
285 |
'searchnone' => __( 'No Results', 'wp-security-audit-log' ),
|
286 |
),
|
287 |
-
'autorefresh'
|
288 |
-
'enabled'
|
289 |
-
'token'
|
290 |
),
|
291 |
)
|
292 |
);
|
@@ -301,15 +396,15 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
|
|
301 |
<?php
|
302 |
echo json_encode(
|
303 |
array(
|
304 |
-
'ajaxurl'
|
305 |
-
'tr8n'
|
306 |
'numofitems' => __( 'Please enter the number of alerts you would like to see on one page:', 'wp-security-audit-log' ),
|
307 |
'searchback' => __( 'All Sites', 'wp-security-audit-log' ),
|
308 |
'searchnone' => __( 'No Results', 'wp-security-audit-log' ),
|
309 |
),
|
310 |
'autorefresh' => array(
|
311 |
'enabled' => $this->_plugin->settings->IsRefreshAlertsEnabled(),
|
312 |
-
'token'
|
313 |
),
|
314 |
)
|
315 |
);
|
@@ -317,7 +412,7 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
|
|
317 |
);
|
318 |
} );
|
319 |
</script>
|
320 |
-
|
321 |
endif;
|
322 |
}
|
323 |
|
@@ -335,6 +430,16 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
|
|
335 |
if ( ! isset( $get_array['occurrence'] ) ) {
|
336 |
die( 'Occurrence parameter expected.' );
|
337 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
338 |
$occ = new WSAL_Models_Occurrence();
|
339 |
$occ->Load( 'id = %d', array( (int) $get_array['occurrence'] ) );
|
340 |
$alert_meta = $occ->GetMetaArray();
|
@@ -463,12 +568,12 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
|
|
463 |
public function wsal_download_failed_login_log() {
|
464 |
// Get post array through filter.
|
465 |
$download_nonce = filter_input( INPUT_POST, 'download_nonce', FILTER_SANITIZE_STRING );
|
466 |
-
$alert_id
|
467 |
|
468 |
// Verify nonce.
|
469 |
-
if ( ! empty( $download_nonce ) && wp_verify_nonce( $download_nonce,
|
470 |
// Get alert by id.
|
471 |
-
$alert
|
472 |
$alert->id = (int) $alert_id;
|
473 |
|
474 |
// Get users using alert meta.
|
@@ -493,24 +598,26 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
|
|
493 |
*/
|
494 |
public function wsal_download_404_log() {
|
495 |
// Get post array through filter.
|
496 |
-
$nonce
|
497 |
$filename = filter_input( INPUT_POST, 'log_file', FILTER_SANITIZE_STRING );
|
498 |
-
$site_id
|
499 |
|
500 |
// If file name is empty then return error.
|
501 |
if ( empty( $filename ) ) {
|
502 |
// Nonce verification failed.
|
503 |
-
echo wp_json_encode(
|
504 |
-
|
505 |
-
|
506 |
-
|
|
|
|
|
507 |
die();
|
508 |
}
|
509 |
|
510 |
// Verify nonce.
|
511 |
-
if ( ! empty( $filename ) && ! empty( $nonce ) && wp_verify_nonce( $nonce,
|
512 |
// Set log file path.
|
513 |
-
$uploads_dir
|
514 |
|
515 |
if ( ! $site_id ) {
|
516 |
$position = strpos( $filename, '/sites/' );
|
@@ -523,8 +630,8 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
|
|
523 |
}
|
524 |
$log_file_path = trailingslashit( $uploads_dir['basedir'] ) . $filename;
|
525 |
} else {
|
526 |
-
$position
|
527 |
-
$filename
|
528 |
$log_file_path = trailingslashit( $uploads_dir['basedir'] ) . $filename;
|
529 |
}
|
530 |
|
@@ -534,24 +641,30 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
|
|
534 |
// Check if the response is valid.
|
535 |
if ( $response ) {
|
536 |
// Return the file body.
|
537 |
-
echo wp_json_encode(
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
|
|
|
|
542 |
} else {
|
543 |
// Request failed.
|
544 |
-
echo wp_json_encode(
|
545 |
-
|
546 |
-
|
547 |
-
|
|
|
|
|
548 |
}
|
549 |
} else {
|
550 |
// Nonce verification failed.
|
551 |
-
echo wp_json_encode(
|
552 |
-
|
553 |
-
|
554 |
-
|
|
|
|
|
555 |
}
|
556 |
die();
|
557 |
}
|
@@ -572,10 +685,12 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
|
|
572 |
// Verify nonce.
|
573 |
if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'wsal-freemius-opt' ) ) {
|
574 |
// Nonce verification failed.
|
575 |
-
echo wp_json_encode(
|
576 |
-
|
577 |
-
|
578 |
-
|
|
|
|
|
579 |
exit();
|
580 |
}
|
581 |
|
@@ -586,7 +701,7 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
|
|
586 |
wsal_freemius()->opt_in(); // Opt in.
|
587 |
} else {
|
588 |
// Get sites.
|
589 |
-
$sites
|
590 |
$sites_data = array();
|
591 |
|
592 |
if ( ! empty( $sites ) ) {
|
@@ -610,15 +725,19 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
|
|
610 |
update_site_option( 'wsal_freemius_state', 'skipped' );
|
611 |
}
|
612 |
|
613 |
-
echo wp_json_encode(
|
614 |
-
|
615 |
-
|
616 |
-
|
|
|
|
|
617 |
} else {
|
618 |
-
echo wp_json_encode(
|
619 |
-
|
620 |
-
|
621 |
-
|
|
|
|
|
622 |
}
|
623 |
exit();
|
624 |
}
|
@@ -637,6 +756,10 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
|
|
637 |
'0.4.0'
|
638 |
);
|
639 |
|
|
|
|
|
|
|
|
|
640 |
// Audit log styles.
|
641 |
wp_enqueue_style(
|
642 |
'auditlog',
|
@@ -660,6 +783,15 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
|
|
660 |
'0.4.0' // Script version.
|
661 |
);
|
662 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
663 |
wp_enqueue_script( 'suggest' );
|
664 |
|
665 |
// Audit log script.
|
@@ -677,14 +809,22 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
|
|
677 |
* @param string $hook_suffix - Current hook suffix.
|
678 |
* @since 3.2
|
679 |
*/
|
680 |
-
function load_pointers( $hook_suffix ) {
|
681 |
// Don't run on WP < 3.3.
|
682 |
if ( get_bloginfo( 'version' ) < '3.3' ) {
|
683 |
return;
|
684 |
}
|
685 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
686 |
// Get screen id.
|
687 |
-
$screen
|
688 |
$screen_id = $screen->id;
|
689 |
|
690 |
// Get pointers for this screen.
|
@@ -695,7 +835,7 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
|
|
695 |
}
|
696 |
|
697 |
// Get dismissed pointers.
|
698 |
-
$dismissed
|
699 |
$valid_pointers = array();
|
700 |
|
701 |
// Check pointers and remove dismissed ones.
|
@@ -729,7 +869,8 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
|
|
729 |
'auditlog-pointer',
|
730 |
$this->_plugin->GetBaseUrl() . '/js/auditlog-pointer.js',
|
731 |
array( 'wp-pointer' ),
|
732 |
-
filemtime( $this->_plugin->GetBaseDir() . '/js/auditlog-pointer.js' )
|
|
|
733 |
);
|
734 |
|
735 |
// Add pointer options to script.
|
@@ -751,15 +892,16 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
|
|
751 |
&& ! $this->IsNoticeDismissed( 'wsal-privacy-notice-3.2' )
|
752 |
) {
|
753 |
$pointer['wsal_privacy'] = array(
|
754 |
-
'target'
|
755 |
'options' => array(
|
756 |
-
'content'
|
|
|
757 |
__( 'WordPress Activity Log', 'wp-security-audit-log' ),
|
758 |
__( 'When a user makes a change on your website the plugin will keep a record of that event here. Right now there is nothing because this is a new install.', 'wp-security-audit-log' ),
|
759 |
__( 'Thank you for using WP Security Audit Log', 'wp-security-audit-log' )
|
760 |
),
|
761 |
'position' => array(
|
762 |
-
'edge'
|
763 |
'align' => 'top',
|
764 |
),
|
765 |
),
|
13 |
exit;
|
14 |
}
|
15 |
|
16 |
+
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
17 |
|
18 |
/**
|
19 |
* Audit Log Viewer Page
|
56 |
add_action( 'all_admin_notices', array( $this, 'AdminNoticesPremium' ) );
|
57 |
add_action( 'admin_enqueue_scripts', array( $this, 'load_pointers' ), 1000 );
|
58 |
add_filter( 'wsal_pointers_toplevel_page_wsal-auditlog', array( $this, 'register_privacy_pointer' ), 10, 1 );
|
59 |
+
add_action( 'admin_init', array( $this, 'handle_form_submission' ) );
|
60 |
|
61 |
// Check plugin version for to dismiss the notice only until upgrade.
|
62 |
$this->_version = WSAL_VERSION;
|
104 |
|
105 |
$more_info = add_query_arg(
|
106 |
array(
|
107 |
+
'utm_source' => 'plugin',
|
108 |
+
'utm_medium' => 'banner',
|
109 |
+
'utm_content' => 'audit+log+viewier+more+info',
|
110 |
'utm_campaign' => 'upgrade+premium',
|
111 |
),
|
112 |
'https://www.wpsecurityauditlog.com/premium-features/'
|
237 |
return $this->_listview;
|
238 |
}
|
239 |
|
240 |
+
/**
|
241 |
+
* Handle Audit Log Form Submission
|
242 |
+
*
|
243 |
+
* @since 3.2.3
|
244 |
+
*/
|
245 |
+
public function handle_form_submission() {
|
246 |
+
// Global WP page now variable.
|
247 |
+
global $pagenow;
|
248 |
+
|
249 |
+
// Only run the function on audit log custom page.
|
250 |
+
$page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : false; // Current page.
|
251 |
+
if ( 'admin.php' !== $pagenow ) {
|
252 |
+
return;
|
253 |
+
} elseif ( 'wsal-auditlog' !== $page ) { // Page is admin.php, now check auditlog page.
|
254 |
+
return; // Return if the current page is not auditlog's.
|
255 |
+
}
|
256 |
+
|
257 |
+
// Verify nonce for security.
|
258 |
+
if ( isset( $_GET['_wpnonce'] ) ) {
|
259 |
+
check_admin_referer( 'bulk-logs' );
|
260 |
+
}
|
261 |
+
|
262 |
+
// @codingStandardsIgnoreStart
|
263 |
+
$wpnonce = isset( $_GET['_wpnonce'] ) ? sanitize_text_field( $_GET['_wpnonce'] ) : false; // View nonce.
|
264 |
+
$search = isset( $_GET['s'] ) ? sanitize_text_field( $_GET['s'] ) : false; // Search.
|
265 |
+
$site_id = isset( $_GET['wsal-cbid'] ) ? (int) sanitize_text_field( $_GET['wsal-cbid'] ) : false; // Site id.
|
266 |
+
$search_save = ( isset( $_REQUEST['wsal-save-search-name'] ) && ! empty( $_REQUEST['wsal-save-search-name'] ) ) ? trim( sanitize_text_field( $_REQUEST['wsal-save-search-name'] ) ) : false;
|
267 |
+
// @codingStandardsIgnoreEnd
|
268 |
+
|
269 |
+
if ( ! empty( $wpnonce ) ) {
|
270 |
+
// Remove args array.
|
271 |
+
$remove_args = array(
|
272 |
+
'_wp_http_referer',
|
273 |
+
'_wpnonce',
|
274 |
+
'wsal_as_widget_ip',
|
275 |
+
'load_saved_search_field',
|
276 |
+
);
|
277 |
+
|
278 |
+
if ( empty( $site_id ) ) {
|
279 |
+
$remove_args[] = 'wsal-cbid';
|
280 |
+
}
|
281 |
+
|
282 |
+
if ( empty( $search_save ) ) {
|
283 |
+
$remove_args[] = 'wsal-save-search-name';
|
284 |
+
}
|
285 |
+
|
286 |
+
if ( empty( $search ) ) {
|
287 |
+
$remove_args[] = 's';
|
288 |
+
}
|
289 |
+
wp_safe_redirect( remove_query_arg( $remove_args ) );
|
290 |
+
exit();
|
291 |
+
}
|
292 |
+
}
|
293 |
+
|
294 |
/**
|
295 |
* Render view table of Audit Log.
|
296 |
*
|
297 |
+
* @since 1.0.0
|
298 |
*/
|
299 |
public function Render() {
|
300 |
if ( ! $this->_plugin->settings->CurrentUserCan( 'view' ) ) {
|
301 |
wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'wp-security-audit-log' ) );
|
302 |
}
|
303 |
|
|
|
|
|
|
|
304 |
// Verify nonce for security.
|
305 |
+
if ( isset( $_GET['_wpnonce'] ) ) {
|
306 |
+
check_admin_referer( 'bulk-logs' );
|
307 |
}
|
308 |
|
309 |
+
// @codingStandardsIgnoreStart
|
310 |
+
$wsal_page = isset( $_GET['page'] ) ? sanitize_text_field( $_GET['page'] ) : false; // Admin WSAL Page.
|
311 |
+
$site_id = isset( $_GET['wsal-cbid'] ) ? (int) sanitize_text_field( $_GET['wsal-cbid'] ) : false; // Site id.
|
312 |
+
$search_term = ( isset( $_REQUEST['s'] ) && ! empty( $_REQUEST['s'] ) ) ? trim( sanitize_text_field( $_REQUEST['s'] ) ) : false;
|
313 |
+
$search_filters = ( isset( $_REQUEST['Filters'] ) && is_array( $_REQUEST['Filters'] ) ) ? array_map( 'sanitize_text_field', $_REQUEST['Filters'] ) : false;
|
314 |
+
// @codingStandardsIgnoreEnd
|
315 |
+
|
316 |
$this->GetListView()->prepare_items();
|
317 |
$occ = new WSAL_Models_Occurrence();
|
318 |
|
319 |
?>
|
320 |
+
<form id="audit-log-viewer" method="get">
|
321 |
<div id="audit-log-viewer-content">
|
322 |
+
<input type="hidden" name="page" value="<?php echo esc_attr( $wsal_page ); ?>" />
|
323 |
+
<input type="hidden" id="wsal-cbid" name="wsal-cbid" value="<?php echo esc_attr( empty( $site_id ) ? '0' : $site_id ); ?>" />
|
324 |
<?php do_action( 'wsal_auditlog_before_view', $this->GetListView() ); ?>
|
325 |
<?php $this->GetListView()->display(); ?>
|
326 |
<?php do_action( 'wsal_auditlog_after_view', $this->GetListView() ); ?>
|
327 |
</div>
|
328 |
</form>
|
329 |
|
330 |
+
<?php
|
331 |
+
if (
|
332 |
+
'no' === $this->_plugin->GetGlobalOption( 'wsal-setup-complete', 'no' )
|
333 |
+
&& 'no' === $this->_plugin->GetGlobalOption( 'wsal-setup-modal-dismissed', 'no' )
|
334 |
+
) :
|
335 |
+
?>
|
336 |
+
<div data-remodal-id="wsal-setup-modal">
|
337 |
+
<button data-remodal-action="close" class="remodal-close"></button>
|
338 |
+
<p>
|
339 |
+
<?php esc_html_e( 'Thank you very much for using the WP Security Audit Log plugin. We have created a wizard to ease the process of configuring the plugin so you can get the best out of it. Would you like to run the wizard?', 'wp-security-audit-log' ); ?>
|
340 |
+
</p>
|
341 |
+
<br>
|
342 |
+
<button data-remodal-action="confirm" class="remodal-confirm"><?php esc_html_e( 'Yes', 'wp-security-audit-log' ); ?></button>
|
343 |
+
<button data-remodal-action="cancel" class="remodal-cancel"><?php esc_html_e( 'No', 'wp-security-audit-log' ); ?></button>
|
344 |
+
</div>
|
345 |
+
<script type="text/javascript">
|
346 |
+
jQuery( document ).ready( function() {
|
347 |
+
var wsal_setup_modal = jQuery( '[data-remodal-id="wsal-setup-modal"]' );
|
348 |
+
wsal_setup_modal.remodal().open();
|
349 |
+
|
350 |
+
jQuery(document).on('confirmation', wsal_setup_modal, function () {
|
351 |
+
<?php $this->_plugin->SetGlobalOption( 'wsal-setup-modal-dismissed', 'yes' ); ?>
|
352 |
+
window.location = '<?php echo esc_url( add_query_arg( 'page', 'wsal-setup', admin_url( 'index.php' ) ) ); ?>';
|
353 |
+
});
|
354 |
+
|
355 |
+
jQuery(document).on('cancellation', wsal_setup_modal, function () {
|
356 |
+
<?php $this->_plugin->SetGlobalOption( 'wsal-setup-modal-dismissed', 'yes' ); ?>
|
357 |
+
});
|
358 |
+
|
359 |
+
jQuery(document).on('closed', wsal_setup_modal, function () {
|
360 |
+
<?php $this->_plugin->SetGlobalOption( 'wsal-setup-modal-dismissed', 'yes' ); ?>
|
361 |
+
});
|
362 |
+
});
|
363 |
+
</script>
|
364 |
+
<?php endif; ?>
|
365 |
+
|
366 |
<?php
|
367 |
if ( class_exists( 'WSAL_SearchExtension' ) &&
|
368 |
+
( ! empty( $search_filters ) || ( ! empty( $search_term ) && trim( $search_term ) ) ) ) :
|
369 |
?>
|
370 |
<script type="text/javascript">
|
371 |
jQuery(document).ready( function() {
|
373 |
<?php
|
374 |
echo json_encode(
|
375 |
array(
|
376 |
+
'ajaxurl' => admin_url( 'admin-ajax.php' ),
|
377 |
+
'tr8n' => array(
|
378 |
'numofitems' => __( 'Please enter the number of alerts you would like to see on one page:', 'wp-security-audit-log' ),
|
379 |
'searchback' => __( 'All Sites', 'wp-security-audit-log' ),
|
380 |
'searchnone' => __( 'No Results', 'wp-security-audit-log' ),
|
381 |
),
|
382 |
+
'autorefresh' => array(
|
383 |
+
'enabled' => false,
|
384 |
+
'token' => (int) $occ->Count(),
|
385 |
),
|
386 |
)
|
387 |
);
|
396 |
<?php
|
397 |
echo json_encode(
|
398 |
array(
|
399 |
+
'ajaxurl' => admin_url( 'admin-ajax.php' ),
|
400 |
+
'tr8n' => array(
|
401 |
'numofitems' => __( 'Please enter the number of alerts you would like to see on one page:', 'wp-security-audit-log' ),
|
402 |
'searchback' => __( 'All Sites', 'wp-security-audit-log' ),
|
403 |
'searchnone' => __( 'No Results', 'wp-security-audit-log' ),
|
404 |
),
|
405 |
'autorefresh' => array(
|
406 |
'enabled' => $this->_plugin->settings->IsRefreshAlertsEnabled(),
|
407 |
+
'token' => (int) $occ->Count(),
|
408 |
),
|
409 |
)
|
410 |
);
|
412 |
);
|
413 |
} );
|
414 |
</script>
|
415 |
+
<?php
|
416 |
endif;
|
417 |
}
|
418 |
|
430 |
if ( ! isset( $get_array['occurrence'] ) ) {
|
431 |
die( 'Occurrence parameter expected.' );
|
432 |
}
|
433 |
+
|
434 |
+
// Get selected db.
|
435 |
+
$selected_db = get_transient( 'wsal_wp_selected_db' );
|
436 |
+
$selected_db_user = (int) get_transient( 'wsal_wp_selected_db_user' );
|
437 |
+
|
438 |
+
// Check if archive db is enabled and the current user matches the one who selected archive db.
|
439 |
+
if ( ! empty( $selected_db ) && 'archive' === $selected_db && get_current_user_id() === $selected_db_user ) {
|
440 |
+
$this->_plugin->settings->SwitchToArchiveDB(); // Switch to archive DB.
|
441 |
+
}
|
442 |
+
|
443 |
$occ = new WSAL_Models_Occurrence();
|
444 |
$occ->Load( 'id = %d', array( (int) $get_array['occurrence'] ) );
|
445 |
$alert_meta = $occ->GetMetaArray();
|
568 |
public function wsal_download_failed_login_log() {
|
569 |
// Get post array through filter.
|
570 |
$download_nonce = filter_input( INPUT_POST, 'download_nonce', FILTER_SANITIZE_STRING );
|
571 |
+
$alert_id = filter_input( INPUT_POST, 'alert_id', FILTER_SANITIZE_NUMBER_INT );
|
572 |
|
573 |
// Verify nonce.
|
574 |
+
if ( ! empty( $download_nonce ) && wp_verify_nonce( $download_nonce, 'wsal-download-failed-logins' ) ) {
|
575 |
// Get alert by id.
|
576 |
+
$alert = new WSAL_Models_Occurrence();
|
577 |
$alert->id = (int) $alert_id;
|
578 |
|
579 |
// Get users using alert meta.
|
598 |
*/
|
599 |
public function wsal_download_404_log() {
|
600 |
// Get post array through filter.
|
601 |
+
$nonce = filter_input( INPUT_POST, 'nonce', FILTER_SANITIZE_STRING );
|
602 |
$filename = filter_input( INPUT_POST, 'log_file', FILTER_SANITIZE_STRING );
|
603 |
+
$site_id = filter_input( INPUT_POST, 'site_id', FILTER_SANITIZE_NUMBER_INT );
|
604 |
|
605 |
// If file name is empty then return error.
|
606 |
if ( empty( $filename ) ) {
|
607 |
// Nonce verification failed.
|
608 |
+
echo wp_json_encode(
|
609 |
+
array(
|
610 |
+
'success' => false,
|
611 |
+
'message' => esc_html__( 'Log file does not exist.', 'wp-security-audit-log' ),
|
612 |
+
)
|
613 |
+
);
|
614 |
die();
|
615 |
}
|
616 |
|
617 |
// Verify nonce.
|
618 |
+
if ( ! empty( $filename ) && ! empty( $nonce ) && wp_verify_nonce( $nonce, 'wsal-download-404-log-' . $filename ) ) {
|
619 |
// Set log file path.
|
620 |
+
$uploads_dir = wp_upload_dir();
|
621 |
|
622 |
if ( ! $site_id ) {
|
623 |
$position = strpos( $filename, '/sites/' );
|
630 |
}
|
631 |
$log_file_path = trailingslashit( $uploads_dir['basedir'] ) . $filename;
|
632 |
} else {
|
633 |
+
$position = strpos( $filename, '/wp-security-audit-log/' );
|
634 |
+
$filename = substr( $filename, $position );
|
635 |
$log_file_path = trailingslashit( $uploads_dir['basedir'] ) . $filename;
|
636 |
}
|
637 |
|
641 |
// Check if the response is valid.
|
642 |
if ( $response ) {
|
643 |
// Return the file body.
|
644 |
+
echo wp_json_encode(
|
645 |
+
array(
|
646 |
+
'success' => true,
|
647 |
+
'filename' => $filename,
|
648 |
+
'file_content' => $response,
|
649 |
+
)
|
650 |
+
);
|
651 |
} else {
|
652 |
// Request failed.
|
653 |
+
echo wp_json_encode(
|
654 |
+
array(
|
655 |
+
'success' => false,
|
656 |
+
'message' => esc_html__( 'Request to get log file failed.', 'wp-security-audit-log' ),
|
657 |
+
)
|
658 |
+
);
|
659 |
}
|
660 |
} else {
|
661 |
// Nonce verification failed.
|
662 |
+
echo wp_json_encode(
|
663 |
+
array(
|
664 |
+
'success' => false,
|
665 |
+
'message' => esc_html__( 'Nonce verification failed.', 'wp-security-audit-log' ),
|
666 |
+
)
|
667 |
+
);
|
668 |
}
|
669 |
die();
|
670 |
}
|
685 |
// Verify nonce.
|
686 |
if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'wsal-freemius-opt' ) ) {
|
687 |
// Nonce verification failed.
|
688 |
+
echo wp_json_encode(
|
689 |
+
array(
|
690 |
+
'success' => false,
|
691 |
+
'message' => esc_html__( 'Nonce verification failed.', 'wp-security-audit-log' ),
|
692 |
+
)
|
693 |
+
);
|
694 |
exit();
|
695 |
}
|
696 |
|
701 |
wsal_freemius()->opt_in(); // Opt in.
|
702 |
} else {
|
703 |
// Get sites.
|
704 |
+
$sites = Freemius::get_sites();
|
705 |
$sites_data = array();
|
706 |
|
707 |
if ( ! empty( $sites ) ) {
|
725 |
update_site_option( 'wsal_freemius_state', 'skipped' );
|
726 |
}
|
727 |
|
728 |
+
echo wp_json_encode(
|
729 |
+
array(
|
730 |
+
'success' => true,
|
731 |
+
'message' => esc_html__( 'Freemius opt choice selected.', 'wp-security-audit-log' ),
|
732 |
+
)
|
733 |
+
);
|
734 |
} else {
|
735 |
+
echo wp_json_encode(
|
736 |
+
array(
|
737 |
+
'success' => false,
|
738 |
+
'message' => esc_html__( 'Freemius opt choice not found.', 'wp-security-audit-log' ),
|
739 |
+
)
|
740 |
+
);
|
741 |
}
|
742 |
exit();
|
743 |
}
|
756 |
'0.4.0'
|
757 |
);
|
758 |
|
759 |
+
// Remodal styles.
|
760 |
+
wp_enqueue_style( 'wsal-remodal', $this->_plugin->GetBaseUrl() . '/css/remodal.css', array(), '1.1.1' );
|
761 |
+
wp_enqueue_style( 'wsal-remodal-theme', $this->_plugin->GetBaseUrl() . '/css/remodal-default-theme.css', array(), '1.1.1' );
|
762 |
+
|
763 |
// Audit log styles.
|
764 |
wp_enqueue_style(
|
765 |
'auditlog',
|
783 |
'0.4.0' // Script version.
|
784 |
);
|
785 |
|
786 |
+
// Remodal script.
|
787 |
+
wp_enqueue_script(
|
788 |
+
'wsal-remodal-js',
|
789 |
+
$this->_plugin->GetBaseUrl() . '/js/remodal.min.js',
|
790 |
+
array(),
|
791 |
+
'1.1.1',
|
792 |
+
true
|
793 |
+
);
|
794 |
+
|
795 |
wp_enqueue_script( 'suggest' );
|
796 |
|
797 |
// Audit log script.
|
809 |
* @param string $hook_suffix - Current hook suffix.
|
810 |
* @since 3.2
|
811 |
*/
|
812 |
+
public function load_pointers( $hook_suffix ) {
|
813 |
// Don't run on WP < 3.3.
|
814 |
if ( get_bloginfo( 'version' ) < '3.3' ) {
|
815 |
return;
|
816 |
}
|
817 |
|
818 |
+
// Don't display notice if the wizard notice is showing.
|
819 |
+
if (
|
820 |
+
'no' === $this->_plugin->GetGlobalOption( 'wsal-setup-complete', 'no' )
|
821 |
+
&& 'no' === $this->_plugin->GetGlobalOption( 'wsal-setup-modal-dismissed', 'no' )
|
822 |
+
) {
|
823 |
+
return;
|
824 |
+
}
|
825 |
+
|
826 |
// Get screen id.
|
827 |
+
$screen = get_current_screen();
|
828 |
$screen_id = $screen->id;
|
829 |
|
830 |
// Get pointers for this screen.
|
835 |
}
|
836 |
|
837 |
// Get dismissed pointers.
|
838 |
+
$dismissed = explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) );
|
839 |
$valid_pointers = array();
|
840 |
|
841 |
// Check pointers and remove dismissed ones.
|
869 |
'auditlog-pointer',
|
870 |
$this->_plugin->GetBaseUrl() . '/js/auditlog-pointer.js',
|
871 |
array( 'wp-pointer' ),
|
872 |
+
filemtime( $this->_plugin->GetBaseDir() . '/js/auditlog-pointer.js' ),
|
873 |
+
true
|
874 |
);
|
875 |
|
876 |
// Add pointer options to script.
|
892 |
&& ! $this->IsNoticeDismissed( 'wsal-privacy-notice-3.2' )
|
893 |
) {
|
894 |
$pointer['wsal_privacy'] = array(
|
895 |
+
'target' => '#toplevel_page_wsal-auditlog .wp-first-item',
|
896 |
'options' => array(
|
897 |
+
'content' => sprintf(
|
898 |
+
'<h3> %s </h3> <p> %s </p> <p><strong>%s</strong></p>',
|
899 |
__( 'WordPress Activity Log', 'wp-security-audit-log' ),
|
900 |
__( 'When a user makes a change on your website the plugin will keep a record of that event here. Right now there is nothing because this is a new install.', 'wp-security-audit-log' ),
|
901 |
__( 'Thank you for using WP Security Audit Log', 'wp-security-audit-log' )
|
902 |
),
|
903 |
'position' => array(
|
904 |
+
'edge' => 'left',
|
905 |
'align' => 'top',
|
906 |
),
|
907 |
),
|
classes/Views/Help.php
CHANGED
@@ -257,7 +257,7 @@ class WSAL_Views_Help extends WSAL_AbstractView {
|
|
257 |
// System info.
|
258 |
global $wpdb;
|
259 |
|
260 |
-
$sysinfo
|
261 |
|
262 |
// Start with the basics...
|
263 |
$sysinfo .= '-- Site Info --' . "\n\n";
|
@@ -267,7 +267,7 @@ class WSAL_Views_Help extends WSAL_AbstractView {
|
|
267 |
|
268 |
// Browser information.
|
269 |
if ( ! class_exists( 'WSAL_Browser' ) && file_exists( WSAL_BASE_DIR . 'sdk/class-wsal-browser.php' ) ) {
|
270 |
-
require_once
|
271 |
|
272 |
$browser = new WSAL_Browser();
|
273 |
$sysinfo .= "\n" . '-- User Browser --' . "\n\n";
|
@@ -300,7 +300,7 @@ class WSAL_Views_Help extends WSAL_AbstractView {
|
|
300 |
// Only show page specs if frontpage is set to 'page'.
|
301 |
if ( 'page' === get_option( 'show_on_front' ) ) {
|
302 |
$front_page_id = (int) get_option( 'page_on_front' );
|
303 |
-
$blog_page_id
|
304 |
|
305 |
$sysinfo .= 'Page On Front: ' . ( 0 !== $front_page_id ? get_the_title( $front_page_id ) . ' (#' . $front_page_id . ')' : 'Unset' ) . "\n";
|
306 |
$sysinfo .= 'Page For Posts: ' . ( 0 !== $blog_page_id ? get_the_title( $blog_page_id ) . ' (#' . $blog_page_id . ')' : 'Unset' ) . "\n";
|
@@ -327,15 +327,24 @@ class WSAL_Views_Help extends WSAL_AbstractView {
|
|
327 |
// WordPress active plugins.
|
328 |
$sysinfo .= "\n" . '-- WordPress Active Plugins --' . "\n\n";
|
329 |
|
330 |
-
$plugins
|
331 |
$active_plugins = get_option( 'active_plugins', array() );
|
332 |
|
333 |
foreach ( $plugins as $plugin_path => $plugin ) {
|
334 |
-
if ( ! in_array( $plugin_path, $active_plugins ) )
|
335 |
continue;
|
|
|
336 |
|
337 |
-
|
338 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
339 |
}
|
340 |
|
341 |
// WordPress inactive plugins.
|
@@ -346,15 +355,23 @@ class WSAL_Views_Help extends WSAL_AbstractView {
|
|
346 |
continue;
|
347 |
}
|
348 |
|
349 |
-
|
350 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
351 |
}
|
352 |
|
353 |
if ( is_multisite() ) {
|
354 |
// WordPress Multisite active plugins.
|
355 |
$sysinfo .= "\n" . '-- Network Active Plugins --' . "\n\n";
|
356 |
|
357 |
-
$plugins
|
358 |
$active_plugins = get_site_option( 'active_sitewide_plugins', array() );
|
359 |
|
360 |
foreach ( $plugins as $plugin_path ) {
|
@@ -364,17 +381,26 @@ class WSAL_Views_Help extends WSAL_AbstractView {
|
|
364 |
continue;
|
365 |
}
|
366 |
|
367 |
-
|
368 |
-
|
369 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
370 |
}
|
371 |
}
|
372 |
|
373 |
// Server configuration.
|
374 |
$server_software = filter_input( INPUT_SERVER, 'SERVER_SOFTWARE', FILTER_SANITIZE_STRING );
|
375 |
-
$sysinfo
|
376 |
-
$sysinfo
|
377 |
-
$sysinfo
|
378 |
|
379 |
if ( isset( $server_software ) ) {
|
380 |
$sysinfo .= 'Webserver Info: ' . $server_software . "\n";
|
@@ -396,7 +422,7 @@ class WSAL_Views_Help extends WSAL_AbstractView {
|
|
396 |
|
397 |
// WSAL options.
|
398 |
$sysinfo .= "\n" . '-- WSAL Options --' . "\n\n";
|
399 |
-
$options
|
400 |
|
401 |
if ( ! empty( $options ) && is_array( $options ) ) {
|
402 |
foreach ( $options as $index => $option ) {
|
257 |
// System info.
|
258 |
global $wpdb;
|
259 |
|
260 |
+
$sysinfo = '### System Info → Begin ###' . "\n\n";
|
261 |
|
262 |
// Start with the basics...
|
263 |
$sysinfo .= '-- Site Info --' . "\n\n";
|
267 |
|
268 |
// Browser information.
|
269 |
if ( ! class_exists( 'WSAL_Browser' ) && file_exists( WSAL_BASE_DIR . 'sdk/class-wsal-browser.php' ) ) {
|
270 |
+
require_once WSAL_BASE_DIR . 'sdk/class-wsal-browser.php';
|
271 |
|
272 |
$browser = new WSAL_Browser();
|
273 |
$sysinfo .= "\n" . '-- User Browser --' . "\n\n";
|
300 |
// Only show page specs if frontpage is set to 'page'.
|
301 |
if ( 'page' === get_option( 'show_on_front' ) ) {
|
302 |
$front_page_id = (int) get_option( 'page_on_front' );
|
303 |
+
$blog_page_id = (int) get_option( 'page_for_posts' );
|
304 |
|
305 |
$sysinfo .= 'Page On Front: ' . ( 0 !== $front_page_id ? get_the_title( $front_page_id ) . ' (#' . $front_page_id . ')' : 'Unset' ) . "\n";
|
306 |
$sysinfo .= 'Page For Posts: ' . ( 0 !== $blog_page_id ? get_the_title( $blog_page_id ) . ' (#' . $blog_page_id . ')' : 'Unset' ) . "\n";
|
327 |
// WordPress active plugins.
|
328 |
$sysinfo .= "\n" . '-- WordPress Active Plugins --' . "\n\n";
|
329 |
|
330 |
+
$plugins = get_plugins();
|
331 |
$active_plugins = get_option( 'active_plugins', array() );
|
332 |
|
333 |
foreach ( $plugins as $plugin_path => $plugin ) {
|
334 |
+
if ( ! in_array( $plugin_path, $active_plugins ) ) {
|
335 |
continue;
|
336 |
+
}
|
337 |
|
338 |
+
if (
|
339 |
+
'WP Security Audit Log' === $plugin['Name']
|
340 |
+
&& wsal_freemius()->can_use_premium_code()
|
341 |
+
) {
|
342 |
+
$update = ( array_key_exists( $plugin_path, $updates ) ) ? ' (needs update - ' . $updates[ $plugin_path ]->update->new_version . ')' : '';
|
343 |
+
$sysinfo .= $plugin['Name'] . ' Premium: ' . $plugin['Version'] . $update . "\n";
|
344 |
+
} else {
|
345 |
+
$update = ( array_key_exists( $plugin_path, $updates ) ) ? ' (needs update - ' . $updates[ $plugin_path ]->update->new_version . ')' : '';
|
346 |
+
$sysinfo .= $plugin['Name'] . ': ' . $plugin['Version'] . $update . "\n";
|
347 |
+
}
|
348 |
}
|
349 |
|
350 |
// WordPress inactive plugins.
|
355 |
continue;
|
356 |
}
|
357 |
|
358 |
+
if (
|
359 |
+
'WP Security Audit Log' === $plugin['Name']
|
360 |
+
&& wsal_freemius()->can_use_premium_code()
|
361 |
+
) {
|
362 |
+
$update = ( array_key_exists( $plugin_path, $updates ) ) ? ' (needs update - ' . $updates[ $plugin_path ]->update->new_version . ')' : '';
|
363 |
+
$sysinfo .= $plugin['Name'] . ' Premium: ' . $plugin['Version'] . $update . "\n";
|
364 |
+
} else {
|
365 |
+
$update = ( array_key_exists( $plugin_path, $updates ) ) ? ' (needs update - ' . $updates[ $plugin_path ]->update->new_version . ')' : '';
|
366 |
+
$sysinfo .= $plugin['Name'] . ': ' . $plugin['Version'] . $update . "\n";
|
367 |
+
}
|
368 |
}
|
369 |
|
370 |
if ( is_multisite() ) {
|
371 |
// WordPress Multisite active plugins.
|
372 |
$sysinfo .= "\n" . '-- Network Active Plugins --' . "\n\n";
|
373 |
|
374 |
+
$plugins = wp_get_active_network_plugins();
|
375 |
$active_plugins = get_site_option( 'active_sitewide_plugins', array() );
|
376 |
|
377 |
foreach ( $plugins as $plugin_path ) {
|
381 |
continue;
|
382 |
}
|
383 |
|
384 |
+
if (
|
385 |
+
'WP Security Audit Log' === $plugin['Name']
|
386 |
+
&& wsal_freemius()->can_use_premium_code()
|
387 |
+
) {
|
388 |
+
$update = ( array_key_exists( $plugin_path, $updates ) ) ? ' (needs update - ' . $updates[ $plugin_path ]->update->new_version . ')' : '';
|
389 |
+
$plugin = get_plugin_data( $plugin_path );
|
390 |
+
$sysinfo .= $plugin['Name'] . ' Premium: ' . $plugin['Version'] . $update . "\n";
|
391 |
+
} else {
|
392 |
+
$update = ( array_key_exists( $plugin_path, $updates ) ) ? ' (needs update - ' . $updates[ $plugin_path ]->update->new_version . ')' : '';
|
393 |
+
$plugin = get_plugin_data( $plugin_path );
|
394 |
+
$sysinfo .= $plugin['Name'] . ': ' . $plugin['Version'] . $update . "\n";
|
395 |
+
}
|
396 |
}
|
397 |
}
|
398 |
|
399 |
// Server configuration.
|
400 |
$server_software = filter_input( INPUT_SERVER, 'SERVER_SOFTWARE', FILTER_SANITIZE_STRING );
|
401 |
+
$sysinfo .= "\n" . '-- Webserver Configuration --' . "\n\n";
|
402 |
+
$sysinfo .= 'PHP Version: ' . PHP_VERSION . "\n";
|
403 |
+
$sysinfo .= 'MySQL Version: ' . $wpdb->db_version() . "\n";
|
404 |
|
405 |
if ( isset( $server_software ) ) {
|
406 |
$sysinfo .= 'Webserver Info: ' . $server_software . "\n";
|
422 |
|
423 |
// WSAL options.
|
424 |
$sysinfo .= "\n" . '-- WSAL Options --' . "\n\n";
|
425 |
+
$options = $this->get_wsal_options();
|
426 |
|
427 |
if ( ! empty( $options ) && is_array( $options ) ) {
|
428 |
foreach ( $options as $index => $option ) {
|
classes/Views/Settings.php
CHANGED
@@ -36,6 +36,22 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
|
|
36 |
*/
|
37 |
private $scan_settings = array();
|
38 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
/**
|
40 |
* Method: Constructor.
|
41 |
*
|
@@ -52,6 +68,64 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
|
|
52 |
add_action( 'wp_ajax_wsal_scan_remove_exception', array( $this, 'scan_remove_exception_file' ) );
|
53 |
add_action( 'wp_ajax_wsal_manual_scan_now', array( $this, 'run_manual_scan_now' ) );
|
54 |
add_action( 'wp_ajax_wsal_stop_file_changes_scan', array( $this, 'stop_file_changes_scan' ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
}
|
56 |
|
57 |
/**
|
@@ -95,39 +169,7 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
|
|
95 |
* @param string $token - Token type.
|
96 |
*/
|
97 |
protected function GetTokenType( $token ) {
|
98 |
-
|
99 |
-
$users = array();
|
100 |
-
foreach ( get_users( 'blog_id=0&fields[]=user_login' ) as $obj ) {
|
101 |
-
$users[] = $obj->user_login;
|
102 |
-
}
|
103 |
-
|
104 |
-
// Get user roles.
|
105 |
-
$roles = array_keys( get_editable_roles() );
|
106 |
-
|
107 |
-
// Get custom post types.
|
108 |
-
$post_types = get_post_types( array(), 'names', 'and' );
|
109 |
-
|
110 |
-
// Check if the token matched users.
|
111 |
-
if ( in_array( $token, $users ) ) {
|
112 |
-
return 'user';
|
113 |
-
}
|
114 |
-
|
115 |
-
// Check if the token matched user roles.
|
116 |
-
if ( in_array( $token, $roles ) ) {
|
117 |
-
return 'role';
|
118 |
-
}
|
119 |
-
|
120 |
-
// Check if the token matched post types.
|
121 |
-
if ( in_array( $token, $post_types ) ) {
|
122 |
-
return 'cpts';
|
123 |
-
}
|
124 |
-
|
125 |
-
// Check if the token matches a URL.
|
126 |
-
if ( ( false !== strpos( $token, home_url() ) ) && filter_var( $token, FILTER_VALIDATE_URL ) ) {
|
127 |
-
return 'urls';
|
128 |
-
}
|
129 |
-
|
130 |
-
return 'other';
|
131 |
}
|
132 |
|
133 |
/**
|
@@ -142,122 +184,31 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
|
|
142 |
|
143 |
// Load saved settings of this view.
|
144 |
$this->scan_settings = array(
|
145 |
-
'scan_file_changes'
|
146 |
-
'scan_frequency'
|
147 |
-
'scan_hour'
|
148 |
-
'scan_day'
|
149 |
-
'scan_date'
|
150 |
-
'scan_directories'
|
151 |
-
'scan_excluded_dirs'
|
152 |
-
'scan_excluded_extensions' => $this->_plugin->GetGlobalOption( 'scan-excluded-extensions', array( 'jpg', 'jpeg', 'png', 'bmp', 'pdf', 'txt', 'log', 'mo', 'po', 'mp3', 'wav' ) ),
|
153 |
-
'scan_in_progress'
|
154 |
);
|
155 |
}
|
156 |
|
157 |
/**
|
158 |
* Method: Save settings.
|
|
|
|
|
159 |
*/
|
160 |
protected function Save() {
|
161 |
check_admin_referer( 'wsal-settings' );
|
162 |
|
163 |
-
//
|
164 |
-
$
|
165 |
-
|
166 |
-
// Get pruning date.
|
167 |
-
$pruning_date = isset( $post_array['PruningDate'] ) ? (int) $post_array['PruningDate'] : '';
|
168 |
-
$pruning_date = ( ! empty( $pruning_date ) ) ? $pruning_date . ' months' : '';
|
169 |
-
|
170 |
-
$this->_plugin->settings->SetPruningDateEnabled( isset( $post_array['PruneBy'] ) ? 'date' === $post_array['PruneBy'] : '' );
|
171 |
-
$this->_plugin->settings->SetPruningDate( $pruning_date );
|
172 |
-
$this->_plugin->settings->SetPruningLimitEnabled( isset( $post_array['PruneBy'] ) ? 'limit' === $post_array['PruneBy'] : '' );
|
173 |
-
$this->_plugin->settings->SetPruningLimit( isset( $post_array['PruningLimit'] ) ? $post_array['PruningLimit'] : '' );
|
174 |
-
|
175 |
-
$this->_plugin->settings->SetFromEmail( $post_array['FromEmail'] );
|
176 |
-
$this->_plugin->settings->SetDisplayName( $post_array['DisplayName'] );
|
177 |
-
|
178 |
-
$this->_plugin->settings->SetWidgetsEnabled( $post_array['EnableDashboardWidgets'] );
|
179 |
-
$this->_plugin->settings->SetAllowedPluginViewers( isset( $post_array['Viewers'] ) ? $post_array['Viewers'] : array() );
|
180 |
-
$this->_plugin->settings->SetAllowedPluginEditors( isset( $post_array['Editors'] ) ? $post_array['Editors'] : array() );
|
181 |
-
|
182 |
-
$this->_plugin->settings->SetExcludedMonitoringUsers( isset( $post_array['ExUsers'] ) ? $post_array['ExUsers'] : array() );
|
183 |
-
$this->_plugin->settings->SetExcludedMonitoringRoles( isset( $post_array['ExRoles'] ) ? $post_array['ExRoles'] : array() );
|
184 |
-
$this->_plugin->settings->SetExcludedMonitoringCustom( isset( $post_array['Customs'] ) ? $post_array['Customs'] : array() );
|
185 |
-
$this->_plugin->settings->SetExcludedMonitoringIP( isset( $post_array['IpAddrs'] ) ? $post_array['IpAddrs'] : array() );
|
186 |
-
$this->_plugin->settings->set_excluded_post_types( isset( $post_array['ExCPTss'] ) ? $post_array['ExCPTss'] : array() );
|
187 |
-
$this->_plugin->settings->set_excluded_urls( isset( $post_array['ExURLss'] ) ? $post_array['ExURLss'] : array() );
|
188 |
-
|
189 |
-
$this->_plugin->settings->SetRestrictAdmins( isset( $post_array['RestrictAdmins'] ) );
|
190 |
-
$this->_plugin->settings->set_login_page_notification( isset( $post_array['login_page_notification'] ) ? 'true' : 'false' );
|
191 |
-
$this->_plugin->settings->set_login_page_notification_text( isset( $post_array['login_page_notification_text'] ) ? $post_array['login_page_notification_text'] : false );
|
192 |
-
$this->_plugin->settings->SetRefreshAlertsEnabled( $post_array['EnableAuditViewRefresh'] );
|
193 |
-
$this->_plugin->settings->SetMainIPFromProxy( isset( $post_array['EnableProxyIpCapture'] ) );
|
194 |
-
$this->_plugin->settings->SetInternalIPsFiltering( isset( $post_array['EnableIpFiltering'] ) );
|
195 |
-
$this->_plugin->settings->SetIncognito( isset( $post_array['Incognito'] ) );
|
196 |
-
$this->_plugin->settings->SetDeleteData( isset( $post_array['DeleteData'] ) );
|
197 |
-
$this->_plugin->settings->SetTimezone( $post_array['Timezone'] );
|
198 |
-
$this->_plugin->settings->set_type_username( $post_array['type_username'] );
|
199 |
-
$this->_plugin->settings->SetWPBackend( isset( $post_array['WPBackend'] ) );
|
200 |
-
if ( ! empty( $post_array['Columns'] ) ) {
|
201 |
-
$this->_plugin->settings->SetColumns( $post_array['Columns'] );
|
202 |
-
}
|
203 |
-
$this->_plugin->settings->ClearDevOptions();
|
204 |
-
|
205 |
-
if ( isset( $post_array['DevOptions'] ) ) {
|
206 |
-
foreach ( $post_array['DevOptions'] as $opt ) {
|
207 |
-
$this->_plugin->settings->SetDevOptionEnabled( $opt, true );
|
208 |
-
}
|
209 |
-
}
|
210 |
-
|
211 |
-
// Check and save enable/disable file changes feature.
|
212 |
-
if ( isset( $post_array['wsal-file-changes'] ) && ! empty( $post_array['wsal-file-changes'] ) ) {
|
213 |
-
$this->_plugin->SetGlobalOption( 'scan-file-changes', $post_array['wsal-file-changes'] );
|
214 |
-
|
215 |
-
// Get file change scan alerts.
|
216 |
-
$file_change_events = $this->_plugin->alerts->get_alerts_by_sub_category( 'File Changes' );
|
217 |
-
$file_change_events = array_keys( $file_change_events );
|
218 |
-
|
219 |
-
// Enable/disable events based on file changes.
|
220 |
-
if ( 'disable' === $post_array['wsal-file-changes'] ) {
|
221 |
-
// Get disabled events.
|
222 |
-
$disabled_events = $this->_plugin->settings->GetDisabledAlerts();
|
223 |
-
|
224 |
-
// Merge file changes events.
|
225 |
-
$disabled_events = array_merge( $disabled_events, $file_change_events );
|
226 |
-
|
227 |
-
// Save the events.
|
228 |
-
$this->_plugin->alerts->SetDisabledAlerts( $disabled_events );
|
229 |
-
} else {
|
230 |
-
// Get disabled events.
|
231 |
-
$disabled_events = $this->_plugin->settings->GetDisabledAlerts();
|
232 |
-
|
233 |
-
foreach ( $file_change_events as $file_change_event ) {
|
234 |
-
// Search for file change events in disabled events.
|
235 |
-
$key = array_search( $file_change_event, $disabled_events, true );
|
236 |
-
|
237 |
-
// If key is found, then unset it.
|
238 |
-
if ( $key ) {
|
239 |
-
unset( $disabled_events[ $key ] );
|
240 |
-
}
|
241 |
-
}
|
242 |
-
|
243 |
-
// Save the disabled events.
|
244 |
-
$this->_plugin->alerts->SetDisabledAlerts( $disabled_events );
|
245 |
-
}
|
246 |
} else {
|
247 |
-
|
248 |
-
}
|
249 |
-
|
250 |
-
// Check and save scan frequency.
|
251 |
-
$this->_plugin->SetGlobalOption( 'scan-frequency', isset( $post_array['wsal-scan-frequency'] ) ? $post_array['wsal-scan-frequency'] : false );
|
252 |
-
$this->_plugin->SetGlobalOption( 'scan-hour', isset( $post_array['wsal-scan-hour'] ) ? $post_array['wsal-scan-hour'] : false );
|
253 |
-
$this->_plugin->SetGlobalOption( 'scan-day', isset( $post_array['wsal-scan-day'] ) ? $post_array['wsal-scan-day'] : false );
|
254 |
-
$this->_plugin->SetGlobalOption( 'scan-date', isset( $post_array['wsal-scan-date'] ) ? $post_array['wsal-scan-date'] : false );
|
255 |
-
|
256 |
-
// Check and save scan directories.
|
257 |
-
if ( isset( $post_array['wsal-scan-directories'] )
|
258 |
-
&& is_array( $post_array['wsal-scan-directories'] ) ) {
|
259 |
-
$scan_directories = array_keys( $post_array['wsal-scan-directories'] );
|
260 |
-
$this->_plugin->SetGlobalOption( 'scan-directories', $scan_directories );
|
261 |
}
|
262 |
}
|
263 |
|
@@ -266,16 +217,48 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
|
|
266 |
*/
|
267 |
public function AjaxCheckSecurityToken() {
|
268 |
if ( ! $this->_plugin->settings->CurrentUserCan( 'view' ) ) {
|
269 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
270 |
}
|
271 |
|
272 |
-
|
273 |
-
$
|
|
|
|
|
274 |
|
275 |
-
if ( !
|
276 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
277 |
}
|
278 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
279 |
}
|
280 |
|
281 |
/**
|
@@ -286,7 +269,14 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
|
|
286 |
die( 'Access Denied.' );
|
287 |
}
|
288 |
$this->_plugin->CleanUp();
|
289 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
290 |
exit;
|
291 |
}
|
292 |
|
@@ -319,15 +309,20 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
|
|
319 |
}
|
320 |
}
|
321 |
|
322 |
-
// Load file changes settings.
|
323 |
-
$this->load_file_changes_settings();
|
324 |
?>
|
325 |
-
<
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
331 |
|
332 |
<form id="audit-log-settings" method="post">
|
333 |
<input type="hidden" name="page" value="<?php echo filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING ); ?>" />
|
@@ -337,1049 +332,1491 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
|
|
337 |
<div id="audit-log-adverts">
|
338 |
</div>
|
339 |
<div class="nav-tabs">
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
<tr>
|
457 |
-
<th><label for="login_page_notification"><?php esc_html_e( 'Login Page Notification', 'wp-security-audit-log' ); ?></label></th>
|
458 |
-
<td>
|
459 |
-
<fieldset>
|
460 |
-
<label for="login_page_notification">
|
461 |
-
<?php
|
462 |
-
// Get login page notification checkbox.
|
463 |
-
$wsal_lpn = $this->_plugin->settings->is_login_page_notification();
|
464 |
-
if ( $wsal_lpn && 'true' === $wsal_lpn ) {
|
465 |
-
// If option exists, value is true then set to true.
|
466 |
-
$wsal_lpn = true;
|
467 |
-
} elseif ( $wsal_lpn && 'false' === $wsal_lpn ) {
|
468 |
-
// If option exists, value is false then set to false.
|
469 |
-
$wsal_lpn = false;
|
470 |
-
} elseif ( ! $wsal_lpn ) {
|
471 |
-
// Default option value.
|
472 |
-
$wsal_lpn = false;
|
473 |
-
}
|
474 |
-
?>
|
475 |
-
<input type="checkbox" name="login_page_notification" id="login_page_notification" <?php checked( $wsal_lpn ); ?> />
|
476 |
-
</label>
|
477 |
-
<br />
|
478 |
-
<?php
|
479 |
-
// Get login page notification text.
|
480 |
-
$wsal_lpn_text = $this->_plugin->settings->get_login_page_notification_text();
|
481 |
-
$wsal_lpn_text_default = __( 'For security and auditing purposes, a record of all of your logged-in actions and changes within the WordPress dashboard will be recorded in an audit log with the <a href="https://www.wpsecurityauditlog.com/" target="_blank">WP Security Audit Log plugin</a>. The audit log also includes the IP address where you accessed this site from.', 'wp-security-audit-log' );
|
482 |
-
|
483 |
-
// Allowed HTML tags for this setting.
|
484 |
-
$allowed_tags = array(
|
485 |
-
'a' => array(
|
486 |
-
'href' => array(),
|
487 |
-
'title' => array(),
|
488 |
-
'target' => array(),
|
489 |
-
),
|
490 |
-
);
|
491 |
-
?>
|
492 |
-
<textarea name="login_page_notification_text"
|
493 |
-
id="login_page_notification_text"
|
494 |
-
cols="60" rows="6"
|
495 |
-
<?php echo ( $wsal_lpn ) ? false : 'disabled'; ?>
|
496 |
-
><?php echo ( $wsal_lpn_text ) ? wp_kses( $wsal_lpn_text, $allowed_tags ) : wp_kses( $wsal_lpn_text_default, $allowed_tags ); ?></textarea>
|
497 |
-
<br/>
|
498 |
-
<span class="description">
|
499 |
-
<?php esc_html_e( 'Many compliance regulations (such as the GDRP) require website administrators to tell the users of this website that a log is kept of all the changes they do when logged in.', 'wp-security-audit-log' ); ?>
|
500 |
-
<br />
|
501 |
-
<?php echo wp_kses( __( '<strong>Note: </strong>', 'wp-security-audit-log' ), $this->_plugin->allowed_html_tags ) . esc_html__( 'The only HTML code allowed in the login page notification is for links ( < a href >...< /a > ).', 'wp-security-audit-log' ); ?>
|
502 |
-
</span>
|
503 |
-
</fieldset>
|
504 |
-
</td>
|
505 |
-
</tr>
|
506 |
-
<!-- Developer Options -->
|
507 |
-
<tr>
|
508 |
-
<th><label><?php esc_html_e( 'Developer Options', 'wp-security-audit-log' ); ?></label></th>
|
509 |
-
<td>
|
510 |
-
<fieldset>
|
511 |
-
<?php $any = $this->_plugin->settings->IsAnyDevOptionEnabled(); ?>
|
512 |
-
<a href="javascript:;" style="<?php echo ( $any ) ? 'display: none;' : false; ?>"
|
513 |
-
onclick="jQuery(this).hide().next().show();">
|
514 |
-
<?php esc_html_e( 'Show Developer Options', 'wp-security-audit-log' ); ?>
|
515 |
-
</a>
|
516 |
-
<div style="<?php echo ( ! $any ) ? 'display: none;' : false; ?>">
|
517 |
-
<p style="border-left: 3px solid #FFD000; padding: 2px 8px; margin-left: 6px; margin-bottom: 16px;">
|
518 |
-
<?php esc_html_e( 'Only enable these options on testing, staging and development websites. Enabling any of the settings below on LIVE websites may cause unintended side-effects including degraded performance.', 'wp-security-audit-log' ); ?>
|
519 |
-
</p>
|
520 |
-
<?php
|
521 |
-
foreach ( array(
|
522 |
-
/**
|
523 |
-
WSAL_Settings::OPT_DEV_DATA_INSPECTOR => array(
|
524 |
-
__( 'Data Inspector', 'wp-security-audit-log' ),
|
525 |
-
__( 'View data logged for each triggered alert.', 'wp-security-audit-log' ),
|
526 |
-
),
|
527 |
-
WSAL_Settings::OPT_DEV_PHP_ERRORS => array(
|
528 |
-
__('PHP Errors', 'wp-security-audit-log'),
|
529 |
-
__('Enables sensor for alerts generated from PHP.', 'wp-security-audit-log')
|
530 |
-
), */
|
531 |
-
WSAL_Settings::OPT_DEV_REQUEST_LOG => array(
|
532 |
-
__( 'Request Log', 'wp-security-audit-log' ),
|
533 |
-
__( 'Enables logging request to file.', 'wp-security-audit-log' ),
|
534 |
-
),
|
535 |
-
/**
|
536 |
-
WSAL_Settings::OPT_DEV_BACKTRACE_LOG => array(
|
537 |
-
__('Backtrace', 'wp-security-audit-log'),
|
538 |
-
__('Log full backtrace for PHP-generated alerts.', 'wp-security-audit-log')
|
539 |
-
), */
|
540 |
-
) as $opt => $info ) {
|
541 |
-
?>
|
542 |
-
<label for="devoption_<?php echo esc_attr( $opt ); ?>">
|
543 |
-
<input type="checkbox" name="DevOptions[]" id="devoption_<?php echo esc_attr( $opt ); ?>"
|
544 |
-
<?php checked( $this->_plugin->settings->IsDevOptionEnabled( $opt ) ); ?>
|
545 |
-
value="<?php echo esc_attr( $opt ); ?>">
|
546 |
-
<span><?php echo esc_html( $info[0] ); ?></span>
|
547 |
-
<!-- Title -->
|
548 |
-
<?php if ( isset( $info[1] ) && $info[1] ) : ?>
|
549 |
-
<span class="description"> — <?php echo esc_html( $info[1] ); ?></span>
|
550 |
-
<?php endif; ?>
|
551 |
-
<!-- Description -->
|
552 |
-
</label><br/>
|
553 |
-
<?php
|
554 |
-
}
|
555 |
-
?>
|
556 |
-
<span class="description">
|
557 |
-
<?php esc_html_e( 'The request log file is saved in the /wp-content/uploads/wp-security-audit-log/ directory.', 'wp-security-audit-log' ); ?>
|
558 |
-
</span>
|
559 |
-
</div>
|
560 |
-
</fieldset>
|
561 |
-
</td>
|
562 |
-
</tr>
|
563 |
-
<!-- Hide Plugin in Plugins Page -->
|
564 |
-
<tr>
|
565 |
-
<th><label for="Incognito"><?php esc_html_e( 'Hide Plugin in Plugins Page', 'wp-security-audit-log' ); ?></label></th>
|
566 |
-
<td>
|
567 |
-
<fieldset>
|
568 |
-
<label for="Incognito">
|
569 |
-
<input type="checkbox" name="Incognito" value="1" id="Incognito" <?php checked( $this->_plugin->settings->IsIncognito() ); ?> />
|
570 |
-
<?php esc_html_e( 'Hide', 'wp-security-audit-log' ); ?>
|
571 |
-
</label>
|
572 |
-
<br/>
|
573 |
-
<span class="description">
|
574 |
-
<?php esc_html_e( 'To manually revert this setting set the value of option wsal-hide-plugin to 0 in the wp_wsal_options table.', 'wp-security-audit-log' ); ?>
|
575 |
-
</span>
|
576 |
-
</fieldset>
|
577 |
-
</td>
|
578 |
-
</tr>
|
579 |
-
<!-- Remove Data on Uninstall -->
|
580 |
-
<tr>
|
581 |
-
<th><label for="DeleteData"><?php esc_html_e( 'Remove Data on Uninstall', 'wp-security-audit-log' ); ?></label></th>
|
582 |
-
<td>
|
583 |
-
<fieldset>
|
584 |
-
<label for="DeleteData">
|
585 |
-
<input type="checkbox" name="DeleteData" value="1" id="DeleteData" onclick="return delete_confirm(this);"
|
586 |
-
<?php checked( $this->_plugin->settings->IsDeleteData() ); ?> />
|
587 |
-
<span class="description">
|
588 |
-
<?php esc_html_e( 'Check this box if you would like remove all data when the plugin is deleted.', 'wp-security-audit-log' ); ?>
|
589 |
-
</span>
|
590 |
-
</label>
|
591 |
-
</fieldset>
|
592 |
-
</td>
|
593 |
-
</tr>
|
594 |
-
</tbody>
|
595 |
-
</table>
|
596 |
-
<!-- Audit Log Tab -->
|
597 |
-
<table class="form-table wsal-tab widefat" id="tab-audit-log">
|
598 |
-
<tbody>
|
599 |
-
<!-- Audit Log Retention -->
|
600 |
-
<?php
|
601 |
-
if ( $this->_plugin->settings->IsArchivingEnabled() ) :
|
602 |
?>
|
603 |
-
<
|
604 |
-
<
|
605 |
-
|
606 |
-
|
607 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
608 |
?>
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
<th><label for="delete1"><?php esc_html_e( 'Audit Log Retention', 'wp-security-audit-log' ); ?></label></th>
|
614 |
-
<td>
|
615 |
-
<fieldset>
|
616 |
-
<?php $text = __( '(eg: 1 month)', 'wp-security-audit-log' ); ?>
|
617 |
-
<?php $nbld = ! ($this->_plugin->settings->IsPruningDateEnabled() || $this->_plugin->settings->IsPruningLimitEnabled()); ?>
|
618 |
-
<label for="delete0">
|
619 |
-
<input type="radio" id="delete0" name="PruneBy" value="" <?php checked( $nbld ); ?> />
|
620 |
-
<?php echo esc_html__( 'None', 'wp-security-audit-log' ); ?>
|
621 |
-
</label>
|
622 |
-
</fieldset>
|
623 |
-
<fieldset>
|
624 |
-
<?php $text = __( '(Leave empty or enter 0 to disable automatic pruning.)', 'wp-security-audit-log' ); ?>
|
625 |
-
<?php $nbld = $this->_plugin->settings->IsPruningDateEnabled(); ?>
|
626 |
-
<label for="delete1">
|
627 |
-
<input type="radio" id="delete1" name="PruneBy" value="date" <?php checked( $nbld ); ?> />
|
628 |
-
<?php echo esc_html__( 'Delete events older than', 'wp-security-audit-log' ); ?>
|
629 |
-
</label>
|
630 |
-
<?php
|
631 |
-
// Find and replace ` months` in the string.
|
632 |
-
$pruning_date = str_replace( ' months', '', $this->_plugin->settings->GetPruningDate() );
|
633 |
-
?>
|
634 |
-
<input type="text" id="PruningDate" name="PruningDate" placeholder="<?php echo esc_attr( $text ); ?>"
|
635 |
-
value="<?php echo esc_attr( $pruning_date ); ?>"
|
636 |
-
onfocus="jQuery('#delete1').attr('checked', true);" />
|
637 |
-
<?php esc_html_e( 'months', 'wp-security-audit-log' ); ?>
|
638 |
-
<span class="description"><?php echo esc_html( $text ); ?></span>
|
639 |
-
</fieldset>
|
640 |
-
<fieldset>
|
641 |
-
<?php $text = __( '(eg: 80)', 'wp-security-audit-log' ); ?>
|
642 |
-
<?php $nbld = $this->_plugin->settings->IsPruningLimitEnabled(); ?>
|
643 |
-
<label for="delete2">
|
644 |
-
<input type="radio" id="delete2" name="PruneBy" value="limit" <?php checked( $nbld ); ?> />
|
645 |
-
<?php echo esc_html__( 'Keep up to', 'wp-security-audit-log' ); ?>
|
646 |
-
</label>
|
647 |
-
<input type="text" id="PruningLimit" name="PruningLimit" placeholder="<?php echo esc_attr( $text ); ?>"
|
648 |
-
value="<?php echo esc_attr( $this->_plugin->settings->GetPruningLimit() ); ?>"
|
649 |
-
onfocus="jQuery('#delete2').attr('checked', true);" />
|
650 |
-
<?php echo esc_html__( 'events', 'wp-security-audit-log' ); ?>
|
651 |
-
<span><?php echo esc_html( $text ); ?></span>
|
652 |
-
</fieldset>
|
653 |
-
<p class="description">
|
654 |
-
<?php
|
655 |
-
$next = wp_next_scheduled( 'wsal_cleanup' );
|
656 |
-
echo esc_html__( 'Next Scheduled Cleanup is in ', 'wp-security-audit-log' );
|
657 |
-
echo esc_html( human_time_diff( current_time( 'timestamp' ), $next ) );
|
658 |
-
echo '<!-- ' . esc_html( date( 'dMy H:i:s', $next ) ) . ' --> ';
|
659 |
-
echo sprintf(
|
660 |
-
esc_html__( '(or %s)', 'wp-security-audit-log' ),
|
661 |
-
'<a href="' . esc_url( add_query_arg( 'action', 'AjaxRunCleanup', admin_url( 'admin-ajax.php' ) ) ) . '">' . esc_html__( 'Run Manually', 'wp-security-audit-log' ) . '</a>'
|
662 |
-
);
|
663 |
-
?>
|
664 |
-
</p>
|
665 |
-
</td>
|
666 |
-
</tr>
|
667 |
-
<?php endif; ?>
|
668 |
-
<!-- Can View Alerts -->
|
669 |
-
<tr>
|
670 |
-
<th><label for="ViewerQueryBox"><?php esc_html_e( 'Can View Events', 'wp-security-audit-log' ); ?></label></th>
|
671 |
-
<td>
|
672 |
-
<fieldset>
|
673 |
-
<input type="text" id="ViewerQueryBox" style="float: left; display: block; width: 250px;">
|
674 |
-
<input type="button" id="ViewerQueryAdd" style="float: left; display: block;" class="button-primary" value="Add">
|
675 |
-
<br style="clear: both;"/>
|
676 |
-
<p class="description">
|
677 |
-
<?php esc_html_e( 'Users and Roles in this list can view the security events', 'wp-security-audit-log' ); ?>
|
678 |
-
</p>
|
679 |
-
<div id="ViewerList">
|
680 |
-
<?php foreach ( $this->_plugin->settings->GetAllowedPluginViewers() as $item ) : ?>
|
681 |
-
<span class="sectoken-<?php echo esc_attr( $this->GetTokenType( $item ) ); ?>">
|
682 |
-
<input type="hidden" name="Viewers[]" value="<?php echo esc_attr( $item ); ?>"/>
|
683 |
-
<?php echo esc_html( $item ); ?>
|
684 |
<a href="javascript:;" title="Remove">×</a>
|
685 |
-
|
686 |
-
<?php endforeach; ?>
|
687 |
-
</div>
|
688 |
-
</fieldset>
|
689 |
-
</td>
|
690 |
-
</tr>
|
691 |
-
<!-- Refresh Audit Log Viewer -->
|
692 |
-
<tr>
|
693 |
-
<th><label for="aroption_on"><?php esc_html_e( 'Refresh Audit Log Viewer', 'wp-security-audit-log' ); ?></label></th>
|
694 |
-
<td>
|
695 |
-
<fieldset>
|
696 |
-
<?php $are = $this->_plugin->settings->IsRefreshAlertsEnabled(); ?>
|
697 |
-
<label for="aroption_on">
|
698 |
-
<input type="radio" name="EnableAuditViewRefresh" id="aroption_on" style="margin-top: 2px;"
|
699 |
-
<?php checked( $are ); ?> value="1">
|
700 |
-
<span><?php esc_html_e( 'Automatic', 'wp-security-audit-log' ); ?></span>
|
701 |
-
</label>
|
702 |
-
<span class="description"> — <?php esc_html_e( 'Refresh Audit Log Viewer as soon as there are new events.', 'wp-security-audit-log' ); ?></span>
|
703 |
-
<br/>
|
704 |
-
<label for="aroption_off">
|
705 |
-
<input type="radio" name="EnableAuditViewRefresh" id="aroption_off" style="margin-top: 2px;"
|
706 |
-
<?php checked( $are, false ); ?> value="0">
|
707 |
-
<span><?php esc_html_e( 'Manual', 'wp-security-audit-log' ); ?></span>
|
708 |
-
</label>
|
709 |
-
<span class="description"> — <?php esc_html_e( 'Refresh Audit Log Viewer only when the page is reloaded.', 'wp-security-audit-log' ); ?></span>
|
710 |
-
<br/>
|
711 |
-
</fieldset>
|
712 |
-
</td>
|
713 |
-
</tr>
|
714 |
-
<!-- Alerts Timestamp -->
|
715 |
-
<tr>
|
716 |
-
<th><label for="timezone-default"><?php esc_html_e( 'Events Timestamp', 'wp-security-audit-log' ); ?></label></th>
|
717 |
-
<td>
|
718 |
-
<fieldset>
|
719 |
-
<?php $timezone = $this->_plugin->settings->GetTimezone(); ?>
|
720 |
-
<label for="timezone-default">
|
721 |
-
<input type="radio" name="Timezone" id="timezone-default" style="margin-top: 2px;"
|
722 |
-
<?php checked( $timezone, 0 ); ?> value="0">
|
723 |
-
<span><?php esc_html_e( 'UTC', 'wp-security-audit-log' ); ?></span>
|
724 |
-
</label>
|
725 |
-
<br/>
|
726 |
-
<label for="timezone">
|
727 |
-
<input type="radio" name="Timezone" id="timezone" style="margin-top: 2px;"
|
728 |
-
<?php checked( $timezone, 1 ); ?> value="1">
|
729 |
-
<span><?php esc_html_e( 'WordPress\' timezone', 'wp-security-audit-log' ); ?></span>
|
730 |
-
</label>
|
731 |
-
<br/>
|
732 |
-
<span class="description"><?php esc_html_e( 'Select which timestamp the events should have in the Audit Log viewer. Note that the WordPress\' timezone might be different from that of the server.', 'wp-security-audit-log' ); ?></span>
|
733 |
-
</fieldset>
|
734 |
-
</td>
|
735 |
-
</tr>
|
736 |
-
<!-- Select type of name -->
|
737 |
-
<tr>
|
738 |
-
<th><label for="timezone-default"><?php esc_html_e( 'User Information in Audit Log', 'wp-security-audit-log' ); ?></label></th>
|
739 |
-
<td>
|
740 |
-
<fieldset>
|
741 |
-
<?php $type_username = $this->_plugin->settings->get_type_username(); ?>
|
742 |
-
<label for="column_username">
|
743 |
-
<input type="radio" name="type_username" id="column_username" style="margin-top: 2px;" <?php checked( $type_username, 'username' ); ?> value="username">
|
744 |
-
<span><?php esc_html_e( 'Username', 'wp-security-audit-log' ); ?></span>
|
745 |
-
</label>
|
746 |
-
<br/>
|
747 |
-
<label for="columns_display_name">
|
748 |
-
<input type="radio" name="type_username" id="columns_display_name" style="margin-top: 2px;" <?php checked( $type_username, 'display_name' ); ?> value="display_name">
|
749 |
-
<span><?php esc_html_e( 'First Name & Last Name', 'wp-security-audit-log' ); ?></span>
|
750 |
-
</label>
|
751 |
-
<br/>
|
752 |
-
<span class="description"><?php esc_html_e( 'Select the type of user information that should be displayed in the audit log.', 'wp-security-audit-log' ); ?></span>
|
753 |
-
</fieldset>
|
754 |
-
</td>
|
755 |
-
</tr>
|
756 |
-
<!-- Audit Log Columns Selection -->
|
757 |
-
<tr>
|
758 |
-
<th><label for="columns"><?php esc_html_e( 'Audit Log Columns Selection', 'wp-security-audit-log' ); ?></label></th>
|
759 |
-
<td>
|
760 |
-
<fieldset>
|
761 |
-
<?php $columns = $this->_plugin->settings->GetColumns(); ?>
|
762 |
-
<?php foreach ( $columns as $key => $value ) { ?>
|
763 |
-
<label for="columns">
|
764 |
-
<input type="checkbox" name="Columns[<?php echo esc_attr( $key ); ?>]" id="<?php echo esc_attr( $key ); ?>" class="sel-columns" style="margin-top: 2px;"
|
765 |
-
<?php checked( $value, '1' ); ?> value="1">
|
766 |
-
<?php if ( 'alert_code' !== $key ) : ?>
|
767 |
-
<span><?php echo esc_html( ucwords( str_replace( '_', ' ', $key ) ) ); ?></span>
|
768 |
-
<?php else : ?>
|
769 |
-
<span><?php esc_html_e( 'Event ID', 'wp-security-audit-log' ); ?></span>
|
770 |
-
<?php endif; ?>
|
771 |
-
</label>
|
772 |
-
<br/>
|
773 |
-
<?php } ?>
|
774 |
-
<span class="description"><?php esc_html_e( 'When you disable any of the above such details won’t be shown in the Audit Log viewer though the plugin will still record such information in the database.', 'wp-security-audit-log' ); ?></span>
|
775 |
-
</fieldset>
|
776 |
-
</td>
|
777 |
-
</tr>
|
778 |
-
<!-- Disable Alerts for WordPress Background activity -->
|
779 |
-
<tr>
|
780 |
-
<th><label for="DeleteData"><?php esc_html_e( 'Disable Events for WordPress Background Activity', 'wp-security-audit-log' ); ?></label></th>
|
781 |
-
<td>
|
782 |
-
<fieldset>
|
783 |
-
<label for="WPBackend">
|
784 |
-
<input type="checkbox" name="WPBackend" value="1" id="WPBackend"
|
785 |
-
<?php checked( $this->_plugin->settings->IsWPBackend() ); ?> />
|
786 |
-
<?php esc_html_e( 'Hide activity', 'wp-security-audit-log' ); ?>
|
787 |
-
</label>
|
788 |
-
<br/>
|
789 |
-
<span class="description">
|
790 |
-
<?php esc_html_e( 'For example do not raise an event when WordPress deletes the auto drafts.', 'wp-security-audit-log' ); ?>
|
791 |
</span>
|
792 |
-
|
793 |
-
</
|
794 |
-
</
|
795 |
-
</
|
796 |
-
</
|
797 |
-
<!--
|
798 |
-
|
799 |
-
|
800 |
-
|
801 |
-
|
802 |
-
|
803 |
-
|
804 |
-
|
805 |
-
|
806 |
-
|
807 |
-
|
808 |
-
|
809 |
-
|
810 |
-
|
811 |
-
|
812 |
-
|
813 |
-
|
814 |
-
|
815 |
-
|
816 |
-
<label>
|
817 |
-
<input id="disable"
|
818 |
-
name="wsal-file-changes"
|
819 |
-
type="radio"
|
820 |
-
value="disable"
|
821 |
-
<?php checked( $this->scan_settings['scan_file_changes'], 'disable' ); ?>
|
822 |
-
/>
|
823 |
-
<?php esc_html_e( 'Disable', 'wp-security-audit-log' ); ?>
|
824 |
-
</label>
|
825 |
-
</fieldset>
|
826 |
-
<span class="description">
|
827 |
-
<?php esc_html_e( 'Enable or disable the logging of file changes in the Activity Log.', 'wp-security-audit-log' ); ?>
|
828 |
-
</span>
|
829 |
-
</td>
|
830 |
-
</tr>
|
831 |
-
<!-- wsal-file-changes -->
|
832 |
-
<tr>
|
833 |
-
<th>
|
834 |
-
<label for="wsal-file-alert-types"><?php esc_html_e( 'Alert me when', 'wp-security-audit-log' ); ?></label>
|
835 |
-
</th>
|
836 |
-
<td>
|
837 |
-
<p>
|
838 |
-
<?php
|
839 |
-
$wsal_events_page = '';
|
840 |
-
if ( ! is_multisite() ) {
|
841 |
-
$wsal_events_page = add_query_arg( 'page', 'wsal-togglealerts', admin_url( 'admin.php' ) );
|
842 |
-
} else {
|
843 |
-
$wsal_events_page = add_query_arg( 'page', 'wsal-togglealerts', network_admin_url( 'admin.php' ) );
|
844 |
-
}
|
845 |
-
?>
|
846 |
-
<a href="<?php echo esc_url( $wsal_events_page . '#tab-file-changes' ); ?>">
|
847 |
-
<?php esc_html_e( 'these events happen', 'wp-security-audit-log' ); ?>
|
848 |
-
</a>
|
849 |
-
</p>
|
850 |
<p class="description">
|
851 |
-
<?php esc_html_e( '
|
852 |
</p>
|
853 |
-
</
|
854 |
-
|
855 |
-
|
856 |
-
<tr>
|
857 |
-
<th>
|
858 |
-
<label for="wsal-scan-frequency"><?php esc_html_e( 'Scan Frequency', 'wp-security-audit-log' ); ?></label>
|
859 |
-
</th>
|
860 |
-
<td>
|
861 |
-
<?php
|
862 |
-
$frequency_options = array(
|
863 |
-
'daily' => __( 'Daily', 'wp-security-audit-log' ),
|
864 |
-
'weekly' => __( 'Weekly', 'wp-security-audit-log' ),
|
865 |
-
'monthly' => __( 'Monthly', 'wp-security-audit-log' ),
|
866 |
-
);
|
867 |
-
?>
|
868 |
-
<fieldset id="wsal-scan-frequency">
|
869 |
-
<select name="wsal-scan-frequency">
|
870 |
-
<?php foreach ( $frequency_options as $value => $html ) : ?>
|
871 |
-
<option
|
872 |
-
value="<?php echo esc_attr( $value ); ?>"
|
873 |
-
<?php echo esc_attr( $value === $this->scan_settings['scan_frequency'] ? 'selected' : false ); ?>>
|
874 |
-
<?php echo esc_html( $html ); ?>
|
875 |
-
</option>
|
876 |
-
<?php endforeach; ?>
|
877 |
-
</select>
|
878 |
-
</fieldset>
|
879 |
-
<span class="description">
|
880 |
-
<?php esc_html_e( 'Select the frequency of the file changes scans.', 'wp-security-audit-log' ); ?>
|
881 |
-
</span>
|
882 |
-
</td>
|
883 |
-
</tr>
|
884 |
-
<!-- wsal-scan-frequency -->
|
885 |
-
<tr id="wsal-scan-time">
|
886 |
-
<th>
|
887 |
-
<label for="wsal-scan-hour"><?php esc_html_e( 'Scan Time', 'wp-security-audit-log' ); ?></label>
|
888 |
-
</th>
|
889 |
-
<td>
|
890 |
<?php
|
891 |
-
|
892 |
-
|
893 |
-
|
894 |
-
|
895 |
-
|
896 |
-
|
897 |
-
|
898 |
-
|
899 |
-
|
900 |
-
|
901 |
-
|
902 |
-
|
903 |
-
|
904 |
-
|
905 |
-
|
906 |
-
|
907 |
-
|
908 |
-
|
909 |
-
|
910 |
-
|
911 |
-
|
912 |
-
|
913 |
-
|
914 |
-
|
915 |
-
|
916 |
-
|
917 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
918 |
|
919 |
-
|
920 |
-
|
921 |
-
|
922 |
-
|
923 |
-
|
924 |
-
|
925 |
-
'5' => __( 'Friday', 'wp-security-audit-log' ),
|
926 |
-
'6' => __( 'Saturday', 'wp-security-audit-log' ),
|
927 |
-
'7' => __( 'Sunday', 'wp-security-audit-log' ),
|
928 |
-
);
|
929 |
|
930 |
-
|
931 |
-
|
932 |
-
|
933 |
-
|
934 |
-
|
935 |
-
|
936 |
-
|
937 |
-
|
938 |
-
|
939 |
-
|
940 |
-
|
941 |
-
|
942 |
-
|
943 |
-
|
944 |
-
|
945 |
-
|
946 |
-
|
947 |
-
|
948 |
-
|
949 |
-
|
950 |
-
|
951 |
-
|
952 |
-
'21' => __( '21', 'wp-security-audit-log' ),
|
953 |
-
'22' => __( '22', 'wp-security-audit-log' ),
|
954 |
-
'23' => __( '23', 'wp-security-audit-log' ),
|
955 |
-
'24' => __( '24', 'wp-security-audit-log' ),
|
956 |
-
'25' => __( '25', 'wp-security-audit-log' ),
|
957 |
-
'26' => __( '26', 'wp-security-audit-log' ),
|
958 |
-
'27' => __( '27', 'wp-security-audit-log' ),
|
959 |
-
'28' => __( '28', 'wp-security-audit-log' ),
|
960 |
-
'29' => __( '29', 'wp-security-audit-log' ),
|
961 |
-
'30' => __( '30', 'wp-security-audit-log' ),
|
962 |
-
);
|
963 |
-
?>
|
964 |
-
<fieldset>
|
965 |
-
<span class="wsal-scan-time-container" id="wsal-scan-hour">
|
966 |
-
<select name="wsal-scan-hour">
|
967 |
-
<?php foreach ( $scan_hours as $value => $html ) : ?>
|
968 |
-
<option
|
969 |
-
value="<?php echo esc_attr( $value ); ?>"
|
970 |
-
<?php echo esc_attr( $value == $this->scan_settings['scan_hour'] ? 'selected' : false ); ?>>
|
971 |
-
<?php echo esc_html( $html ); ?>
|
972 |
-
</option>
|
973 |
-
<?php endforeach; ?>
|
974 |
-
</select>
|
975 |
-
<br />
|
976 |
-
<span class="description">
|
977 |
-
<?php esc_html_e( 'Hour', 'wp-security-audit-log' ); ?>
|
978 |
-
</span>
|
979 |
-
</span>
|
980 |
|
981 |
-
|
982 |
-
|
983 |
-
|
984 |
-
|
985 |
-
|
986 |
-
<?php echo esc_attr( $value == $this->scan_settings['scan_day'] ? 'selected' : false ); ?>>
|
987 |
-
<?php echo esc_html( $html ); ?>
|
988 |
-
</option>
|
989 |
-
<?php endforeach; ?>
|
990 |
-
</select>
|
991 |
-
<br />
|
992 |
-
<span class="description">
|
993 |
-
<?php esc_html_e( 'Day', 'wp-security-audit-log' ); ?>
|
994 |
-
</span>
|
995 |
-
</span>
|
996 |
|
997 |
-
|
998 |
-
|
999 |
-
|
1000 |
-
|
1001 |
-
|
1002 |
-
|
1003 |
-
|
1004 |
-
</option>
|
1005 |
-
<?php endforeach; ?>
|
1006 |
-
</select>
|
1007 |
-
<br />
|
1008 |
-
<span class="description">
|
1009 |
-
<?php esc_html_e( 'Day', 'wp-security-audit-log' ); ?>
|
1010 |
-
</span>
|
1011 |
-
</span>
|
1012 |
-
</fieldset>
|
1013 |
-
</td>
|
1014 |
-
</tr>
|
1015 |
-
<tr>
|
1016 |
-
<th>
|
1017 |
-
<label for="wsal-scan-directories"><?php esc_html_e( 'Directories to scan', 'wp-security-audit-log' ); ?></label>
|
1018 |
-
</th>
|
1019 |
-
<td>
|
1020 |
-
<?php
|
1021 |
-
// WP Directories.
|
1022 |
-
$wp_directories = array(
|
1023 |
-
'root' => __( 'Root directory of WordPress (excluding sub directories)', 'wp-security-audit-log' ),
|
1024 |
-
'wp-admin' => __( 'WP Admin directory (/wp-admin/)', 'wp-security-audit-log' ),
|
1025 |
-
'wp-includes' => __( 'WP Includes directory (/wp-includes/)', 'wp-security-audit-log' ),
|
1026 |
-
'wp-content' => __( '/wp-content/ directory (excluding plugins, themes & uploads directories)', 'wp-security-audit-log' ),
|
1027 |
-
'wp-content/themes' => __( 'Themes directory (/wp-content/themes/)', 'wp-security-audit-log' ),
|
1028 |
-
'wp-content/plugins' => __( 'Plugins directory (/wp-content/plugins/)', 'wp-security-audit-log' ),
|
1029 |
-
'wp-content/uploads' => __( 'Uploads directory (/wp-content/uploads/)', 'wp-security-audit-log' ),
|
1030 |
-
);
|
1031 |
|
1032 |
-
|
1033 |
-
|
1034 |
-
|
1035 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1036 |
}
|
1037 |
?>
|
1038 |
-
<
|
1039 |
-
|
1040 |
-
|
1041 |
-
|
1042 |
-
|
1043 |
-
|
1044 |
-
|
1045 |
-
|
1046 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1047 |
<?php echo esc_html( $html ); ?>
|
1048 |
-
</
|
1049 |
-
<br />
|
1050 |
<?php endforeach; ?>
|
1051 |
-
</
|
1052 |
-
<
|
1053 |
-
<?php esc_html_e( 'Select which directories should be scanned for file changes.', 'wp-security-audit-log' ); ?>
|
1054 |
-
</span>
|
1055 |
-
</td>
|
1056 |
-
</tr>
|
1057 |
-
<!-- wsal-scan-directories -->
|
1058 |
-
<tr>
|
1059 |
-
<th>
|
1060 |
-
<label for="wsal_add_dir_name"><?php esc_html_e( 'Exclude All Files in These Directories', 'wp-security-audit-log' ); ?></label>
|
1061 |
-
</th>
|
1062 |
-
<td>
|
1063 |
-
<div class="wsal_file_containter">
|
1064 |
-
<div id="wsal_dirs">
|
1065 |
-
<?php foreach ( $this->scan_settings['scan_excluded_dirs'] as $index => $dir ) : ?>
|
1066 |
-
<span id="wsal_dir-<?php echo esc_attr( $dir ); ?>">
|
1067 |
-
<input type="checkbox" id="<?php echo esc_attr( $dir ); ?>" value="<?php echo esc_attr( $dir ); ?>" />
|
1068 |
-
<label for="<?php echo esc_attr( $dir ); ?>"><?php echo esc_html( $dir ); ?></label>
|
1069 |
-
</span>
|
1070 |
-
<?php endforeach; ?>
|
1071 |
-
</div>
|
1072 |
-
<?php wp_nonce_field( 'wsal-scan-remove-exception-dir', 'wsal_scan_remove_exception_dir' ); ?>
|
1073 |
-
<input class="button" id="wsal_remove_exception_dir" type="button" value="<?php esc_html_e( 'REMOVE', 'wp-security-audit-log' ); ?>" />
|
1074 |
-
</div>
|
1075 |
-
<div class="wsal_file_containter">
|
1076 |
-
<input type="text" id="wsal_add_dir_name" />
|
1077 |
-
<?php wp_nonce_field( 'wsal-scan-exception-dir', 'wsal_scan_exception_dir' ); ?>
|
1078 |
-
<input id="wsal_add_dir" class="button" type="button" value="<?php esc_html_e( 'ADD', 'wp-security-audit-log' ); ?>" />
|
1079 |
-
</div>
|
1080 |
-
<span class="description">
|
1081 |
-
<?php echo sprintf( esc_html__( 'Specify the name of the directory and the path to it in relation to the website\'s root. For example, if you want to want to exclude all files in the sub directory dir1/dir2 specify the following: %s.', 'wp-security-audit-log' ), esc_html( trailingslashit( ABSPATH ) ) . 'dir1/dir2/' ); ?>
|
1082 |
-
<?php esc_html_e( 'Note that when you exclude a sub directory, all the files in that sub directory and all sub directories underneath it will be excluded from the scan.', 'wp-security-audit-log' ); ?>
|
1083 |
-
</span>
|
1084 |
-
<span class="error hide" id="wsal_dir_error"></span>
|
1085 |
-
</td>
|
1086 |
-
</tr>
|
1087 |
-
<!-- wsal-scan-exclude-dirs -->
|
1088 |
-
<tr>
|
1089 |
-
<th>
|
1090 |
-
<label for="wsal_add_file_name"><?php esc_html_e( 'Exclude These Files', 'wp-security-audit-log' ); ?></label>
|
1091 |
-
</th>
|
1092 |
-
<td>
|
1093 |
-
<?php
|
1094 |
-
// Get files to be excluded.
|
1095 |
-
$excluded_files = $this->_plugin->GetGlobalOption( 'scan_excluded_files', array() );
|
1096 |
-
?>
|
1097 |
-
<div class="wsal_file_containter">
|
1098 |
-
<div id="wsal_files">
|
1099 |
-
<?php foreach ( $excluded_files as $index => $file ) : ?>
|
1100 |
-
<span id="wsal_file-<?php echo esc_attr( $file ); ?>">
|
1101 |
-
<input type="checkbox" id="<?php echo esc_attr( $file ); ?>" value="<?php echo esc_attr( $file ); ?>" />
|
1102 |
-
<label for="<?php echo esc_attr( $file ); ?>"><?php echo esc_html( $file ); ?></label>
|
1103 |
-
</span>
|
1104 |
-
<?php endforeach; ?>
|
1105 |
-
</div>
|
1106 |
-
<?php wp_nonce_field( 'wsal-scan-remove-exception-file', 'wsal_scan_remove_exception_file' ); ?>
|
1107 |
-
<input class="button" id="wsal_remove_exception_file" type="button" value="<?php esc_html_e( 'REMOVE', 'wp-security-audit-log' ); ?>" />
|
1108 |
-
</div>
|
1109 |
-
<div class="wsal_file_containter">
|
1110 |
-
<input type="text" id="wsal_add_file_name" />
|
1111 |
-
<?php wp_nonce_field( 'wsal-scan-exception-file', 'wsal_scan_exception_file' ); ?>
|
1112 |
-
<input id="wsal_add_file" class="button" type="button" value="<?php esc_html_e( 'ADD', 'wp-security-audit-log' ); ?>" />
|
1113 |
-
</div>
|
1114 |
<span class="description">
|
1115 |
-
<?php esc_html_e( '
|
1116 |
</span>
|
1117 |
-
|
1118 |
-
|
1119 |
-
|
1120 |
-
|
1121 |
-
|
1122 |
-
|
1123 |
-
|
1124 |
-
|
1125 |
-
|
1126 |
-
|
1127 |
-
|
1128 |
-
|
1129 |
-
|
1130 |
-
<input type="checkbox" id="<?php echo esc_attr( $file_type ); ?>" value="<?php echo esc_attr( $file_type ); ?>" />
|
1131 |
-
<label for="<?php echo esc_attr( $file_type ); ?>"><?php echo esc_html( $file_type ); ?></label>
|
1132 |
-
</span>
|
1133 |
-
<?php endforeach; ?>
|
1134 |
-
</div>
|
1135 |
-
<?php wp_nonce_field( 'wsal-scan-remove-exception-file-type', 'wsal_scan_remove_exception_file_type' ); ?>
|
1136 |
-
<input class="button" id="wsal_remove_exception_file_type" type="button" value="<?php esc_html_e( 'REMOVE', 'wp-security-audit-log' ); ?>" />
|
1137 |
-
</div>
|
1138 |
-
<div class="wsal_file_containter">
|
1139 |
-
<input type="text" id="wsal_add_file_type_name" />
|
1140 |
-
<?php wp_nonce_field( 'wsal-scan-exception-file-type', 'wsal_scan_exception_file_type' ); ?>
|
1141 |
-
<input id="wsal_add_file_type" class="button" type="button" value="<?php esc_html_e( 'ADD', 'wp-security-audit-log' ); ?>" />
|
1142 |
-
</div>
|
1143 |
<span class="description">
|
1144 |
-
<?php esc_html_e( '
|
1145 |
</span>
|
1146 |
-
|
1147 |
-
|
1148 |
-
|
1149 |
-
|
1150 |
-
|
1151 |
-
|
1152 |
-
|
1153 |
-
|
1154 |
-
|
1155 |
-
|
1156 |
-
|
1157 |
-
|
1158 |
-
<a href="javascript:;" class="button button-primary" id="wsal-scan-now">
|
1159 |
-
<?php esc_attr_e( 'Scan Now', 'wp-security-audit-log' ); ?>
|
1160 |
-
</a>
|
1161 |
-
<a href="javascript:;" class="button button-secondary" id="wsal-stop-scan" disabled>
|
1162 |
-
<?php esc_attr_e( 'Stop Scan', 'wp-security-audit-log' ); ?>
|
1163 |
-
</a>
|
1164 |
-
<?php else : ?>
|
1165 |
-
<a href="javascript:;" class="button button-primary" id="wsal-scan-now" disabled>
|
1166 |
-
<?php esc_attr_e( 'Scan in Progress', 'wp-security-audit-log' ); ?>
|
1167 |
-
</a>
|
1168 |
-
<a href="javascript:;" class="button button-ui-primary" id="wsal-stop-scan">
|
1169 |
-
<?php esc_attr_e( 'Stop Scan', 'wp-security-audit-log' ); ?>
|
1170 |
-
</a>
|
1171 |
-
<!-- Scan in progress -->
|
1172 |
-
<?php endif; ?>
|
1173 |
<br />
|
1174 |
<span class="description">
|
1175 |
-
<?php esc_html_e( '
|
1176 |
</span>
|
1177 |
-
</
|
1178 |
-
</
|
1179 |
-
|
1180 |
-
|
1181 |
-
|
1182 |
-
|
1183 |
-
|
1184 |
-
|
1185 |
-
|
1186 |
-
|
1187 |
-
|
1188 |
-
|
1189 |
-
|
1190 |
-
|
1191 |
-
|
1192 |
-
|
1193 |
-
|
1194 |
-
|
1195 |
-
|
1196 |
-
|
1197 |
-
|
1198 |
-
|
1199 |
-
|
1200 |
-
|
1201 |
-
|
1202 |
-
|
1203 |
-
|
1204 |
-
|
1205 |
-
|
1206 |
-
|
1207 |
-
|
1208 |
-
|
1209 |
-
|
1210 |
-
|
1211 |
-
|
1212 |
-
|
1213 |
-
|
1214 |
-
|
1215 |
-
|
1216 |
-
|
1217 |
-
<input
|
1218 |
-
|
1219 |
-
|
1220 |
-
<?php
|
1221 |
-
|
1222 |
-
|
1223 |
-
|
1224 |
-
|
1225 |
-
</span>
|
1226 |
-
<?php endforeach; ?>
|
1227 |
-
</div>
|
1228 |
-
</fieldset>
|
1229 |
-
</td>
|
1230 |
-
</tr>
|
1231 |
-
<tr>
|
1232 |
-
<td><h2 class="wsal-tab__heading"><?php esc_html_e( 'Custom Fields', 'wp-security-audit-log' ); ?></h2></td>
|
1233 |
-
</tr>
|
1234 |
-
<tr>
|
1235 |
-
<td colspan="2">
|
1236 |
-
<?php esc_html_e( 'All of the custom fields listed below will be excluded from monitoring. This means that if they are changed or updated the plugin will not log such activity.', 'wp-security-audit-log' ); ?><br>
|
1237 |
-
<?php esc_html_e( 'You can use the * wildcard to exclude more than one Custom Field. For example, to exclude all the Custom Fields that start with wp123 specify wp123*.', 'wp-security-audit-log' ); ?>
|
1238 |
-
</td>
|
1239 |
-
</tr>
|
1240 |
-
<!-- Excluded Custom Fields -->
|
1241 |
-
<tr>
|
1242 |
-
<th><label for="CustomQueryBox"><?php esc_html_e( 'Excluded Custom Fields', 'wp-security-audit-log' ); ?></label></th>
|
1243 |
-
<td>
|
1244 |
-
<fieldset>
|
1245 |
-
<input type="text" id="CustomQueryBox" style="float: left; display: block; width: 250px;">
|
1246 |
-
<input type="button" id="CustomQueryAdd" style="float: left; display: block;" class="button-primary" value="Add">
|
1247 |
-
<br style="clear: both;"/>
|
1248 |
-
<div id="CustomList">
|
1249 |
-
<?php foreach ( $this->_plugin->settings->GetExcludedMonitoringCustom() as $item ) : ?>
|
1250 |
-
<span class="sectoken-<?php echo esc_attr( $this->GetTokenType( $item ) ); ?>">
|
1251 |
-
<input type="hidden" name="Customs[]" value="<?php echo esc_attr( $item ); ?>"/>
|
1252 |
-
<?php echo esc_html( $item ); ?>
|
1253 |
-
<a href="javascript:;" title="Remove">×</a>
|
1254 |
-
</span>
|
1255 |
-
<?php endforeach; ?>
|
1256 |
-
</div>
|
1257 |
-
</fieldset>
|
1258 |
-
</td>
|
1259 |
-
</tr>
|
1260 |
-
<tr>
|
1261 |
-
<th><h2 class="wsal-tab__heading"><?php esc_html_e( 'IP Addresses', 'wp-security-audit-log' ); ?></h2></th>
|
1262 |
-
</tr>
|
1263 |
-
<tr>
|
1264 |
-
<td colspan="2"><?php esc_html_e( 'Any of the IP addresses listed below will be excluded from monitoring. This means that all activity from such IP address will not be recorded.', 'wp-security-audit-log' ); ?></td>
|
1265 |
-
</tr>
|
1266 |
-
<!-- Excluded IP Addresses -->
|
1267 |
-
<tr>
|
1268 |
-
<th><label for="IpAddrQueryBox"><?php esc_html_e( 'Excluded IP Addresses', 'wp-security-audit-log' ); ?></label></th>
|
1269 |
-
<td>
|
1270 |
-
<fieldset>
|
1271 |
-
<input type="text" id="IpAddrQueryBox" style="float: left; display: block; width: 250px;">
|
1272 |
-
<input type="button" id="IpAddrQueryAdd" style="float: left; display: block;" class="button-primary" value="Add">
|
1273 |
-
<br style="clear: both;"/>
|
1274 |
-
<div id="IpAddrList">
|
1275 |
-
<?php foreach ( $this->_plugin->settings->GetExcludedMonitoringIP() as $item ) : ?>
|
1276 |
-
<span class="sectoken-<?php echo esc_attr( $this->GetTokenType( $item ) ); ?>">
|
1277 |
-
<input type="hidden" name="IpAddrs[]" value="<?php echo esc_attr( $item ); ?>"/>
|
1278 |
-
<?php echo esc_html( $item ); ?>
|
1279 |
-
<a href="javascript:;" title="Remove">×</a>
|
1280 |
-
</span>
|
1281 |
-
<?php endforeach; ?>
|
1282 |
-
</div>
|
1283 |
-
</fieldset>
|
1284 |
-
</td>
|
1285 |
-
</tr>
|
1286 |
-
<tr>
|
1287 |
-
<th><h2 class="wsal-tab__heading"><?php esc_html_e( 'Post Types', 'wp-security-audit-log' ); ?></h2></th>
|
1288 |
-
</tr>
|
1289 |
-
<tr>
|
1290 |
-
<td colspan="2"><?php esc_html_e( 'The below list of Post Types are excluded from monitoring. This means that all activity related to these post types will not be recorded.', 'wp-security-audit-log' ); ?></td>
|
1291 |
-
</tr>
|
1292 |
-
<tr>
|
1293 |
-
<th><label for="ExCPTsQueryBox"><?php esc_html_e( 'Exclude Post Type from monitoring', 'wp-security-audit-log' ); ?></label></th>
|
1294 |
-
<td>
|
1295 |
-
<fieldset>
|
1296 |
-
<input type="text" id="ExCPTsQueryBox" style="float: left; display: block; width: 250px;">
|
1297 |
-
<input type="button" id="ExCPTsQueryAdd" style="float: left; display: block;" class="button-primary" value="Add">
|
1298 |
-
<br style="clear: both;"/>
|
1299 |
-
<div id="ExCPTsList">
|
1300 |
-
<?php foreach ( $this->_plugin->settings->get_excluded_post_types() as $item ) : ?>
|
1301 |
-
<span class="sectoken-<?php echo esc_attr( $this->GetTokenType( $item ) ); ?>">
|
1302 |
-
<input type="hidden" name="ExCPTss[]" value="<?php echo esc_attr( $item ); ?>"/>
|
1303 |
-
<?php echo esc_html( $item ); ?>
|
1304 |
-
<a href="javascript:;" title="Remove">×</a>
|
1305 |
-
</span>
|
1306 |
-
<?php endforeach; ?>
|
1307 |
-
</div>
|
1308 |
-
</fieldset>
|
1309 |
-
</td>
|
1310 |
-
</tr>
|
1311 |
-
<!-- Excluded Custom Post Types -->
|
1312 |
-
<tr>
|
1313 |
-
<th colspan="2">
|
1314 |
-
<h2 class="wsal-tab__heading"><?php esc_html_e( 'Non-Existing URLs (404)', 'wp-security-audit-log' ); ?></h2>
|
1315 |
-
</th>
|
1316 |
-
</tr>
|
1317 |
-
<tr>
|
1318 |
-
<td colspan="2">
|
1319 |
-
<?php esc_html_e( 'Add the non existing URLs for which you do not want to be alerted of HTTP 404 errors in the activity log by specifying the whole URL.', 'wp-security-audit-log' ); ?>
|
1320 |
-
<br />
|
1321 |
-
<br />
|
1322 |
-
<?php echo sprintf( esc_html__( 'Example for file: %s/subdirectory/file.php', 'wp-security-audit-log' ), esc_url( home_url() ) ); ?>
|
1323 |
<br />
|
1324 |
-
|
1325 |
-
|
1326 |
-
|
1327 |
-
|
1328 |
-
|
1329 |
-
|
1330 |
-
|
1331 |
-
|
1332 |
-
|
1333 |
-
|
1334 |
-
|
1335 |
-
|
1336 |
-
|
1337 |
-
|
1338 |
-
|
1339 |
-
|
1340 |
-
|
1341 |
-
|
1342 |
-
|
1343 |
-
|
1344 |
-
|
1345 |
-
|
1346 |
-
|
1347 |
-
|
1348 |
-
|
1349 |
-
|
1350 |
-
|
1351 |
-
|
1352 |
-
|
1353 |
-
|
1354 |
-
|
1355 |
-
|
1356 |
-
|
1357 |
-
|
1358 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1359 |
|
1360 |
-
|
1361 |
-
|
1362 |
-
|
1363 |
-
|
1364 |
-
|
1365 |
-
|
1366 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1367 |
}
|
1368 |
}
|
1369 |
|
1370 |
-
//
|
1371 |
-
|
1372 |
-
|
|
|
|
|
|
|
1373 |
|
1374 |
-
|
1375 |
-
|
1376 |
-
|
1377 |
-
|
1378 |
-
|
1379 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1380 |
<?php
|
1381 |
}
|
1382 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1383 |
/**
|
1384 |
* Method: Get View Header.
|
1385 |
*/
|
@@ -1390,10 +1827,17 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
|
|
1390 |
array(),
|
1391 |
filemtime( $this->_plugin->GetBaseDir() . '/css/settings.css' )
|
1392 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1393 |
?>
|
1394 |
<style type="text/css">
|
1395 |
.wsal-tab {
|
1396 |
-
display: none;
|
1397 |
}
|
1398 |
.wsal-tab tr.alert-incomplete td {
|
1399 |
color: #9BE;
|
@@ -1418,6 +1862,18 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
|
|
1418 |
false
|
1419 |
);
|
1420 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1421 |
// Register settings script.
|
1422 |
wp_register_script(
|
1423 |
'settings',
|
@@ -1428,34 +1884,30 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
|
|
1428 |
);
|
1429 |
// Passing nonce for security to JS file.
|
1430 |
$wsal_data = array(
|
1431 |
-
'wp_nonce'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1432 |
);
|
1433 |
wp_localize_script( 'settings', 'wsal_data', $wsal_data );
|
1434 |
wp_enqueue_script( 'settings' );
|
1435 |
?>
|
1436 |
<script type="text/javascript">
|
1437 |
-
jQuery(document).ready(function(){
|
1438 |
-
|
1439 |
-
jQuery('#wsal-tabs>a').click(function(){
|
1440 |
-
jQuery('#wsal-tabs>a').removeClass('nav-tab-active');
|
1441 |
-
jQuery('table.wsal-tab').hide();
|
1442 |
-
jQuery(jQuery(this).addClass('nav-tab-active').attr('href')).show();
|
1443 |
-
});
|
1444 |
-
// show relevant tab
|
1445 |
-
var hashlink = jQuery('#wsal-tabs>a[href="' + location.hash + '"]');
|
1446 |
-
if (hashlink.length) {
|
1447 |
-
hashlink.click();
|
1448 |
-
} else {
|
1449 |
-
jQuery('#wsal-tabs>a:first').click();
|
1450 |
-
}
|
1451 |
-
|
1452 |
-
jQuery(".sel-columns").change(function(){
|
1453 |
var notChecked = 1;
|
1454 |
-
jQuery(
|
1455 |
-
if(this.checked) notChecked = 0;
|
1456 |
})
|
1457 |
-
if(notChecked == 1){
|
1458 |
-
alert(
|
1459 |
}
|
1460 |
});
|
1461 |
});</script>
|
@@ -1859,4 +2311,56 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
|
|
1859 |
) );
|
1860 |
exit();
|
1861 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1862 |
}
|
36 |
*/
|
37 |
private $scan_settings = array();
|
38 |
|
39 |
+
/**
|
40 |
+
* WSAL Setting Tabs.
|
41 |
+
*
|
42 |
+
* @var array
|
43 |
+
* @since 3.2.3
|
44 |
+
*/
|
45 |
+
private $wsal_setting_tabs = array();
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Current Setting Tab.
|
49 |
+
*
|
50 |
+
* @var string
|
51 |
+
* @since 3.2.3
|
52 |
+
*/
|
53 |
+
private $current_tab = '';
|
54 |
+
|
55 |
/**
|
56 |
* Method: Constructor.
|
57 |
*
|
68 |
add_action( 'wp_ajax_wsal_scan_remove_exception', array( $this, 'scan_remove_exception_file' ) );
|
69 |
add_action( 'wp_ajax_wsal_manual_scan_now', array( $this, 'run_manual_scan_now' ) );
|
70 |
add_action( 'wp_ajax_wsal_stop_file_changes_scan', array( $this, 'stop_file_changes_scan' ) );
|
71 |
+
add_action( 'wp_ajax_wsal_reset_settings', array( $this, 'reset_settings' ) );
|
72 |
+
add_action( 'wp_ajax_wsal_purge_activity', array( $this, 'purge_activity' ) );
|
73 |
+
|
74 |
+
// Tab links.
|
75 |
+
$wsal_setting_tabs = array(
|
76 |
+
'general' => array(
|
77 |
+
'name' => __( 'General', 'wp-security-audit-log' ),
|
78 |
+
'link' => add_query_arg( 'tab', 'general' ),
|
79 |
+
'render' => array( $this, 'tab_general' ),
|
80 |
+
'save' => array( $this, 'tab_general_save' ),
|
81 |
+
),
|
82 |
+
'audit-log' => array(
|
83 |
+
'name' => __( 'Activity Log', 'wp-security-audit-log' ),
|
84 |
+
'link' => add_query_arg( 'tab', 'audit-log' ),
|
85 |
+
'render' => array( $this, 'tab_audit_log' ),
|
86 |
+
'save' => array( $this, 'tab_audit_log_save' ),
|
87 |
+
),
|
88 |
+
'file-changes' => array(
|
89 |
+
'name' => __( 'File Integrity Scan', 'wp-security-audit-log' ),
|
90 |
+
'link' => add_query_arg( 'tab', 'file-changes' ),
|
91 |
+
'render' => array( $this, 'tab_file_changes' ),
|
92 |
+
'save' => array( $this, 'tab_file_changes_save' ),
|
93 |
+
),
|
94 |
+
'exclude-objects' => array(
|
95 |
+
'name' => __( 'Exclude Objects', 'wp-security-audit-log' ),
|
96 |
+
'link' => add_query_arg( 'tab', 'exclude-objects' ),
|
97 |
+
'render' => array( $this, 'tab_exclude_objects' ),
|
98 |
+
'save' => array( $this, 'tab_exclude_objects_save' ),
|
99 |
+
),
|
100 |
+
'advanced-settings' => array(
|
101 |
+
'name' => __( 'Advanced Settings', 'wp-security-audit-log' ),
|
102 |
+
'link' => add_query_arg( 'tab', 'advanced-settings' ),
|
103 |
+
'render' => array( $this, 'tab_advanced_settings' ),
|
104 |
+
'save' => array( $this, 'tab_advanced_settings_save' ),
|
105 |
+
),
|
106 |
+
);
|
107 |
+
|
108 |
+
/**
|
109 |
+
* Filter: `wsal_setting_tabs`
|
110 |
+
*
|
111 |
+
* This filter is used to filter the tabs of WSAL settings page.
|
112 |
+
*
|
113 |
+
* Setting tabs structure:
|
114 |
+
* $wsal_setting_tabs['unique-tab-id'] = array(
|
115 |
+
* 'name' => Name of the tab,
|
116 |
+
* 'link' => Link of the tab,
|
117 |
+
* 'render' => This function is used to render HTML elements in the tab,
|
118 |
+
* 'name' => This function is used to save the related setting of the tab,
|
119 |
+
* );
|
120 |
+
*
|
121 |
+
* @param array $wsal_setting_tabs – Array of WSAL Setting Tabs.
|
122 |
+
* @since 3.2.3
|
123 |
+
*/
|
124 |
+
$this->wsal_setting_tabs = apply_filters( 'wsal_setting_tabs', $wsal_setting_tabs );
|
125 |
+
|
126 |
+
// Get the current tab.
|
127 |
+
$current_tab = filter_input( INPUT_GET, 'tab', FILTER_SANITIZE_STRING );
|
128 |
+
$this->current_tab = empty( $current_tab ) ? 'general' : $current_tab;
|
129 |
}
|
130 |
|
131 |
/**
|
169 |
* @param string $token - Token type.
|
170 |
*/
|
171 |
protected function GetTokenType( $token ) {
|
172 |
+
return $this->_plugin->settings->get_token_type( $token );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
173 |
}
|
174 |
|
175 |
/**
|
184 |
|
185 |
// Load saved settings of this view.
|
186 |
$this->scan_settings = array(
|
187 |
+
'scan_file_changes' => $this->_plugin->GetGlobalOption( 'scan-file-changes', 'enable' ),
|
188 |
+
'scan_frequency' => $this->_plugin->GetGlobalOption( 'scan-frequency', 'weekly' ),
|
189 |
+
'scan_hour' => $this->_plugin->GetGlobalOption( 'scan-hour', '04' ),
|
190 |
+
'scan_day' => $this->_plugin->GetGlobalOption( 'scan-day', '1' ),
|
191 |
+
'scan_date' => $this->_plugin->GetGlobalOption( 'scan-date', '10' ),
|
192 |
+
'scan_directories' => $this->_plugin->GetGlobalOption( 'scan-directories', $default_scan_dirs ),
|
193 |
+
'scan_excluded_dirs' => $this->_plugin->GetGlobalOption( 'scan-excluded-directories', array() ),
|
194 |
+
'scan_excluded_extensions' => $this->_plugin->GetGlobalOption( 'scan-excluded-extensions', array( 'jpg', 'jpeg', 'png', 'bmp', 'pdf', 'txt', 'log', 'mo', 'po', 'mp3', 'wav', 'gif', 'ico', 'jpe', 'psd', 'raw', 'svg', 'tif', 'tiff', 'aif', 'flac', 'm4a', 'oga', 'ogg', 'ra', 'wma', 'asf', 'avi', 'mkv', 'mov', 'mp4', 'mpe', 'mpeg', 'mpg', 'ogv', 'qt', 'rm', 'vob', 'webm', 'wm', 'wmv' ) ),
|
195 |
+
'scan_in_progress' => $this->_plugin->GetGlobalOption( 'scan-in-progress', false ),
|
196 |
);
|
197 |
}
|
198 |
|
199 |
/**
|
200 |
* Method: Save settings.
|
201 |
+
*
|
202 |
+
* @throws Exception - Unrecognized settings tab error.
|
203 |
*/
|
204 |
protected function Save() {
|
205 |
check_admin_referer( 'wsal-settings' );
|
206 |
|
207 |
+
// Call respective tab save functions if they are set.
|
208 |
+
if ( ! empty( $this->current_tab ) && ! empty( $this->wsal_setting_tabs[ $this->current_tab ]['save'] ) ) {
|
209 |
+
call_user_func( $this->wsal_setting_tabs[ $this->current_tab ]['save'] );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
210 |
} else {
|
211 |
+
throw new Exception( esc_html__( 'Unknown settings tab.', 'wp-security-audit-log' ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
212 |
}
|
213 |
}
|
214 |
|
217 |
*/
|
218 |
public function AjaxCheckSecurityToken() {
|
219 |
if ( ! $this->_plugin->settings->CurrentUserCan( 'view' ) ) {
|
220 |
+
echo wp_json_encode(
|
221 |
+
array(
|
222 |
+
'success' => false,
|
223 |
+
'message' => esc_html__( 'Access Denied.', 'wp-security-audit-log' ),
|
224 |
+
)
|
225 |
+
);
|
226 |
+
die();
|
227 |
}
|
228 |
|
229 |
+
//@codingStandardsIgnoreStart
|
230 |
+
$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : false;
|
231 |
+
$token = isset( $_POST['token'] ) ? sanitize_text_field( $_POST['token'] ) : false;
|
232 |
+
//@codingStandardsIgnoreEnd
|
233 |
|
234 |
+
if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'wsal-exclude-nonce' ) ) {
|
235 |
+
echo wp_json_encode(
|
236 |
+
array(
|
237 |
+
'success' => false,
|
238 |
+
'message' => esc_html__( 'Nonce verification failed.', 'wp-security-audit-log' ),
|
239 |
+
)
|
240 |
+
);
|
241 |
+
die();
|
242 |
+
}
|
243 |
+
|
244 |
+
if ( empty( $token ) ) {
|
245 |
+
echo wp_json_encode(
|
246 |
+
array(
|
247 |
+
'success' => false,
|
248 |
+
'message' => esc_html__( 'Invalid input.', 'wp-security-audit-log' ),
|
249 |
+
)
|
250 |
+
);
|
251 |
+
die();
|
252 |
}
|
253 |
+
|
254 |
+
echo wp_json_encode(
|
255 |
+
array(
|
256 |
+
'success' => true,
|
257 |
+
'token' => $token,
|
258 |
+
'tokenType' => esc_html( $this->GetTokenType( $token ) ),
|
259 |
+
)
|
260 |
+
);
|
261 |
+
die();
|
262 |
}
|
263 |
|
264 |
/**
|
269 |
die( 'Access Denied.' );
|
270 |
}
|
271 |
$this->_plugin->CleanUp();
|
272 |
+
|
273 |
+
if ( $this->_plugin->settings->IsArchivingEnabled() ) {
|
274 |
+
$redirect_url = add_query_arg( 'page', 'wsal-ext-settings', admin_url( 'admin.php' ) );
|
275 |
+
$redirect_url .= '#archiving';
|
276 |
+
wp_safe_redirect( $redirect_url );
|
277 |
+
} else {
|
278 |
+
wp_safe_redirect( $this->GetUrl() );
|
279 |
+
}
|
280 |
exit;
|
281 |
}
|
282 |
|
309 |
}
|
310 |
}
|
311 |
|
|
|
|
|
312 |
?>
|
313 |
+
<nav id="wsal-tabs" class="nav-tab-wrapper">
|
314 |
+
<?php foreach ( $this->wsal_setting_tabs as $tab_id => $tab ) : ?>
|
315 |
+
<?php if ( empty( $this->current_tab ) ) : ?>
|
316 |
+
<a href="<?php echo esc_url( $tab['link'] ); ?>" class="nav-tab <?php echo ( 'general' === $tab_id ) ? 'nav-tab-active' : false; ?>">
|
317 |
+
<?php echo esc_html( $tab['name'] ); ?>
|
318 |
+
</a>
|
319 |
+
<?php else : ?>
|
320 |
+
<a href="<?php echo esc_url( $tab['link'] ); ?>" class="nav-tab <?php echo ( $tab_id === $this->current_tab ) ? 'nav-tab-active' : false; ?>">
|
321 |
+
<?php echo esc_html( $tab['name'] ); ?>
|
322 |
+
</a>
|
323 |
+
<?php endif; ?>
|
324 |
+
<?php endforeach; ?>
|
325 |
+
</nav>
|
326 |
|
327 |
<form id="audit-log-settings" method="post">
|
328 |
<input type="hidden" name="page" value="<?php echo filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING ); ?>" />
|
332 |
<div id="audit-log-adverts">
|
333 |
</div>
|
334 |
<div class="nav-tabs">
|
335 |
+
<?php
|
336 |
+
if ( ! empty( $this->current_tab ) && ! empty( $this->wsal_setting_tabs[ $this->current_tab ]['render'] ) ) {
|
337 |
+
call_user_func( $this->wsal_setting_tabs[ $this->current_tab ]['render'] );
|
338 |
+
} else {
|
339 |
+
call_user_func( $this->wsal_setting_tabs['general']['render'] );
|
340 |
+
}
|
341 |
+
?>
|
342 |
+
</div>
|
343 |
+
<p class="submit"><input type="submit" name="submit" id="submit" class="button button-primary" value="Save Changes"></p>
|
344 |
+
</form>
|
345 |
+
<script type="text/javascript">
|
346 |
+
<!--
|
347 |
+
function delete_confirm(elementRef) {
|
348 |
+
if (elementRef.checked) {
|
349 |
+
if ( window.confirm('Do you want remove all data when the plugin is deleted?') == false )
|
350 |
+
elementRef.checked = false;
|
351 |
+
}
|
352 |
+
}
|
353 |
+
|
354 |
+
jQuery( document ).ready( function() {
|
355 |
+
// Enable/disable setting.
|
356 |
+
function wsal_update_setting( checkbox, setting ) {
|
357 |
+
if ( checkbox.prop( 'checked' ) ) {
|
358 |
+
setting.removeProp( 'disabled' );
|
359 |
+
} else {
|
360 |
+
setting.prop( 'disabled', 'disabled' );
|
361 |
+
}
|
362 |
+
}
|
363 |
+
|
364 |
+
// Login page notification settings.
|
365 |
+
var login_page_notif = jQuery( 'input[name=login_page_notification]' );
|
366 |
+
var login_page_notif_text = jQuery( '#login_page_notification_text' );
|
367 |
+
|
368 |
+
// Check the change event on checkbox.
|
369 |
+
login_page_notif.on( 'change', function() {
|
370 |
+
wsal_update_setting( login_page_notif, login_page_notif_text );
|
371 |
+
} );
|
372 |
+
|
373 |
+
// Proxy settings.
|
374 |
+
var proxy_ip_setting = jQuery( 'input[name=EnableProxyIpCapture]' );
|
375 |
+
var ip_filtering = jQuery( '#EnableIpFiltering' );
|
376 |
+
wsal_update_setting( proxy_ip_setting, ip_filtering );
|
377 |
+
proxy_ip_setting.on( 'change', function() {
|
378 |
+
wsal_update_setting( proxy_ip_setting, ip_filtering );
|
379 |
+
} );
|
380 |
+
} );
|
381 |
+
// --></script>
|
382 |
+
<?php
|
383 |
+
}
|
384 |
+
|
385 |
+
/**
|
386 |
+
* Tab: `General`
|
387 |
+
*/
|
388 |
+
private function tab_general() {
|
389 |
+
?>
|
390 |
+
<p class="description">
|
391 |
+
<?php echo wp_kses( __( 'Need help with setting up the plugin to meet your requirements? <a href="https://www.wpsecurityauditlog.com/contact/" target="_blank">Schedule a 20 minutes consultation and setup call</a> with our experts for just $50.', 'wp-security-audit-log' ), $this->_plugin->allowed_html_tags ); ?>
|
392 |
+
</p>
|
393 |
+
|
394 |
+
<h3><?php esc_html_e( 'Display latest events widget in dashboard', 'wp-security-audit-log' ); ?></h3>
|
395 |
+
<p class="description">
|
396 |
+
<?php
|
397 |
+
echo sprintf(
|
398 |
+
/* translators: Max number of dashboard widget alerts. */
|
399 |
+
esc_html__( 'The events widget displays the latest %d security events in the dashboard so you can get an overview of the latest events once you login.', 'wp-security-audit-log' ),
|
400 |
+
esc_html( $this->_plugin->settings->GetDashboardWidgetMaxAlerts() )
|
401 |
+
);
|
402 |
+
?>
|
403 |
+
</p>
|
404 |
+
<table class="form-table wsal-tab">
|
405 |
+
<tbody>
|
406 |
+
<tr>
|
407 |
+
<th><label for="dwoption_on"><?php esc_html_e( 'Dashboard Widget', 'wp-security-audit-log' ); ?></label></th>
|
408 |
+
<td>
|
409 |
+
<fieldset>
|
410 |
+
<?php $dwe = $this->_plugin->settings->IsWidgetsEnabled(); ?>
|
411 |
+
<label for="dwoption_on">
|
412 |
+
<input type="radio" name="EnableDashboardWidgets" id="dwoption_on" style="margin-top: 2px;" <?php checked( $dwe ); ?> value="1">
|
413 |
+
<span><?php esc_html_e( 'Yes', 'wp-security-audit-log' ); ?></span>
|
414 |
+
</label>
|
415 |
+
<br/>
|
416 |
+
<label for="dwoption_off">
|
417 |
+
<input type="radio" name="EnableDashboardWidgets" id="dwoption_off" style="margin-top: 2px;" <?php checked( $dwe, false ); ?> value="0">
|
418 |
+
<span><?php esc_html_e( 'No', 'wp-security-audit-log' ); ?></span>
|
419 |
+
</label>
|
420 |
+
</fieldset>
|
421 |
+
</td>
|
422 |
+
</tr>
|
423 |
+
<!-- / Events Dashboard Widget -->
|
424 |
+
</tbody>
|
425 |
+
</table>
|
426 |
+
<!-- Dashboard Widget -->
|
427 |
+
|
428 |
+
<h3><?php esc_html_e( 'Add user notification on the WordPress login page', 'wp-security-audit-log' ); ?></h3>
|
429 |
+
<p class="description">
|
430 |
+
<?php esc_html_e( 'Many compliance regulations (such as the GDRP) require website administrators to tell the users of their website that all the changes they do when logged in are being logged.', 'wp-security-audit-log' ); ?>
|
431 |
+
</p>
|
432 |
+
<table class="form-table wsal-tab">
|
433 |
+
<tbody>
|
434 |
+
<tr>
|
435 |
+
<th><label for="login_page_notification"><?php esc_html_e( 'Login Page Notification', 'wp-security-audit-log' ); ?></label></th>
|
436 |
+
<td>
|
437 |
+
<fieldset>
|
438 |
+
<?php
|
439 |
+
// Get login page notification checkbox.
|
440 |
+
$wsal_lpn = $this->_plugin->settings->is_login_page_notification();
|
441 |
+
if ( $wsal_lpn && 'true' === $wsal_lpn ) {
|
442 |
+
// If option exists, value is true then set to true.
|
443 |
+
$wsal_lpn = true;
|
444 |
+
} elseif ( $wsal_lpn && 'false' === $wsal_lpn ) {
|
445 |
+
// If option exists, value is false then set to false.
|
446 |
+
$wsal_lpn = false;
|
447 |
+
} elseif ( ! $wsal_lpn ) {
|
448 |
+
// Default option value.
|
449 |
+
$wsal_lpn = false;
|
450 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
451 |
?>
|
452 |
+
<label for="wsal_lpn_yes">
|
453 |
+
<input type="radio" name="login_page_notification" id="wsal_lpn_yes" <?php checked( $wsal_lpn ); ?> value="true" />
|
454 |
+
<?php esc_html_e( 'Yes', 'wp-security-audit-log' ); ?>
|
455 |
+
</label>
|
456 |
+
<br />
|
457 |
+
<?php
|
458 |
+
// Get login page notification text.
|
459 |
+
$wsal_lpn_text = $this->_plugin->settings->get_login_page_notification_text();
|
460 |
+
$wsal_lpn_text_default = __( 'For security and auditing purposes, a record of all of your logged-in actions and changes within the WordPress dashboard will be recorded in an audit log with the <a href="https://www.wpsecurityauditlog.com/" target="_blank">WP Security Audit Log plugin</a>. The audit log also includes the IP address where you accessed this site from.', 'wp-security-audit-log' );
|
461 |
+
|
462 |
+
// Allowed HTML tags for this setting.
|
463 |
+
$allowed_tags = array(
|
464 |
+
'a' => array(
|
465 |
+
'href' => array(),
|
466 |
+
'title' => array(),
|
467 |
+
'target' => array(),
|
468 |
+
),
|
469 |
+
);
|
470 |
+
?>
|
471 |
+
<textarea name="login_page_notification_text"
|
472 |
+
id="login_page_notification_text"
|
473 |
+
cols="60" rows="6"
|
474 |
+
<?php echo ( $wsal_lpn ) ? false : 'disabled'; ?>
|
475 |
+
><?php echo ( $wsal_lpn_text ) ? wp_kses( $wsal_lpn_text, $allowed_tags ) : wp_kses( $wsal_lpn_text_default, $allowed_tags ); ?></textarea>
|
476 |
+
<br/>
|
477 |
+
<p class="description">
|
478 |
+
<?php echo wp_kses( __( '<strong>Note: </strong>', 'wp-security-audit-log' ), $this->_plugin->allowed_html_tags ) . esc_html__( 'The only HTML code allowed in the login page notification is for links ( < a href >< /a > ).', 'wp-security-audit-log' ); ?>
|
479 |
+
</p>
|
480 |
+
<br />
|
481 |
+
|
482 |
+
<label for="wsal_lpn_no">
|
483 |
+
<input type="radio" name="login_page_notification" id="wsal_lpn_no" <?php checked( $wsal_lpn, false ); ?> value="false" />
|
484 |
+
<?php esc_html_e( 'No', 'wp-security-audit-log' ); ?>
|
485 |
+
</label>
|
486 |
+
</fieldset>
|
487 |
+
</td>
|
488 |
+
</tr>
|
489 |
+
<!-- / Login Page Notification -->
|
490 |
+
</tbody>
|
491 |
+
</table>
|
492 |
+
<!-- Login Page Notification -->
|
493 |
+
|
494 |
+
<h3><?php esc_html_e( 'Is your website running behind a firewall or reverse proxy?', 'wp-security-audit-log' ); ?></h3>
|
495 |
+
<p class="description">
|
496 |
+
<?php
|
497 |
+
echo sprintf(
|
498 |
+
/* translators: Learn more link. */
|
499 |
+
esc_html__( 'If your website is running behind a firewall set this option to yes so the plugin retrieves the end user’s IP address from the proxy header - %s.', 'wp-security-audit-log' ),
|
500 |
+
'<a href="https://www.wpsecurityauditlog.com/support-documentation/support-reverse-proxies-web-application-firewalls/" target="_blank">' . esc_html__( 'learn more', 'wp-security-audit-log' ) . '</a>'
|
501 |
+
);
|
502 |
+
?>
|
503 |
+
</p>
|
504 |
+
<table class="form-table wsal-tab">
|
505 |
+
<tbody>
|
506 |
+
<tr>
|
507 |
+
<th><label for="pioption_on"><?php esc_html_e( 'Reverse Proxy / Firewall Options', 'wp-security-audit-log' ); ?></label></th>
|
508 |
+
<td>
|
509 |
+
<fieldset>
|
510 |
+
<label for="enable_proxy_ip_capture_yes">
|
511 |
+
<input type="radio" name="EnableProxyIpCapture" value="1" id="enable_proxy_ip_capture_yes" <?php checked( $this->_plugin->settings->IsMainIPFromProxy() ); ?> />
|
512 |
+
<?php esc_html_e( 'Yes', 'wp-security-audit-log' ); ?>
|
513 |
+
</label>
|
514 |
+
<br/>
|
515 |
+
<label for="EnableIpFiltering">
|
516 |
+
<input type="checkbox" name="EnableIpFiltering" value="1" id="EnableIpFiltering" <?php checked( $this->_plugin->settings->IsInternalIPsFiltered() ); ?> />
|
517 |
+
<?php esc_html_e( 'Filter internal IP addresses from the proxy headers. Enable this option only if you are are still seeing the internal IP addresses of the firewall or proxy.', 'wp-security-audit-log' ); ?>
|
518 |
+
</label>
|
519 |
+
<br/>
|
520 |
+
<label for="enable_proxy_ip_capture_no">
|
521 |
+
<input type="radio" name="EnableProxyIpCapture" value="0" id="enable_proxy_ip_capture_no" <?php checked( $this->_plugin->settings->IsMainIPFromProxy(), false ); ?> />
|
522 |
+
<?php esc_html_e( 'No', 'wp-security-audit-log' ); ?>
|
523 |
+
</label>
|
524 |
+
<br />
|
525 |
+
</fieldset>
|
526 |
+
</td>
|
527 |
+
</tr>
|
528 |
+
<!-- / Reverse Proxy / Firewall Options -->
|
529 |
+
</tbody>
|
530 |
+
</table>
|
531 |
+
<!-- Reverse Proxy -->
|
532 |
+
|
533 |
+
<h3><?php esc_html_e( 'Who can change the plugin settings?', 'wp-security-audit-log' ); ?></h3>
|
534 |
+
<p class="description">
|
535 |
+
<?php esc_html_e( 'By default only users with administrator or super administrator (multisite) roles can change the settings of the plugin. Though you can change these privileges from this section.', 'wp-security-audit-log' ); ?>
|
536 |
+
</p>
|
537 |
+
<table class="form-table wsal-tab">
|
538 |
+
<tbody>
|
539 |
+
<tr>
|
540 |
+
<th><label for="RestrictAdmins"><?php esc_html_e( 'Restrict Plugin Access', 'wp-security-audit-log' ); ?></label></th>
|
541 |
+
<td>
|
542 |
+
<fieldset>
|
543 |
+
<?php $restrict_settings = $this->_plugin->settings->get_restrict_plugin_setting(); ?>
|
544 |
+
<label for="only_me">
|
545 |
+
<input type="radio" name="restrict-plugin-settings" id="only_me" value="only_me" <?php checked( $restrict_settings, 'only_me' ); ?> />
|
546 |
+
<?php esc_html_e( 'Only me', 'wp-security-audit-log' ); ?>
|
547 |
+
</label>
|
548 |
+
<br/>
|
549 |
+
<label for="only_admins">
|
550 |
+
<input type="radio" name="restrict-plugin-settings" id="only_admins" value="only_admins" <?php checked( $restrict_settings, 'only_admins' ); ?> />
|
551 |
+
<?php esc_html_e( 'Only administrators', 'wp-security-audit-log' ); ?>
|
552 |
+
</label>
|
553 |
+
<br/>
|
554 |
+
<label for="only_selected_users">
|
555 |
+
<input type="radio" name="restrict-plugin-settings" id="only_selected_users" value="only_selected_users" <?php checked( $restrict_settings, 'only_selected_users' ); ?> />
|
556 |
+
<?php esc_html_e( 'All these users or users with these roles', 'wp-security-audit-log' ); ?>
|
557 |
+
</label>
|
558 |
+
|
559 |
+
<p class="description">
|
560 |
+
<?php esc_html_e( 'Specify the username or the users which can change the plugin settings. You can also specify roles.', 'wp-security-audit-log' ); ?>
|
561 |
+
</p>
|
562 |
+
|
563 |
+
<label>
|
564 |
+
<input type="text" id="EditorQueryBox" style="width: 250px;">
|
565 |
+
<input type="button" id="EditorQueryAdd" style="" class="button-primary" value="Add">
|
566 |
+
</label>
|
567 |
+
|
568 |
+
<div id="EditorList">
|
569 |
+
<?php
|
570 |
+
foreach ( $this->_plugin->settings->GetAllowedPluginEditors() as $item ) :
|
571 |
+
if ( wp_get_current_user()->user_login === $item ) {
|
572 |
+
continue;
|
573 |
+
}
|
574 |
?>
|
575 |
+
<span class="sectoken-<?php echo esc_attr( $this->GetTokenType( $item ) ); ?>">
|
576 |
+
<input type="hidden" name="Editors[]" value="<?php echo esc_attr( $item ); ?>"/>
|
577 |
+
<?php echo esc_html( $item ); ?>
|
578 |
+
<?php if ( wp_get_current_user()->user_login !== $item ) : ?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
579 |
<a href="javascript:;" title="Remove">×</a>
|
580 |
+
<?php endif; ?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
581 |
</span>
|
582 |
+
<?php endforeach; ?>
|
583 |
+
</div>
|
584 |
+
</fieldset>
|
585 |
+
</td>
|
586 |
+
</tr>
|
587 |
+
<!-- / Restrict Plugin Access -->
|
588 |
+
</tbody>
|
589 |
+
</table>
|
590 |
+
<!-- Restrict Plugin Access -->
|
591 |
+
|
592 |
+
<h3><?php esc_html_e( 'Allow other users to view the activity log', 'wp-security-audit-log' ); ?></h3>
|
593 |
+
<p class="description">
|
594 |
+
<?php esc_html_e( 'By default only users with administrator and super administrator (multisite) role can view the WordPress activity log. Though you can allow other users with no admin role to view the events.', 'wp-security-audit-log' ); ?>
|
595 |
+
</p>
|
596 |
+
<table class="form-table wsal-tab">
|
597 |
+
<tbody>
|
598 |
+
<tr>
|
599 |
+
<th><label for="ViewerQueryBox"><?php esc_html_e( 'Can View Events', 'wp-security-audit-log' ); ?></label></th>
|
600 |
+
<td>
|
601 |
+
<fieldset>
|
602 |
+
<label>
|
603 |
+
<input type="text" id="ViewerQueryBox" style="width: 250px;">
|
604 |
+
<input type="button" id="ViewerQueryAdd" class="button-primary" value="Add">
|
605 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
606 |
<p class="description">
|
607 |
+
<?php esc_html_e( 'Specify the username or the users which do not have an admin role but can also see the WordPress activity role. You can also specify roles.', 'wp-security-audit-log' ); ?>
|
608 |
</p>
|
609 |
+
</label>
|
610 |
+
|
611 |
+
<div id="ViewerList">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
612 |
<?php
|
613 |
+
foreach ( $this->_plugin->settings->GetAllowedPluginViewers() as $item ) :
|
614 |
+
if ( wp_get_current_user()->user_login === $item ) {
|
615 |
+
continue;
|
616 |
+
}
|
617 |
+
?>
|
618 |
+
<span class="sectoken-<?php echo esc_attr( $this->GetTokenType( $item ) ); ?>">
|
619 |
+
<input type="hidden" name="Viewers[]" value="<?php echo esc_attr( $item ); ?>"/>
|
620 |
+
<?php echo esc_html( $item ); ?>
|
621 |
+
<a href="javascript:;" title="Remove">×</a>
|
622 |
+
</span>
|
623 |
+
<?php endforeach; ?>
|
624 |
+
</div>
|
625 |
+
</fieldset>
|
626 |
+
</td>
|
627 |
+
</tr>
|
628 |
+
<!-- / Can View Alerts -->
|
629 |
+
</tbody>
|
630 |
+
</table>
|
631 |
+
<!-- Can View Events -->
|
632 |
+
|
633 |
+
<h3><?php esc_html_e( 'Which email address should the plugin use as a from address?', 'wp-security-audit-log' ); ?></h3>
|
634 |
+
<p class="description">
|
635 |
+
<?php esc_html_e( 'By default when the plugin sends an email notification it uses the email address specified in this website’s general settings. Though you can change the email address and display name from this section.', 'wp-security-audit-log' ); ?>
|
636 |
+
</p>
|
637 |
+
<table class="form-table wsal-tab">
|
638 |
+
<tbody>
|
639 |
+
<tr>
|
640 |
+
<th><label for="FromEmail"><?php esc_html_e( 'From Email & Name', 'wp-security-audit-log' ); ?></label></th>
|
641 |
+
<td>
|
642 |
+
<fieldset>
|
643 |
+
<?php $use_email = $this->_plugin->GetGlobalOption( 'use-email', 'default_email' ); ?>
|
644 |
+
<label for="default_email">
|
645 |
+
<input type="radio" name="use-email" id="default_email" value="default_email" <?php checked( $use_email, 'default_email' ); ?> />
|
646 |
+
<?php esc_html_e( 'Use the email address from the WordPress general settings', 'wp-security-audit-log' ); ?>
|
647 |
+
</label>
|
648 |
+
<br>
|
649 |
+
<label for="custom_email">
|
650 |
+
<input type="radio" name="use-email" id="custom_email" value="custom_email" <?php checked( $use_email, 'custom_email' ); ?> />
|
651 |
+
<?php esc_html_e( 'Use another email address', 'wp-security-audit-log' ); ?>
|
652 |
+
</label>
|
653 |
+
<br>
|
654 |
+
<label for="FromEmail">
|
655 |
+
<?php esc_html_e( 'Email Address', 'wp-security-audit-log' ); ?>
|
656 |
+
<input type="email" id="FromEmail" name="FromEmail" value="<?php echo esc_attr( $this->_plugin->settings->GetFromEmail() ); ?>" />
|
657 |
+
</label>
|
658 |
+
<br>
|
659 |
+
<label for="DisplayName">
|
660 |
+
<?php esc_html_e( 'Display Name', 'wp-security-audit-log' ); ?>
|
661 |
+
<input type="text" id="DisplayName" name="DisplayName" value="<?php echo esc_attr( $this->_plugin->settings->GetDisplayName() ); ?>" />
|
662 |
+
</label>
|
663 |
+
</fieldset>
|
664 |
+
</td>
|
665 |
+
</tr>
|
666 |
+
<!-- / From Email & Name -->
|
667 |
+
</tbody>
|
668 |
+
</table>
|
669 |
+
<!-- From Email & Name -->
|
670 |
+
|
671 |
+
<h3><?php esc_html_e( 'Do you want to hide the plugin from the list of installed plugins?', 'wp-security-audit-log' ); ?></h3>
|
672 |
+
<p class="description">
|
673 |
+
<?php esc_html_e( 'By default all installed plugins are listed in the plugins page. If you do not want other administrators to see that you installed this plugin set this option to Yes so the WP Security Audit Log is not listed as an installed plugin on this website.', 'wp-security-audit-log' ); ?>
|
674 |
+
</p>
|
675 |
+
<table class="form-table wsal-tab">
|
676 |
+
<tbody>
|
677 |
+
<tr>
|
678 |
+
<th><label for="incognito_yes"><?php esc_html_e( 'Hide Plugin in Plugins Page', 'wp-security-audit-log' ); ?></label></th>
|
679 |
+
<td>
|
680 |
+
<fieldset>
|
681 |
+
<label for="incognito_yes">
|
682 |
+
<input type="radio" name="Incognito" value="1" id="incognito_yes" <?php checked( $this->_plugin->settings->IsIncognito() ); ?> />
|
683 |
+
<?php esc_html_e( 'Yes, hide the plugin from the list of installed plugins', 'wp-security-audit-log' ); ?>
|
684 |
+
</label>
|
685 |
+
<br/>
|
686 |
+
<label for="incognito_no">
|
687 |
+
<input type="radio" name="Incognito" value="0" id="incognito_no" <?php checked( $this->_plugin->settings->IsIncognito(), false ); ?> />
|
688 |
+
<?php esc_html_e( 'No, do not hide the plugin', 'wp-security-audit-log' ); ?>
|
689 |
+
</label>
|
690 |
+
</fieldset>
|
691 |
+
</td>
|
692 |
+
</tr>
|
693 |
+
<!-- / Hide Plugin in Plugins Page -->
|
694 |
+
</tbody>
|
695 |
+
</table>
|
696 |
+
<!-- Hide Plugin -->
|
697 |
+
<?php
|
698 |
+
}
|
699 |
|
700 |
+
/**
|
701 |
+
* Save: `General`
|
702 |
+
*/
|
703 |
+
private function tab_general_save() {
|
704 |
+
// Get $_POST global array.
|
705 |
+
$post_array = filter_input_array( INPUT_POST );
|
|
|
|
|
|
|
|
|
706 |
|
707 |
+
$this->_plugin->settings->set_use_email( sanitize_text_field( $post_array['use-email'] ) );
|
708 |
+
$this->_plugin->settings->SetFromEmail( sanitize_email( $post_array['FromEmail'] ) );
|
709 |
+
$this->_plugin->settings->SetDisplayName( sanitize_text_field( $post_array['DisplayName'] ) );
|
710 |
+
|
711 |
+
$this->_plugin->settings->SetWidgetsEnabled( sanitize_text_field( $post_array['EnableDashboardWidgets'] ) );
|
712 |
+
|
713 |
+
// Get plugin viewers.
|
714 |
+
$viewers = isset( $post_array['Viewers'] ) ? array_map( 'sanitize_text_field', $post_array['Viewers'] ) : array();
|
715 |
+
$this->_plugin->settings->SetAllowedPluginViewers( $viewers );
|
716 |
+
|
717 |
+
// Get plugin editors.
|
718 |
+
$editors = isset( $post_array['Editors'] ) ? array_map( 'sanitize_text_field', $post_array['Editors'] ) : array();
|
719 |
+
$restrict_settings = isset( $post_array['restrict-plugin-settings'] ) ? sanitize_text_field( $post_array['restrict-plugin-settings'] ) : false;
|
720 |
+
if ( ! empty( $restrict_settings ) && 'only_me' === $restrict_settings ) {
|
721 |
+
// Add current username to plugin editors.
|
722 |
+
$editors = array(); // Empty the array to remove previous editors in restrict mode.
|
723 |
+
$editors[] = wp_get_current_user()->user_login;
|
724 |
+
} elseif ( ! empty( $restrict_settings ) && 'only_selected_users' !== $restrict_settings ) {
|
725 |
+
// Empty the editors if option is not user or user roles.
|
726 |
+
$editors = array();
|
727 |
+
}
|
728 |
+
$this->_plugin->settings->SetAllowedPluginEditors( $editors );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
729 |
|
730 |
+
if ( ! empty( $restrict_settings ) && 'only_me' === $restrict_settings ) {
|
731 |
+
$this->_plugin->settings->SetRestrictAdmins( true );
|
732 |
+
} else {
|
733 |
+
$this->_plugin->settings->SetRestrictAdmins( false );
|
734 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
735 |
|
736 |
+
$this->_plugin->settings->set_restrict_plugin_setting( $restrict_settings );
|
737 |
+
$this->_plugin->settings->set_login_page_notification( isset( $post_array['login_page_notification'] ) ? sanitize_text_field( $post_array['login_page_notification'] ) : false );
|
738 |
+
$this->_plugin->settings->set_login_page_notification_text( isset( $post_array['login_page_notification_text'] ) ? $post_array['login_page_notification_text'] : false );
|
739 |
+
$this->_plugin->settings->SetMainIPFromProxy( isset( $post_array['EnableProxyIpCapture'] ) ? sanitize_text_field( $post_array['EnableProxyIpCapture'] ) : false );
|
740 |
+
$this->_plugin->settings->SetInternalIPsFiltering( isset( $post_array['EnableIpFiltering'] ) ? sanitize_text_field( $post_array['EnableIpFiltering'] ) : false );
|
741 |
+
$this->_plugin->settings->SetIncognito( isset( $post_array['Incognito'] ) ? sanitize_text_field( $post_array['Incognito'] ) : false );
|
742 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
743 |
|
744 |
+
/**
|
745 |
+
* Tab: `Audit Log`
|
746 |
+
*/
|
747 |
+
private function tab_audit_log() {
|
748 |
+
?>
|
749 |
+
<h3><?php esc_html_e( 'For how long do you want to keep the activity log events (Retention settings) ?', 'wp-security-audit-log' ); ?></h3>
|
750 |
+
<p class="description">
|
751 |
+
<?php
|
752 |
+
esc_html_e( 'The plugin uses an efficient way to store the activity log data in the WordPress database, though the more data you keep the more disk space will be required. ', 'wp-security-audit-log' );
|
753 |
+
$retention_help_text = __( '<a href="https://www.wpsecurityauditlog.com/pricing/" target="_blank">Upgrade to Premium</a> to store the activity log data in an external database.', 'wp-security-audit-log' );
|
754 |
+
|
755 |
+
echo wp_kses( $retention_help_text, $this->_plugin->allowed_html_tags );
|
756 |
+
?>
|
757 |
+
</p>
|
758 |
+
<?php if ( $this->_plugin->settings->IsArchivingEnabled() ) : ?>
|
759 |
+
<p class="description">
|
760 |
+
<?php
|
761 |
+
$archiving_page = add_query_arg( 'page', 'wsal-ext-settings', admin_url( 'admin.php' ) ) . '#archiving';
|
762 |
+
/* translators: 1: Archive page link tag. 2: Link closing tag. */
|
763 |
+
echo '<span class="dashicons dashicons-warning"></span> ' . sprintf( esc_html__( 'Retention settings moved to %1$s archiving settings %2$s because archiving is enabled', 'wp-security-audit-log' ), '<a href="' . esc_url( $archiving_page ) . '" target="_blank">', '</a>' );
|
764 |
+
?>
|
765 |
+
</p>
|
766 |
+
<?php else : ?>
|
767 |
+
<table class="form-table wsal-tab">
|
768 |
+
<tbody>
|
769 |
+
<tr>
|
770 |
+
<th><label for="delete1"><?php esc_html_e( 'Audit Log Retention', 'wp-security-audit-log' ); ?></label></th>
|
771 |
+
<td>
|
772 |
+
<fieldset>
|
773 |
+
<?php $nbld = ! $this->_plugin->settings->IsPruningDateEnabled(); ?>
|
774 |
+
<label for="delete0">
|
775 |
+
<input type="radio" id="delete0" name="PruneBy" value="" <?php checked( $nbld ); ?> />
|
776 |
+
<?php echo esc_html__( 'Keep all data', 'wp-security-audit-log' ); ?>
|
777 |
+
</label>
|
778 |
+
</fieldset>
|
779 |
+
|
780 |
+
<fieldset>
|
781 |
+
<?php
|
782 |
+
// Check pruning date option.
|
783 |
+
$nbld = $this->_plugin->settings->IsPruningDateEnabled();
|
784 |
+
|
785 |
+
// Find and replace ` months` in the string.
|
786 |
+
$pruning_date = $this->_plugin->settings->GetPruningDate();
|
787 |
+
$pruning_date = str_replace( ' months', '', $pruning_date );
|
788 |
+
$pruning_date = str_replace( ' years', '', $pruning_date );
|
789 |
+
$pruning_unit = $this->_plugin->settings->get_pruning_unit();
|
790 |
+
|
791 |
+
// Check if pruning limit was enabled for backwards compatibility.
|
792 |
+
if ( $this->_plugin->settings->IsPruningLimitEnabled() ) {
|
793 |
+
$nbld = true;
|
794 |
+
$pruning_date = '6';
|
795 |
+
$pruning_unit = 'months';
|
796 |
+
$this->_plugin->settings->SetPruningDate( $pruning_date . ' ' . $pruning_unit );
|
797 |
+
$this->_plugin->settings->SetPruningDateEnabled( true );
|
798 |
+
$this->_plugin->settings->SetPruningLimitEnabled( false );
|
799 |
}
|
800 |
?>
|
801 |
+
<label for="delete1">
|
802 |
+
<input type="radio" id="delete1" name="PruneBy" value="date" <?php checked( $nbld ); ?> />
|
803 |
+
<?php esc_html_e( 'Delete events older than', 'wp-security-audit-log' ); ?>
|
804 |
+
</label>
|
805 |
+
<input type="text" id="PruningDate" name="PruningDate"
|
806 |
+
value="<?php echo esc_attr( $pruning_date ); ?>"
|
807 |
+
onfocus="jQuery('#delete1').attr('checked', true);"
|
808 |
+
/>
|
809 |
+
<select name="pruning-unit" id="pruning-unit">
|
810 |
+
<option value="months" <?php echo ( 'months' === $pruning_unit ) ? 'selected' : false; ?>><?php esc_html_e( 'Months', 'wp-security-audit-log' ); ?></option>
|
811 |
+
<option value="years" <?php echo ( 'years' === $pruning_unit ) ? 'selected' : false; ?>><?php esc_html_e( 'Years', 'wp-security-audit-log' ); ?></option>
|
812 |
+
</select>
|
813 |
+
</fieldset>
|
814 |
+
|
815 |
+
<?php if ( $this->_plugin->settings->IsPruningDateEnabled() ) : ?>
|
816 |
+
<p class="description">
|
817 |
+
<?php
|
818 |
+
$next = wp_next_scheduled( 'wsal_cleanup' );
|
819 |
+
echo esc_html__( 'The next scheduled purging of activity log data that is older than ', 'wp-security-audit-log' );
|
820 |
+
echo esc_html( $pruning_date . ' ' . $pruning_unit );
|
821 |
+
echo sprintf(
|
822 |
+
' is in %s.',
|
823 |
+
esc_html( human_time_diff( current_time( 'timestamp' ), $next ) )
|
824 |
+
);
|
825 |
+
echo '<!-- ' . esc_html( date( 'dMy H:i:s', $next ) ) . ' --> ';
|
826 |
+
echo esc_html__( 'You can run the purging process now by clicking the button below.', 'wp-security-audit-log' );
|
827 |
+
?>
|
828 |
+
</p>
|
829 |
+
<p>
|
830 |
+
<a class="button-primary" href="<?php echo esc_url( add_query_arg( 'action', 'AjaxRunCleanup', admin_url( 'admin-ajax.php' ) ) ); ?>"><?php esc_html_e( 'Purge Old Data', 'wp-security-audit-log' ) ?></a>
|
831 |
+
</p>
|
832 |
+
<?php endif; ?>
|
833 |
+
</td>
|
834 |
+
</tr>
|
835 |
+
<!-- Audit Log Retention -->
|
836 |
+
</tbody>
|
837 |
+
</table>
|
838 |
+
<?php endif; ?>
|
839 |
+
<!-- Audit Log Retention -->
|
840 |
+
|
841 |
+
<h3><?php esc_html_e( 'What timestamp you would like to see in the WordPress activity log?', 'wp-security-audit-log' ); ?></h3>
|
842 |
+
<p class="description"><?php esc_html_e( 'Note that the WordPress\' timezone might be different from that configured on the server so when you switch from UTC to WordPress timezone or vice versa you might notice a big difference.', 'wp-security-audit-log' ); ?></p>
|
843 |
+
<table class="form-table wsal-tab">
|
844 |
+
<tbody>
|
845 |
+
<tr>
|
846 |
+
<th><label for="timezone-default"><?php esc_html_e( 'Events Timestamp', 'wp-security-audit-log' ); ?></label></th>
|
847 |
+
<td>
|
848 |
+
<fieldset>
|
849 |
+
<?php
|
850 |
+
$timezone = $this->_plugin->settings->GetTimezone();
|
851 |
+
|
852 |
+
/**
|
853 |
+
* Transform timezone values.
|
854 |
+
*
|
855 |
+
* @since 3.2.3
|
856 |
+
*/
|
857 |
+
if ( '0' === $timezone ) {
|
858 |
+
$timezone = 'utc';
|
859 |
+
} elseif ( '1' === $timezone ) {
|
860 |
+
$timezone = 'wp';
|
861 |
+
}
|
862 |
+
?>
|
863 |
+
<label for="timezone-default">
|
864 |
+
<input type="radio" name="Timezone" id="timezone-default" style="margin-top: -2px;"
|
865 |
+
<?php checked( $timezone, 'utc' ); ?> value="utc">
|
866 |
+
<?php esc_html_e( 'UTC', 'wp-security-audit-log' ); ?>
|
867 |
+
</label>
|
868 |
+
<br/>
|
869 |
+
<label for="timezone">
|
870 |
+
<input type="radio" name="Timezone" id="timezone" style="margin-top: -2px;"
|
871 |
+
<?php checked( $timezone, 'wp' ); ?> value="wp">
|
872 |
+
<?php esc_html_e( 'Timezone configured on this WordPress website', 'wp-security-audit-log' ); ?>
|
873 |
+
</label>
|
874 |
+
</fieldset>
|
875 |
+
</td>
|
876 |
+
</tr>
|
877 |
+
<!-- Alerts Timestamp -->
|
878 |
+
</tbody>
|
879 |
+
</table>
|
880 |
+
<!-- Timestamp -->
|
881 |
+
|
882 |
+
<h3><?php esc_html_e( 'What user information should be displayed in the WordPress activity log?', 'wp-security-audit-log' ); ?></h3>
|
883 |
+
<p class="description"><?php esc_html_e( 'Usernames might not be the same as a user\'s first and last name so it can be difficult to recognize whose user was that did a change. When there is no first & last name or public display name configured the plugin will revert back to the WordPress username.', 'wp-security-audit-log' ); ?></p>
|
884 |
+
<table class="form-table wsal-tab">
|
885 |
+
<tbody>
|
886 |
+
<tr>
|
887 |
+
<th><label for="timezone-default"><?php esc_html_e( 'User Information in Audit Log', 'wp-security-audit-log' ); ?></label></th>
|
888 |
+
<td>
|
889 |
+
<fieldset>
|
890 |
+
<?php $type_username = $this->_plugin->settings->get_type_username(); ?>
|
891 |
+
<label for="column_username">
|
892 |
+
<input type="radio" name="type_username" id="column_username" style="margin-top: -2px;" <?php checked( $type_username, 'username' ); ?> value="username">
|
893 |
+
<span><?php esc_html_e( 'WordPress Username', 'wp-security-audit-log' ); ?></span>
|
894 |
+
</label>
|
895 |
+
<br/>
|
896 |
+
<label for="columns_first_last_name">
|
897 |
+
<input type="radio" name="type_username" id="columns_first_last_name" style="margin-top: -2px;" <?php checked( $type_username, 'first_last_name' ); ?> value="first_last_name">
|
898 |
+
<span><?php esc_html_e( 'First Name & Last Name', 'wp-security-audit-log' ); ?></span>
|
899 |
+
</label>
|
900 |
+
<br/>
|
901 |
+
<label for="columns_display_name">
|
902 |
+
<input type="radio" name="type_username" id="columns_display_name" style="margin-top: -2px;" <?php checked( $type_username, 'display_name' ); ?> value="display_name">
|
903 |
+
<span><?php esc_html_e( 'Configured Public Display Name', 'wp-security-audit-log' ); ?></span>
|
904 |
+
</label>
|
905 |
+
</fieldset>
|
906 |
+
</td>
|
907 |
+
</tr>
|
908 |
+
<!-- Select type of name -->
|
909 |
+
</tbody>
|
910 |
+
</table>
|
911 |
+
<!-- User Information -->
|
912 |
+
|
913 |
+
<h3><?php esc_html_e( 'Select the columns to be displayed in the WordPress activity log', 'wp-security-audit-log' ); ?></h3>
|
914 |
+
<p class="description"><?php esc_html_e( 'When you deselect a column it won’t be shown in the activity log viewer but the data will still be recorded by the plugin, so when you select it again all the data will be displayed.', 'wp-security-audit-log' ); ?></p>
|
915 |
+
<table class="form-table wsal-tab">
|
916 |
+
<tbody>
|
917 |
+
<tr>
|
918 |
+
<th><label for="columns"><?php esc_html_e( 'Audit Log Columns Selection', 'wp-security-audit-log' ); ?></label></th>
|
919 |
+
<td>
|
920 |
+
<fieldset>
|
921 |
+
<?php $columns = $this->_plugin->settings->GetColumns(); ?>
|
922 |
+
<?php foreach ( $columns as $key => $value ) { ?>
|
923 |
+
<label for="columns">
|
924 |
+
<input type="checkbox" name="Columns[<?php echo esc_attr( $key ); ?>]" id="<?php echo esc_attr( $key ); ?>" class="sel-columns" style="margin-top: -2px;"
|
925 |
+
<?php checked( $value, '1' ); ?> value="1">
|
926 |
+
<?php if ( 'alert_code' === $key ) : ?>
|
927 |
+
<span><?php esc_html_e( 'Event ID', 'wp-security-audit-log' ); ?></span>
|
928 |
+
<?php elseif ( 'type' === $key ) : ?>
|
929 |
+
<span><?php esc_html_e( 'Severity', 'wp-security-audit-log' ); ?></span>
|
930 |
+
<?php elseif ( 'date' === $key ) : ?>
|
931 |
+
<span><?php esc_html_e( 'Date & Time', 'wp-security-audit-log' ); ?></span>
|
932 |
+
<?php elseif ( 'username' === $key ) : ?>
|
933 |
+
<span><?php esc_html_e( 'User', 'wp-security-audit-log' ); ?></span>
|
934 |
+
<?php elseif ( 'source_ip' === $key ) : ?>
|
935 |
+
<span><?php esc_html_e( 'Source IP Address', 'wp-security-audit-log' ); ?></span>
|
936 |
+
<?php else : ?>
|
937 |
+
<span><?php echo esc_html( ucwords( str_replace( '_', ' ', $key ) ) ); ?></span>
|
938 |
+
<?php endif; ?>
|
939 |
+
</label>
|
940 |
+
<br/>
|
941 |
+
<?php } ?>
|
942 |
+
</fieldset>
|
943 |
+
</td>
|
944 |
+
</tr>
|
945 |
+
<!-- Audit Log Columns Selection -->
|
946 |
+
</tbody>
|
947 |
+
</table>
|
948 |
+
<!-- Audit Log Columns -->
|
949 |
+
|
950 |
+
<h3><?php esc_html_e( 'Do you want the activity log viewer to auto refresh?', 'wp-security-audit-log' ); ?></h3>
|
951 |
+
<p class="description"><?php esc_html_e( 'The activity log viewer auto refreshes every 30 seconds when opened so you can see the latest events as they happen almost in real time.', 'wp-security-audit-log' ); ?></p>
|
952 |
+
<table class="form-table wsal-tab">
|
953 |
+
<tbody>
|
954 |
+
<tr>
|
955 |
+
<th><label for="aroption_on"><?php esc_html_e( 'Refresh Audit Log Viewer', 'wp-security-audit-log' ); ?></label></th>
|
956 |
+
<td>
|
957 |
+
<fieldset>
|
958 |
+
<?php $are = $this->_plugin->settings->IsRefreshAlertsEnabled(); ?>
|
959 |
+
<label for="aroption_on">
|
960 |
+
<input type="radio" name="EnableAuditViewRefresh" id="aroption_on" style="margin-top: -2px;"
|
961 |
+
<?php checked( $are ); ?> value="1">
|
962 |
+
<span><?php esc_html_e( 'Auto refresh', 'wp-security-audit-log' ); ?></span>
|
963 |
+
</label>
|
964 |
+
<br/>
|
965 |
+
<label for="aroption_off">
|
966 |
+
<input type="radio" name="EnableAuditViewRefresh" id="aroption_off" style="margin-top: -2px;"
|
967 |
+
<?php checked( $are, false ); ?> value="0">
|
968 |
+
<span><?php esc_html_e( 'Do not auto refresh', 'wp-security-audit-log' ); ?></span>
|
969 |
+
</label>
|
970 |
+
</fieldset>
|
971 |
+
</td>
|
972 |
+
</tr>
|
973 |
+
<!-- Refresh Audit Log Viewer -->
|
974 |
+
</tbody>
|
975 |
+
</table>
|
976 |
+
<!-- Refresh Audit Log -->
|
977 |
+
|
978 |
+
<h3><?php esc_html_e( 'Do you want to keep a log of WordPress background activity?', 'wp-security-audit-log' ); ?></h3>
|
979 |
+
<p class="description">
|
980 |
+
<?php esc_html_e( 'WordPress does a lot of things in the background that you do not necessarily need to know about, such as; deletion of post revisions, deletion of auto saved drafts etc. By default the plugin does not report them since there might be a lot and are irrelevant to the user.', 'wp-security-audit-log' ); ?>
|
981 |
+
</p>
|
982 |
+
<table class="form-table wsal-tab">
|
983 |
+
<tbody>
|
984 |
+
<tr>
|
985 |
+
<th><label for="wp_backend_no"><?php esc_html_e( 'Disable Events for WordPress Background Activity', 'wp-security-audit-log' ); ?></label></th>
|
986 |
+
<td>
|
987 |
+
<fieldset>
|
988 |
+
<label for="wp_backend_yes">
|
989 |
+
<input type="radio" name="WPBackend" value="1" id="wp_backend_yes"
|
990 |
+
<?php checked( $this->_plugin->settings->IsWPBackend() ); ?> />
|
991 |
+
<?php esc_html_e( 'Yes', 'wp-security-audit-log' ); ?>
|
992 |
+
</label>
|
993 |
+
<br/>
|
994 |
+
<label for="wp_backend_no">
|
995 |
+
<input type="radio" name="WPBackend" value="0" id="wp_backend_no"
|
996 |
+
<?php checked( $this->_plugin->settings->IsWPBackend(), false ); ?> />
|
997 |
+
<?php esc_html_e( 'No', 'wp-security-audit-log' ); ?>
|
998 |
+
</label>
|
999 |
+
</fieldset>
|
1000 |
+
</td>
|
1001 |
+
</tr>
|
1002 |
+
<!-- Disable Alerts for WordPress Background activity -->
|
1003 |
+
</tbody>
|
1004 |
+
</table>
|
1005 |
+
<!-- Background Events -->
|
1006 |
+
<?php
|
1007 |
+
}
|
1008 |
+
|
1009 |
+
/**
|
1010 |
+
* Save: `Audit Log`
|
1011 |
+
*/
|
1012 |
+
private function tab_audit_log_save() {
|
1013 |
+
// Get $_POST global array.
|
1014 |
+
$post_array = filter_input_array( INPUT_POST );
|
1015 |
+
|
1016 |
+
// Get pruning date.
|
1017 |
+
$pruning_date = isset( $post_array['PruningDate'] ) ? (int) sanitize_text_field( $post_array['PruningDate'] ) : false;
|
1018 |
+
$pruning_unit = isset( $post_array['pruning-unit'] ) ? sanitize_text_field( $post_array['pruning-unit'] ) : false;
|
1019 |
+
$pruning_date = ( ! empty( $pruning_date ) && ! empty( $pruning_unit ) ) ? $pruning_date . ' ' . $pruning_unit : false;
|
1020 |
+
|
1021 |
+
$this->_plugin->settings->SetPruningDateEnabled( isset( $post_array['PruneBy'] ) ? 'date' === $post_array['PruneBy'] : '' );
|
1022 |
+
$this->_plugin->settings->SetPruningDate( $pruning_date );
|
1023 |
+
$this->_plugin->settings->set_pruning_unit( $pruning_unit );
|
1024 |
+
$this->_plugin->settings->SetRefreshAlertsEnabled( $post_array['EnableAuditViewRefresh'] );
|
1025 |
+
$this->_plugin->settings->SetTimezone( $post_array['Timezone'] );
|
1026 |
+
$this->_plugin->settings->set_type_username( $post_array['type_username'] );
|
1027 |
+
$this->_plugin->settings->SetWPBackend( isset( $post_array['WPBackend'] ) ? sanitize_text_field( $post_array['WPBackend'] ) : false );
|
1028 |
+
if ( ! empty( $post_array['Columns'] ) ) {
|
1029 |
+
$this->_plugin->settings->SetColumns( $post_array['Columns'] );
|
1030 |
+
}
|
1031 |
+
}
|
1032 |
+
|
1033 |
+
/**
|
1034 |
+
* Tab: `File Changes`
|
1035 |
+
*/
|
1036 |
+
private function tab_file_changes() {
|
1037 |
+
// Load file changes settings.
|
1038 |
+
$this->load_file_changes_settings();
|
1039 |
+
?>
|
1040 |
+
<p class="description">
|
1041 |
+
<?php esc_html_e( 'The plugin runs file integrity scans on your website so it keeps a log when a file is added, modified or deleted. All the settings for the file integrity scans can be found in this page.', 'wp-security-audit-log' ); ?>
|
1042 |
+
<?php echo wp_kses( __( '<a href="https://www.wpsecurityauditlog.com/support-documentation/wordpress-files-changes-warning-activity-logs/" target="_blank">Refer to the WordPress file integrity scans feature page</a> for more information.', 'wp-security-audit-log' ), $this->_plugin->allowed_html_tags ); ?>
|
1043 |
+
</p>
|
1044 |
+
|
1045 |
+
<h3><?php esc_html_e( 'Do you want the plugin to scan your website for file changes?', 'wp-security-audit-log' ); ?></h3>
|
1046 |
+
<table class="form-table wsal-tab">
|
1047 |
+
<tbody>
|
1048 |
+
<tr>
|
1049 |
+
<th>
|
1050 |
+
<label for="wsal-file-changes"><?php esc_html_e( 'Keep a Log of File Changes', 'wp-security-audit-log' ); ?></label>
|
1051 |
+
</th>
|
1052 |
+
<td>
|
1053 |
+
<fieldset>
|
1054 |
+
<label>
|
1055 |
+
<input id="enable" name="wsal-file-changes" type="radio" value="enable"
|
1056 |
+
<?php checked( $this->scan_settings['scan_file_changes'], 'enable' ); ?>
|
1057 |
+
/>
|
1058 |
+
<?php esc_html_e( 'Yes', 'wp-security-audit-log' ); ?>
|
1059 |
+
</label>
|
1060 |
+
<br />
|
1061 |
+
<label>
|
1062 |
+
<input id="disable" name="wsal-file-changes" type="radio" value="disable"
|
1063 |
+
<?php checked( $this->scan_settings['scan_file_changes'], 'disable' ); ?>
|
1064 |
+
/>
|
1065 |
+
<?php esc_html_e( 'No', 'wp-security-audit-log' ); ?>
|
1066 |
+
</label>
|
1067 |
+
</fieldset>
|
1068 |
+
</td>
|
1069 |
+
</tr>
|
1070 |
+
</tbody>
|
1071 |
+
</table>
|
1072 |
+
<!-- wsal-file-changes -->
|
1073 |
+
|
1074 |
+
<h3><?php esc_html_e( 'Which file changes events do you want to keep a log of in the activity log?', 'wp-security-audit-log' ); ?></h3>
|
1075 |
+
<p class="description">
|
1076 |
+
<?php esc_html_e( 'By default the plugin will keep a log whenever a file has been added, modified or deleted. It will also log an event in the activity log when a file is too big to scan or there are too many files to scan. Click on the link to specify which of these events the plugin should keep a log of.', 'wp-security-audit-log' ); ?>
|
1077 |
+
</p>
|
1078 |
+
<table class="form-table wsal-tab">
|
1079 |
+
<tbody>
|
1080 |
+
<tr>
|
1081 |
+
<th>
|
1082 |
+
<label for="wsal-file-alert-types"><?php esc_html_e( 'Alert me when', 'wp-security-audit-log' ); ?></label>
|
1083 |
+
</th>
|
1084 |
+
<td>
|
1085 |
+
<p>
|
1086 |
+
<?php
|
1087 |
+
$wsal_events_page = '';
|
1088 |
+
if ( ! is_multisite() ) {
|
1089 |
+
$wsal_events_page = add_query_arg( 'page', 'wsal-togglealerts', admin_url( 'admin.php' ) );
|
1090 |
+
} else {
|
1091 |
+
$wsal_events_page = add_query_arg( 'page', 'wsal-togglealerts', network_admin_url( 'admin.php' ) );
|
1092 |
+
}
|
1093 |
+
?>
|
1094 |
+
<a href="<?php echo esc_url( $wsal_events_page . '#tab-file-changes' ); ?>">
|
1095 |
+
<?php esc_html_e( 'Configure Events', 'wp-security-audit-log' ); ?>
|
1096 |
+
</a>
|
1097 |
+
</p>
|
1098 |
+
</td>
|
1099 |
+
</tr>
|
1100 |
+
</tbody>
|
1101 |
+
</table>
|
1102 |
+
<!-- wsal-file-alert-types -->
|
1103 |
+
|
1104 |
+
<h3><?php esc_html_e( 'When should the plugin scan your website for file changes?', 'wp-security-audit-log' ); ?></h3>
|
1105 |
+
<p class="description">
|
1106 |
+
<?php esc_html_e( 'By default the plugin will run file integrity scans once a week. If you can, ideally you should run file integrity scans on a daily basis. The file integrity scanner is very efficient and requires very little resources. Though if you have a fairly large website we recommend you to scan it when it is the least busy. The scan process should only take a few seconds to complete.', 'wp-security-audit-log' ); ?>
|
1107 |
+
</p>
|
1108 |
+
<table class="form-table wsal-tab">
|
1109 |
+
<tbody>
|
1110 |
+
<tr>
|
1111 |
+
<th>
|
1112 |
+
<label for="wsal-scan-frequency"><?php esc_html_e( 'Scan Frequency', 'wp-security-audit-log' ); ?></label>
|
1113 |
+
</th>
|
1114 |
+
<td>
|
1115 |
+
<?php
|
1116 |
+
$frequency_options = array(
|
1117 |
+
'daily' => __( 'Daily', 'wp-security-audit-log' ),
|
1118 |
+
'weekly' => __( 'Weekly', 'wp-security-audit-log' ),
|
1119 |
+
'monthly' => __( 'Monthly', 'wp-security-audit-log' ),
|
1120 |
+
);
|
1121 |
+
?>
|
1122 |
+
<fieldset id="wsal-scan-frequency">
|
1123 |
+
<select name="wsal-scan-frequency">
|
1124 |
+
<?php foreach ( $frequency_options as $value => $html ) : ?>
|
1125 |
+
<option
|
1126 |
+
value="<?php echo esc_attr( $value ); ?>"
|
1127 |
+
<?php echo esc_attr( $value === $this->scan_settings['scan_frequency'] ? 'selected' : false ); ?>>
|
1128 |
+
<?php echo esc_html( $html ); ?>
|
1129 |
+
</option>
|
1130 |
+
<?php endforeach; ?>
|
1131 |
+
</select>
|
1132 |
+
</fieldset>
|
1133 |
+
</td>
|
1134 |
+
</tr>
|
1135 |
+
<tr id="wsal-scan-time">
|
1136 |
+
<th>
|
1137 |
+
<label for="wsal-scan-hour"><?php esc_html_e( 'Scan Time', 'wp-security-audit-log' ); ?></label>
|
1138 |
+
</th>
|
1139 |
+
<td>
|
1140 |
+
<?php
|
1141 |
+
// Scan hours option.
|
1142 |
+
$scan_hours = array(
|
1143 |
+
'00' => __( '00:00', 'wp-security-audit-log' ),
|
1144 |
+
'01' => __( '01:00', 'wp-security-audit-log' ),
|
1145 |
+
'02' => __( '02:00', 'wp-security-audit-log' ),
|
1146 |
+
'03' => __( '03:00', 'wp-security-audit-log' ),
|
1147 |
+
'04' => __( '04:00', 'wp-security-audit-log' ),
|
1148 |
+
'05' => __( '05:00', 'wp-security-audit-log' ),
|
1149 |
+
'06' => __( '06:00', 'wp-security-audit-log' ),
|
1150 |
+
'07' => __( '07:00', 'wp-security-audit-log' ),
|
1151 |
+
'08' => __( '08:00', 'wp-security-audit-log' ),
|
1152 |
+
'09' => __( '09:00', 'wp-security-audit-log' ),
|
1153 |
+
'10' => __( '10:00', 'wp-security-audit-log' ),
|
1154 |
+
'11' => __( '11:00', 'wp-security-audit-log' ),
|
1155 |
+
'12' => __( '12:00', 'wp-security-audit-log' ),
|
1156 |
+
'13' => __( '13:00', 'wp-security-audit-log' ),
|
1157 |
+
'14' => __( '14:00', 'wp-security-audit-log' ),
|
1158 |
+
'15' => __( '15:00', 'wp-security-audit-log' ),
|
1159 |
+
'16' => __( '16:00', 'wp-security-audit-log' ),
|
1160 |
+
'17' => __( '17:00', 'wp-security-audit-log' ),
|
1161 |
+
'18' => __( '18:00', 'wp-security-audit-log' ),
|
1162 |
+
'19' => __( '19:00', 'wp-security-audit-log' ),
|
1163 |
+
'20' => __( '20:00', 'wp-security-audit-log' ),
|
1164 |
+
'21' => __( '21:00', 'wp-security-audit-log' ),
|
1165 |
+
'22' => __( '22:00', 'wp-security-audit-log' ),
|
1166 |
+
'23' => __( '23:00', 'wp-security-audit-log' ),
|
1167 |
+
);
|
1168 |
+
|
1169 |
+
// Scan days option.
|
1170 |
+
$scan_days = array(
|
1171 |
+
'1' => __( 'Monday', 'wp-security-audit-log' ),
|
1172 |
+
'2' => __( 'Tuesday', 'wp-security-audit-log' ),
|
1173 |
+
'3' => __( 'Wednesday', 'wp-security-audit-log' ),
|
1174 |
+
'4' => __( 'Thursday', 'wp-security-audit-log' ),
|
1175 |
+
'5' => __( 'Friday', 'wp-security-audit-log' ),
|
1176 |
+
'6' => __( 'Saturday', 'wp-security-audit-log' ),
|
1177 |
+
'7' => __( 'Sunday', 'wp-security-audit-log' ),
|
1178 |
+
);
|
1179 |
+
|
1180 |
+
// Scan date option.
|
1181 |
+
$scan_date = array(
|
1182 |
+
'01' => __( '01', 'wp-security-audit-log' ),
|
1183 |
+
'02' => __( '02', 'wp-security-audit-log' ),
|
1184 |
+
'03' => __( '03', 'wp-security-audit-log' ),
|
1185 |
+
'04' => __( '04', 'wp-security-audit-log' ),
|
1186 |
+
'05' => __( '05', 'wp-security-audit-log' ),
|
1187 |
+
'06' => __( '06', 'wp-security-audit-log' ),
|
1188 |
+
'07' => __( '07', 'wp-security-audit-log' ),
|
1189 |
+
'08' => __( '08', 'wp-security-audit-log' ),
|
1190 |
+
'09' => __( '09', 'wp-security-audit-log' ),
|
1191 |
+
'10' => __( '10', 'wp-security-audit-log' ),
|
1192 |
+
'11' => __( '11', 'wp-security-audit-log' ),
|
1193 |
+
'12' => __( '12', 'wp-security-audit-log' ),
|
1194 |
+
'13' => __( '13', 'wp-security-audit-log' ),
|
1195 |
+
'14' => __( '14', 'wp-security-audit-log' ),
|
1196 |
+
'15' => __( '15', 'wp-security-audit-log' ),
|
1197 |
+
'16' => __( '16', 'wp-security-audit-log' ),
|
1198 |
+
'17' => __( '17', 'wp-security-audit-log' ),
|
1199 |
+
'18' => __( '18', 'wp-security-audit-log' ),
|
1200 |
+
'19' => __( '19', 'wp-security-audit-log' ),
|
1201 |
+
'20' => __( '20', 'wp-security-audit-log' ),
|
1202 |
+
'21' => __( '21', 'wp-security-audit-log' ),
|
1203 |
+
'22' => __( '22', 'wp-security-audit-log' ),
|
1204 |
+
'23' => __( '23', 'wp-security-audit-log' ),
|
1205 |
+
'24' => __( '24', 'wp-security-audit-log' ),
|
1206 |
+
'25' => __( '25', 'wp-security-audit-log' ),
|
1207 |
+
'26' => __( '26', 'wp-security-audit-log' ),
|
1208 |
+
'27' => __( '27', 'wp-security-audit-log' ),
|
1209 |
+
'28' => __( '28', 'wp-security-audit-log' ),
|
1210 |
+
'29' => __( '29', 'wp-security-audit-log' ),
|
1211 |
+
'30' => __( '30', 'wp-security-audit-log' ),
|
1212 |
+
);
|
1213 |
+
?>
|
1214 |
+
<fieldset>
|
1215 |
+
<span class="wsal-scan-time-container" id="wsal-scan-hour">
|
1216 |
+
<select name="wsal-scan-hour">
|
1217 |
+
<?php foreach ( $scan_hours as $value => $html ) : ?>
|
1218 |
+
<option
|
1219 |
+
value="<?php echo esc_attr( $value ); ?>"
|
1220 |
+
<?php echo esc_attr( $value == $this->scan_settings['scan_hour'] ? 'selected' : false ); ?>>
|
1221 |
<?php echo esc_html( $html ); ?>
|
1222 |
+
</option>
|
|
|
1223 |
<?php endforeach; ?>
|
1224 |
+
</select>
|
1225 |
+
<br />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1226 |
<span class="description">
|
1227 |
+
<?php esc_html_e( 'Hour', 'wp-security-audit-log' ); ?>
|
1228 |
</span>
|
1229 |
+
</span>
|
1230 |
+
|
1231 |
+
<span class="wsal-scan-time-container hide" id="wsal-scan-day">
|
1232 |
+
<select name="wsal-scan-day">
|
1233 |
+
<?php foreach ( $scan_days as $value => $html ) : ?>
|
1234 |
+
<option
|
1235 |
+
value="<?php echo esc_attr( $value ); ?>"
|
1236 |
+
<?php echo esc_attr( $value == $this->scan_settings['scan_day'] ? 'selected' : false ); ?>>
|
1237 |
+
<?php echo esc_html( $html ); ?>
|
1238 |
+
</option>
|
1239 |
+
<?php endforeach; ?>
|
1240 |
+
</select>
|
1241 |
+
<br />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1242 |
<span class="description">
|
1243 |
+
<?php esc_html_e( 'Day', 'wp-security-audit-log' ); ?>
|
1244 |
</span>
|
1245 |
+
</span>
|
1246 |
+
|
1247 |
+
<span class="wsal-scan-time-container hide" id="wsal-scan-date">
|
1248 |
+
<select name="wsal-scan-date">
|
1249 |
+
<?php foreach ( $scan_date as $value => $html ) : ?>
|
1250 |
+
<option
|
1251 |
+
value="<?php echo esc_attr( $value ); ?>"
|
1252 |
+
<?php echo esc_attr( $value == $this->scan_settings['scan_date'] ? 'selected' : false ); ?>>
|
1253 |
+
<?php echo esc_html( $html ); ?>
|
1254 |
+
</option>
|
1255 |
+
<?php endforeach; ?>
|
1256 |
+
</select>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1257 |
<br />
|
1258 |
<span class="description">
|
1259 |
+
<?php esc_html_e( 'Day', 'wp-security-audit-log' ); ?>
|
1260 |
</span>
|
1261 |
+
</span>
|
1262 |
+
</fieldset>
|
1263 |
+
</td>
|
1264 |
+
</tr>
|
1265 |
+
</tbody>
|
1266 |
+
</table>
|
1267 |
+
<!-- wsal-scan-frequency -->
|
1268 |
+
|
1269 |
+
<h3><?php esc_html_e( 'Which directories should be scanned for file changes?', 'wp-security-audit-log' ); ?></h3>
|
1270 |
+
<p class="description">
|
1271 |
+
<?php esc_html_e( 'The plugin will scan all the directories in your WordPress website by default because that is the most secure option. Though if for some reason you do not want the plugin to scan any of these directories you can uncheck them from the below list.', 'wp-security-audit-log' ); ?>
|
1272 |
+
</p>
|
1273 |
+
<table class="form-table wsal-tab">
|
1274 |
+
<tbody>
|
1275 |
+
<tr>
|
1276 |
+
<th>
|
1277 |
+
<label for="wsal-scan-directories"><?php esc_html_e( 'Directories to scan', 'wp-security-audit-log' ); ?></label>
|
1278 |
+
</th>
|
1279 |
+
<td>
|
1280 |
+
<?php
|
1281 |
+
// WP Directories.
|
1282 |
+
$wp_directories = array(
|
1283 |
+
'root' => __( 'Root directory of WordPress (excluding sub directories)', 'wp-security-audit-log' ),
|
1284 |
+
'wp-admin' => __( 'WP Admin directory (/wp-admin/)', 'wp-security-audit-log' ),
|
1285 |
+
'wp-includes' => __( 'WP Includes directory (/wp-includes/)', 'wp-security-audit-log' ),
|
1286 |
+
'wp-content' => __( '/wp-content/ directory (excluding plugins, themes & uploads directories)', 'wp-security-audit-log' ),
|
1287 |
+
'wp-content/themes' => __( 'Themes directory (/wp-content/themes/)', 'wp-security-audit-log' ),
|
1288 |
+
'wp-content/plugins' => __( 'Plugins directory (/wp-content/plugins/)', 'wp-security-audit-log' ),
|
1289 |
+
'wp-content/uploads' => __( 'Uploads directory (/wp-content/uploads/)', 'wp-security-audit-log' ),
|
1290 |
+
);
|
1291 |
+
|
1292 |
+
// Check if multisite.
|
1293 |
+
if ( is_multisite() ) {
|
1294 |
+
// Upload directories of subsites.
|
1295 |
+
$wp_directories['wp-content/uploads/sites'] = __( 'Uploads directory of all sub sites on this network (/wp-content/sites/*)', 'wp-security-audit-log' );
|
1296 |
+
}
|
1297 |
+
?>
|
1298 |
+
<fieldset id="wsal-scan-directories">
|
1299 |
+
<?php foreach ( $wp_directories as $value => $html ) : ?>
|
1300 |
+
<label>
|
1301 |
+
<input
|
1302 |
+
name="wsal-scan-directories[<?php echo esc_attr( $value ); ?>]"
|
1303 |
+
type="checkbox"
|
1304 |
+
value="<?php echo esc_attr( $value ); ?>"
|
1305 |
+
<?php echo esc_attr( in_array( $value, $this->scan_settings['scan_directories'], true ) ? 'checked' : false ); ?>
|
1306 |
+
/>
|
1307 |
+
<?php echo esc_html( $html ); ?>
|
1308 |
+
</label>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1309 |
<br />
|
1310 |
+
<?php endforeach; ?>
|
1311 |
+
</fieldset>
|
1312 |
+
</td>
|
1313 |
+
</tr>
|
1314 |
+
</tbody>
|
1315 |
+
</table>
|
1316 |
+
<!-- wsal-scan-directories -->
|
1317 |
+
|
1318 |
+
<h3><?php esc_html_e( 'Do you want to exclude specific files or files with a particular extension from the scan?', 'wp-security-audit-log' ); ?></h3>
|
1319 |
+
<p class="description"><?php esc_html_e( 'The plugin will scan everything that is in the WordPress root directory or below, even if the files and directories are not part of WordPress. It is recommended to scan all source code files and only exclude files that cannot be tampered, such as text files, media files etc, most of which are already excluded by default.', 'wp-security-audit-log' ); ?></p>
|
1320 |
+
<table class="form-table wsal-tab">
|
1321 |
+
<tbody>
|
1322 |
+
<tr>
|
1323 |
+
<th>
|
1324 |
+
<label for="wsal_add_dir_name"><?php esc_html_e( 'Exclude All Files in These Directories', 'wp-security-audit-log' ); ?></label>
|
1325 |
+
</th>
|
1326 |
+
<td>
|
1327 |
+
<div class="wsal_file_containter">
|
1328 |
+
<div id="wsal_dirs">
|
1329 |
+
<?php foreach ( $this->scan_settings['scan_excluded_dirs'] as $index => $dir ) : ?>
|
1330 |
+
<span id="wsal_dir-<?php echo esc_attr( $dir ); ?>">
|
1331 |
+
<input type="checkbox" id="<?php echo esc_attr( $dir ); ?>" value="<?php echo esc_attr( $dir ); ?>" />
|
1332 |
+
<label for="<?php echo esc_attr( $dir ); ?>"><?php echo esc_html( $dir ); ?></label>
|
1333 |
+
</span>
|
1334 |
+
<?php endforeach; ?>
|
1335 |
+
</div>
|
1336 |
+
<?php wp_nonce_field( 'wsal-scan-remove-exception-dir', 'wsal_scan_remove_exception_dir' ); ?>
|
1337 |
+
<input class="button" id="wsal_remove_exception_dir" type="button" value="<?php esc_html_e( 'REMOVE', 'wp-security-audit-log' ); ?>" />
|
1338 |
+
</div>
|
1339 |
+
<div class="wsal_file_containter">
|
1340 |
+
<input type="text" id="wsal_add_dir_name" />
|
1341 |
+
<?php wp_nonce_field( 'wsal-scan-exception-dir', 'wsal_scan_exception_dir' ); ?>
|
1342 |
+
<input id="wsal_add_dir" class="button" type="button" value="<?php esc_html_e( 'ADD', 'wp-security-audit-log' ); ?>" />
|
1343 |
+
</div>
|
1344 |
+
<p class="description">
|
1345 |
+
<?php esc_html_e( 'Specify the name of the directory and the path to it in relation to the website\'s root. For example, if you want to want to exclude all files in the sub directory dir1/dir2 specify the following:', 'wp-security-audit-log' ); ?>
|
1346 |
+
<br>
|
1347 |
+
<?php echo esc_html( trailingslashit( ABSPATH ) ) . 'dir1/dir2/'; ?>
|
1348 |
+
</p>
|
1349 |
+
<span class="error hide" id="wsal_dir_error"></span>
|
1350 |
+
</td>
|
1351 |
+
</tr>
|
1352 |
+
<!-- wsal-scan-exclude-dirs -->
|
1353 |
+
|
1354 |
+
<tr>
|
1355 |
+
<th>
|
1356 |
+
<label for="wsal_add_file_name"><?php esc_html_e( 'Exclude These Files', 'wp-security-audit-log' ); ?></label>
|
1357 |
+
</th>
|
1358 |
+
<td>
|
1359 |
+
<?php
|
1360 |
+
// Get files to be excluded.
|
1361 |
+
$excluded_files = $this->_plugin->GetGlobalOption( 'scan_excluded_files', array() );
|
1362 |
+
?>
|
1363 |
+
<div class="wsal_file_containter">
|
1364 |
+
<div id="wsal_files">
|
1365 |
+
<?php foreach ( $excluded_files as $index => $file ) : ?>
|
1366 |
+
<span id="wsal_file-<?php echo esc_attr( $file ); ?>">
|
1367 |
+
<input type="checkbox" id="<?php echo esc_attr( $file ); ?>" value="<?php echo esc_attr( $file ); ?>" />
|
1368 |
+
<label for="<?php echo esc_attr( $file ); ?>"><?php echo esc_html( $file ); ?></label>
|
1369 |
+
</span>
|
1370 |
+
<?php endforeach; ?>
|
1371 |
+
</div>
|
1372 |
+
<?php wp_nonce_field( 'wsal-scan-remove-exception-file', 'wsal_scan_remove_exception_file' ); ?>
|
1373 |
+
<input class="button" id="wsal_remove_exception_file" type="button" value="<?php esc_html_e( 'REMOVE', 'wp-security-audit-log' ); ?>" />
|
1374 |
+
</div>
|
1375 |
+
<div class="wsal_file_containter">
|
1376 |
+
<input type="text" id="wsal_add_file_name" />
|
1377 |
+
<?php wp_nonce_field( 'wsal-scan-exception-file', 'wsal_scan_exception_file' ); ?>
|
1378 |
+
<input id="wsal_add_file" class="button" type="button" value="<?php esc_html_e( 'ADD', 'wp-security-audit-log' ); ?>" />
|
1379 |
+
</div>
|
1380 |
+
<p class="description">
|
1381 |
+
<?php esc_html_e( 'Specify the name and extension of the file(s) you want to exclude. Wildcard not supported. There is no need to specify the path of the file.', 'wp-security-audit-log' ); ?>
|
1382 |
+
</p>
|
1383 |
+
<span class="error hide" id="wsal_file_name_error"></span>
|
1384 |
+
</td>
|
1385 |
+
</tr>
|
1386 |
+
<!-- wsal_add_file_name -->
|
1387 |
+
|
1388 |
+
<tr>
|
1389 |
+
<th>
|
1390 |
+
<label for="wsal_add_file_type_name"><?php esc_html_e( 'Exclude these File Types', 'wp-security-audit-log' ); ?></label>
|
1391 |
+
</th>
|
1392 |
+
<td>
|
1393 |
+
<div class="wsal_file_containter">
|
1394 |
+
<div id="wsal_files_types">
|
1395 |
+
<?php foreach ( $this->scan_settings['scan_excluded_extensions'] as $index => $file_type ) : ?>
|
1396 |
+
<span id="wsal_file_type-<?php echo esc_attr( $file_type ); ?>">
|
1397 |
+
<input type="checkbox" id="<?php echo esc_attr( $file_type ); ?>" value="<?php echo esc_attr( $file_type ); ?>" />
|
1398 |
+
<label for="<?php echo esc_attr( $file_type ); ?>"><?php echo esc_html( $file_type ); ?></label>
|
1399 |
+
</span>
|
1400 |
+
<?php endforeach; ?>
|
1401 |
+
</div>
|
1402 |
+
<?php wp_nonce_field( 'wsal-scan-remove-exception-file-type', 'wsal_scan_remove_exception_file_type' ); ?>
|
1403 |
+
<input class="button" id="wsal_remove_exception_file_type" type="button" value="<?php esc_html_e( 'REMOVE', 'wp-security-audit-log' ); ?>" />
|
1404 |
+
</div>
|
1405 |
+
<div class="wsal_file_containter">
|
1406 |
+
<input type="text" id="wsal_add_file_type_name" />
|
1407 |
+
<?php wp_nonce_field( 'wsal-scan-exception-file-type', 'wsal_scan_exception_file_type' ); ?>
|
1408 |
+
<input id="wsal_add_file_type" class="button" type="button" value="<?php esc_html_e( 'ADD', 'wp-security-audit-log' ); ?>" />
|
1409 |
+
</div>
|
1410 |
+
<p class="description">
|
1411 |
+
<?php esc_html_e( 'Specify the extension of the file types you want to exclude. You should exclude any type of logs and backup files that tend to be very big.', 'wp-security-audit-log' ); ?>
|
1412 |
+
</p>
|
1413 |
+
<span class="error hide" id="wsal_file_type_error"></span>
|
1414 |
+
</td>
|
1415 |
+
</tr>
|
1416 |
+
<!-- wsal-scan-exclude-extensions -->
|
1417 |
+
</tbody>
|
1418 |
+
</table>
|
1419 |
+
|
1420 |
+
<h3><?php esc_html_e( 'Launch an instant file integrity scan', 'wp-security-audit-log' ); ?></h3>
|
1421 |
+
<p class="description">
|
1422 |
+
<?php esc_html_e( 'Click the Scan Now button to launch an instant file integrity scan using the configured settings. You can navigate away from this page during the scan. Note that the instant scan can be more resource intensive than scheduled scans.', 'wp-security-audit-log' ); ?>
|
1423 |
+
</p>
|
1424 |
+
<table class="form-table wsal-tab">
|
1425 |
+
<tbody>
|
1426 |
+
<tr>
|
1427 |
+
<th>
|
1428 |
+
<label for="wsal-scan-now"><?php esc_html_e( 'Launch Instant Scan', 'wp-security-audit-log' ); ?></label>
|
1429 |
+
</th>
|
1430 |
+
<td>
|
1431 |
+
<input type="hidden" id="wsal-scan-now-nonce" name="wsal_scan_now_nonce" value="<?php echo esc_attr( wp_create_nonce( 'wsal-scan-now' ) ); ?>" />
|
1432 |
+
<input type="hidden" id="wsal-stop-scan-nonce" name="wsal_stop_scan_nonce" value="<?php echo esc_attr( wp_create_nonce( 'wsal-stop-scan' ) ); ?>" />
|
1433 |
+
<?php if ( ! $this->scan_settings['scan_in_progress'] ) : ?>
|
1434 |
+
<a href="javascript:;" class="button button-primary" id="wsal-scan-now">
|
1435 |
+
<?php esc_attr_e( 'Scan Now', 'wp-security-audit-log' ); ?>
|
1436 |
+
</a>
|
1437 |
+
<a href="javascript:;" class="button button-secondary" id="wsal-stop-scan" disabled>
|
1438 |
+
<?php esc_attr_e( 'Stop Scan', 'wp-security-audit-log' ); ?>
|
1439 |
+
</a>
|
1440 |
+
<?php else : ?>
|
1441 |
+
<a href="javascript:;" class="button button-primary" id="wsal-scan-now" disabled>
|
1442 |
+
<?php esc_attr_e( 'Scan in Progress', 'wp-security-audit-log' ); ?>
|
1443 |
+
</a>
|
1444 |
+
<a href="javascript:;" class="button button-ui-primary" id="wsal-stop-scan">
|
1445 |
+
<?php esc_attr_e( 'Stop Scan', 'wp-security-audit-log' ); ?>
|
1446 |
+
</a>
|
1447 |
+
<!-- Scan in progress -->
|
1448 |
+
<?php endif; ?>
|
1449 |
+
</td>
|
1450 |
+
</tr>
|
1451 |
+
<!-- wsal-scan-now -->
|
1452 |
+
</tbody>
|
1453 |
+
</table>
|
1454 |
+
<!-- / File Changes Logging Tab -->
|
1455 |
+
<?php
|
1456 |
+
}
|
1457 |
|
1458 |
+
/**
|
1459 |
+
* Save: `File Changes`
|
1460 |
+
*/
|
1461 |
+
private function tab_file_changes_save() {
|
1462 |
+
// Get $_POST global array.
|
1463 |
+
$post_array = filter_input_array( INPUT_POST );
|
1464 |
+
|
1465 |
+
// Check and save enable/disable file changes feature.
|
1466 |
+
if ( isset( $post_array['wsal-file-changes'] ) && ! empty( $post_array['wsal-file-changes'] ) ) {
|
1467 |
+
$this->_plugin->SetGlobalOption( 'scan-file-changes', $post_array['wsal-file-changes'] );
|
1468 |
+
|
1469 |
+
// Get file change scan alerts.
|
1470 |
+
$file_change_events = $this->_plugin->alerts->get_alerts_by_sub_category( 'File Changes' );
|
1471 |
+
$file_change_events = array_keys( $file_change_events );
|
1472 |
+
|
1473 |
+
// Enable/disable events based on file changes.
|
1474 |
+
if ( 'disable' === $post_array['wsal-file-changes'] ) {
|
1475 |
+
// Get disabled events.
|
1476 |
+
$disabled_events = $this->_plugin->settings->GetDisabledAlerts();
|
1477 |
+
|
1478 |
+
// Merge file changes events.
|
1479 |
+
$disabled_events = array_merge( $disabled_events, $file_change_events );
|
1480 |
+
|
1481 |
+
// Save the events.
|
1482 |
+
$this->_plugin->alerts->SetDisabledAlerts( $disabled_events );
|
1483 |
+
} else {
|
1484 |
+
// Get disabled events.
|
1485 |
+
$disabled_events = $this->_plugin->settings->GetDisabledAlerts();
|
1486 |
+
|
1487 |
+
foreach ( $file_change_events as $file_change_event ) {
|
1488 |
+
// Search for file change events in disabled events.
|
1489 |
+
$key = array_search( $file_change_event, $disabled_events, true );
|
1490 |
+
|
1491 |
+
// If key is found, then unset it.
|
1492 |
+
if ( $key ) {
|
1493 |
+
unset( $disabled_events[ $key ] );
|
1494 |
}
|
1495 |
}
|
1496 |
|
1497 |
+
// Save the disabled events.
|
1498 |
+
$this->_plugin->alerts->SetDisabledAlerts( $disabled_events );
|
1499 |
+
}
|
1500 |
+
} else {
|
1501 |
+
$this->_plugin->SetGlobalOption( 'scan-file-changes', false );
|
1502 |
+
}
|
1503 |
|
1504 |
+
// Check and save scan frequency.
|
1505 |
+
$this->_plugin->SetGlobalOption( 'scan-frequency', isset( $post_array['wsal-scan-frequency'] ) ? $post_array['wsal-scan-frequency'] : false );
|
1506 |
+
$this->_plugin->SetGlobalOption( 'scan-hour', isset( $post_array['wsal-scan-hour'] ) ? $post_array['wsal-scan-hour'] : false );
|
1507 |
+
$this->_plugin->SetGlobalOption( 'scan-day', isset( $post_array['wsal-scan-day'] ) ? $post_array['wsal-scan-day'] : false );
|
1508 |
+
$this->_plugin->SetGlobalOption( 'scan-date', isset( $post_array['wsal-scan-date'] ) ? $post_array['wsal-scan-date'] : false );
|
1509 |
+
|
1510 |
+
// Check and save scan directories.
|
1511 |
+
if (
|
1512 |
+
isset( $post_array['wsal-scan-directories'] )
|
1513 |
+
&& is_array( $post_array['wsal-scan-directories'] )
|
1514 |
+
) {
|
1515 |
+
$scan_directories = array_keys( $post_array['wsal-scan-directories'] );
|
1516 |
+
$this->_plugin->SetGlobalOption( 'scan-directories', $scan_directories );
|
1517 |
+
}
|
1518 |
+
}
|
1519 |
+
|
1520 |
+
/**
|
1521 |
+
* Tab: `Exclude Objects`
|
1522 |
+
*/
|
1523 |
+
private function tab_exclude_objects() {
|
1524 |
+
?>
|
1525 |
+
<p class="description"><?php esc_html_e( 'By default the plugin keeps a log of all user changes done on your WordPress website. Use the setting below to exclude any objects from the activity log. When an object is excluded from the activity log, any event in which that object is referred will not be logged in the activity log.', 'wp-security-audit-log' ); ?></p>
|
1526 |
+
<table class="form-table wsal-tab">
|
1527 |
+
<tbody>
|
1528 |
+
<tr>
|
1529 |
+
<th><label for="ExUserQueryBox"><?php esc_html_e( 'Exclude Users:', 'wp-security-audit-log' ); ?></label></th>
|
1530 |
+
<td>
|
1531 |
+
<fieldset>
|
1532 |
+
<input type="text" id="ExUserQueryBox" style="width: 250px;">
|
1533 |
+
<input type="button" id="ExUserQueryAdd" class="button-primary" value="Add">
|
1534 |
+
<br style="clear: both;"/>
|
1535 |
+
<div id="ExUserList">
|
1536 |
+
<?php foreach ( $this->_plugin->settings->GetExcludedMonitoringUsers() as $item ) : ?>
|
1537 |
+
<span class="sectoken-<?php echo esc_attr( $this->GetTokenType( $item ) ); ?>">
|
1538 |
+
<input type="hidden" name="ExUsers[]" value="<?php echo esc_attr( $item ); ?>"/>
|
1539 |
+
<?php echo esc_html( $item ); ?>
|
1540 |
+
<a href="javascript:;" title="Remove">×</a>
|
1541 |
+
</span>
|
1542 |
+
<?php endforeach; ?>
|
1543 |
+
</div>
|
1544 |
+
</fieldset>
|
1545 |
+
</td>
|
1546 |
+
</tr>
|
1547 |
+
<!-- Exclude Users -->
|
1548 |
+
|
1549 |
+
<tr>
|
1550 |
+
<th><label for="ExRoleQueryBox"><?php esc_html_e( 'Exclude Roles:', 'wp-security-audit-log' ); ?></label></th>
|
1551 |
+
<td>
|
1552 |
+
<fieldset>
|
1553 |
+
<input type="text" id="ExRoleQueryBox" style="width: 250px;">
|
1554 |
+
<input type="button" id="ExRoleQueryAdd" class="button-primary" value="Add">
|
1555 |
+
<br style="clear: both;"/>
|
1556 |
+
<div id="ExRoleList">
|
1557 |
+
<?php foreach ( $this->_plugin->settings->GetExcludedMonitoringRoles() as $item ) : ?>
|
1558 |
+
<span class="sectoken-<?php echo esc_attr( $this->GetTokenType( $item ) ); ?>">
|
1559 |
+
<input type="hidden" name="ExRoles[]" value="<?php echo esc_attr( $item ); ?>"/>
|
1560 |
+
<?php echo esc_html( $item ); ?>
|
1561 |
+
<a href="javascript:;" title="Remove">×</a>
|
1562 |
+
</span>
|
1563 |
+
<?php endforeach; ?>
|
1564 |
+
</div>
|
1565 |
+
</fieldset>
|
1566 |
+
</td>
|
1567 |
+
</tr>
|
1568 |
+
<!-- Exclude Roles -->
|
1569 |
+
|
1570 |
+
<tr>
|
1571 |
+
<th><label for="IpAddrQueryBox"><?php esc_html_e( 'Exclude IP Addresses:', 'wp-security-audit-log' ); ?></label></th>
|
1572 |
+
<td>
|
1573 |
+
<fieldset>
|
1574 |
+
<input type="text" id="IpAddrQueryBox" style="width: 250px;">
|
1575 |
+
<input type="button" id="IpAddrQueryAdd" class="button-primary" value="Add">
|
1576 |
+
<br style="clear: both;"/>
|
1577 |
+
<div id="IpAddrList">
|
1578 |
+
<?php foreach ( $this->_plugin->settings->GetExcludedMonitoringIP() as $item ) : ?>
|
1579 |
+
<span class="sectoken-<?php echo esc_attr( $this->GetTokenType( $item ) ); ?>">
|
1580 |
+
<input type="hidden" name="IpAddrs[]" value="<?php echo esc_attr( $item ); ?>"/>
|
1581 |
+
<?php echo esc_html( $item ); ?>
|
1582 |
+
<a href="javascript:;" title="Remove">×</a>
|
1583 |
+
</span>
|
1584 |
+
<?php endforeach; ?>
|
1585 |
+
</div>
|
1586 |
+
</fieldset>
|
1587 |
+
</td>
|
1588 |
+
</tr>
|
1589 |
+
<!-- Exclude IP Addresses -->
|
1590 |
+
|
1591 |
+
<tr>
|
1592 |
+
<th><label for="ExCPTsQueryBox"><?php esc_html_e( 'Exclude Post Type:', 'wp-security-audit-log' ); ?></label></th>
|
1593 |
+
<td>
|
1594 |
+
<fieldset>
|
1595 |
+
<input type="text" id="ExCPTsQueryBox" style="width: 250px;">
|
1596 |
+
<input type="button" id="ExCPTsQueryAdd" class="button-primary" value="Add">
|
1597 |
+
<br style="clear: both;"/>
|
1598 |
+
<div id="ExCPTsList">
|
1599 |
+
<?php foreach ( $this->_plugin->settings->get_excluded_post_types() as $item ) : ?>
|
1600 |
+
<span class="sectoken-<?php echo esc_attr( $this->GetTokenType( $item ) ); ?>">
|
1601 |
+
<input type="hidden" name="ExCPTss[]" value="<?php echo esc_attr( $item ); ?>"/>
|
1602 |
+
<?php echo esc_html( $item ); ?>
|
1603 |
+
<a href="javascript:;" title="Remove">×</a>
|
1604 |
+
</span>
|
1605 |
+
<?php endforeach; ?>
|
1606 |
+
</div>
|
1607 |
+
<p class="description"><?php esc_html_e( 'WordPress has the post and page post types by default though your website might use more post types (custom post types). You can exclude all post types, including the default WordPress ones.', 'wp-security-audit-log' ); ?></p>
|
1608 |
+
</fieldset>
|
1609 |
+
</td>
|
1610 |
+
</tr>
|
1611 |
+
<!-- Exclude Custom Post Types -->
|
1612 |
+
|
1613 |
+
<tr>
|
1614 |
+
<th><label for="CustomQueryBox"><?php esc_html_e( 'Exclude Custom Fields:', 'wp-security-audit-log' ); ?></label></th>
|
1615 |
+
<td>
|
1616 |
+
<fieldset>
|
1617 |
+
<input type="text" id="CustomQueryBox" style="width: 250px;">
|
1618 |
+
<input type="button" id="CustomQueryAdd" class="button-primary" value="Add">
|
1619 |
+
<br style="clear: both;"/>
|
1620 |
+
<div id="CustomList">
|
1621 |
+
<?php foreach ( $this->_plugin->settings->GetExcludedMonitoringCustom() as $item ) : ?>
|
1622 |
+
<span class="sectoken-<?php echo esc_attr( $this->GetTokenType( $item ) ); ?>">
|
1623 |
+
<input type="hidden" name="Customs[]" value="<?php echo esc_attr( $item ); ?>"/>
|
1624 |
+
<?php echo esc_html( $item ); ?>
|
1625 |
+
<a href="javascript:;" title="Remove">×</a>
|
1626 |
+
</span>
|
1627 |
+
<?php endforeach; ?>
|
1628 |
+
</div>
|
1629 |
+
<p class="description"><?php esc_html_e( 'You can use the * wildcard to exclude multiple matching custom fields. For example to exclude all custom fields starting with wp123 enter wp123*', 'wp-security-audit-log' ); ?></p>
|
1630 |
+
</fieldset>
|
1631 |
+
</td>
|
1632 |
+
</tr>
|
1633 |
+
<!-- Exclude Custom Fields -->
|
1634 |
+
|
1635 |
+
<tr>
|
1636 |
+
<th><label for="ExURLsQueryBox"><?php esc_html_e( 'Exclude Non-Existing URLs:', 'wp-security-audit-log' ); ?></label></th>
|
1637 |
+
<td>
|
1638 |
+
<fieldset>
|
1639 |
+
<input type="text" id="ExURLsQueryBox" style="width: 250px;">
|
1640 |
+
<input type="button" id="ExURLsQueryAdd" class="button-primary" value="Add">
|
1641 |
+
<br style="clear: both;"/>
|
1642 |
+
<div id="ExURLsList">
|
1643 |
+
<?php foreach ( $this->_plugin->settings->get_excluded_urls() as $item ) : ?>
|
1644 |
+
<span class="sectoken-<?php echo esc_attr( $this->GetTokenType( $item ) ); ?>">
|
1645 |
+
<input type="hidden" name="ExURLss[]" value="<?php echo esc_attr( $item ); ?>"/>
|
1646 |
+
<?php echo esc_html( $item ); ?>
|
1647 |
+
<a href="javascript:;" title="Remove">×</a>
|
1648 |
+
</span>
|
1649 |
+
<?php endforeach; ?>
|
1650 |
+
</div>
|
1651 |
+
<p class="description">
|
1652 |
+
<?php esc_html_e( 'Add the non existing URLs for which you do not want to be alerted of HTTP 404 errors in the activity log by specifying the complete URL. Examples below:', 'wp-security-audit-log' ); ?>
|
1653 |
+
<br>
|
1654 |
+
<?php echo esc_html__( 'File: ', 'wp-security-audit-log' ) . esc_url( home_url() ) . '/subdirectory/file.php'; ?>
|
1655 |
+
<br>
|
1656 |
+
<?php echo esc_html__( 'Directory: ', 'wp-security-audit-log' ) . esc_url( home_url() ) . '/subdirectory/subdirectory2'; ?>
|
1657 |
+
</p>
|
1658 |
+
</fieldset>
|
1659 |
+
</td>
|
1660 |
+
</tr>
|
1661 |
+
<!-- Exclude 404 URLs -->
|
1662 |
+
</tbody>
|
1663 |
+
</table>
|
1664 |
+
<!-- / Exclude Objects Tab -->
|
1665 |
+
<?php
|
1666 |
+
}
|
1667 |
+
|
1668 |
+
/**
|
1669 |
+
* Save: `Exclude Objects`
|
1670 |
+
*/
|
1671 |
+
private function tab_exclude_objects_save() {
|
1672 |
+
// Get $_POST global array.
|
1673 |
+
$post_array = filter_input_array( INPUT_POST );
|
1674 |
+
|
1675 |
+
$this->_plugin->settings->SetExcludedMonitoringUsers( isset( $post_array['ExUsers'] ) ? $post_array['ExUsers'] : array() );
|
1676 |
+
$this->_plugin->settings->SetExcludedMonitoringRoles( isset( $post_array['ExRoles'] ) ? $post_array['ExRoles'] : array() );
|
1677 |
+
$this->_plugin->settings->SetExcludedMonitoringCustom( isset( $post_array['Customs'] ) ? $post_array['Customs'] : array() );
|
1678 |
+
$this->_plugin->settings->SetExcludedMonitoringIP( isset( $post_array['IpAddrs'] ) ? $post_array['IpAddrs'] : array() );
|
1679 |
+
$this->_plugin->settings->set_excluded_post_types( isset( $post_array['ExCPTss'] ) ? $post_array['ExCPTss'] : array() );
|
1680 |
+
$this->_plugin->settings->set_excluded_urls( isset( $post_array['ExURLss'] ) ? $post_array['ExURLss'] : array() );
|
1681 |
+
}
|
1682 |
+
|
1683 |
+
/**
|
1684 |
+
* Tab: `Advanced Settings`
|
1685 |
+
*/
|
1686 |
+
private function tab_advanced_settings() {
|
1687 |
+
?>
|
1688 |
+
<p class="description">
|
1689 |
+
<?php esc_html_e( 'These settings are for advanced users.', 'wp-security-audit-log' ); ?>
|
1690 |
+
<?php echo sprintf( __( 'If you have any questions <a href="https://www.wpsecurityauditlog.com/contact/" target="_blank">contact us</a>.', 'wp-security-audit-log' ), $this->_plugin->allowed_html_tags ); ?>
|
1691 |
+
</p>
|
1692 |
+
|
1693 |
+
<h3><?php esc_html_e( 'Troubleshooting setting: Keep a debug log of all the requests this website receives', 'wp-security-audit-log' ); ?></h3>
|
1694 |
+
<p class="description"><?php esc_html_e( 'Only enable the request log on testing, staging and development website. Never enable logging on a live website unless instructed to do so. Enabling request logging on a live website may degrade the performance of the website.', 'wp-security-audit-log' ); ?></p>
|
1695 |
+
<table class="form-table wsal-tab">
|
1696 |
+
<tbody>
|
1697 |
+
<tr>
|
1698 |
+
<th><label><?php esc_html_e( 'Request Log', 'wp-security-audit-log' ); ?></label></th>
|
1699 |
+
<td>
|
1700 |
+
<fieldset>
|
1701 |
+
<?php $devoption_checked = $this->_plugin->settings->IsDevOptionEnabled( WSAL_Settings::OPT_DEV_REQUEST_LOG ); ?>
|
1702 |
+
<label for="devoption_yes">
|
1703 |
+
<input type="radio" name="DevOptions" id="devoption_yes"
|
1704 |
+
<?php checked( $devoption_checked, true ); ?>
|
1705 |
+
value="<?php echo esc_attr( WSAL_Settings::OPT_DEV_REQUEST_LOG ); ?>">
|
1706 |
+
<?php esc_html_e( 'Yes', 'wp-security-audit-log' ); ?>
|
1707 |
+
</label>
|
1708 |
+
<br>
|
1709 |
+
<label for="devoption_no">
|
1710 |
+
<input type="radio" name="DevOptions" id="devoption_no" <?php checked( $devoption_checked, false ); ?> value="0">
|
1711 |
+
<?php esc_html_e( 'No', 'wp-security-audit-log' ); ?>
|
1712 |
+
</label>
|
1713 |
+
<p class="description">
|
1714 |
+
<?php
|
1715 |
+
echo wp_kses(
|
1716 |
+
__( '<strong>Note:</strong> The requests debug log file is saved as request.log.php in the /wp-content/uploads/wp-security-audit-log/ directory.' ),
|
1717 |
+
$this->_plugin->allowed_html_tags
|
1718 |
+
);
|
1719 |
+
?>
|
1720 |
+
</p>
|
1721 |
+
</fieldset>
|
1722 |
+
</td>
|
1723 |
+
</tr>
|
1724 |
+
<!-- / Developer Options -->
|
1725 |
+
</tbody>
|
1726 |
+
</table>
|
1727 |
+
|
1728 |
+
<h3><?php esc_html_e( 'Reset plugin settings to default', 'wp-security-audit-log' ); ?></h3>
|
1729 |
+
<p class="description"><?php esc_html_e( 'Click the RESET button to reset ALL plugin settings to default. Note that the activity log data will be retained and only the plugin settings will be reset. To purge the data of the activity log use the setting below.', 'wp-security-audit-log' ); ?></p>
|
1730 |
+
<table class="form-table wsal-tab">
|
1731 |
+
<tbody>
|
1732 |
+
<tr>
|
1733 |
+
<th><?php esc_html_e( 'Reset Settings', 'wp-security-audit-log' ); ?></th>
|
1734 |
+
<td>
|
1735 |
+
<a href="#wsal_reset_settings" class="button-primary"><?php esc_html_e( 'RESET', 'wp-security-audit-log' ); ?></a>
|
1736 |
+
</td>
|
1737 |
+
</tr>
|
1738 |
+
</tbody>
|
1739 |
+
</table>
|
1740 |
+
|
1741 |
+
<h3><?php esc_html_e( 'Purge the WordPress activity log', 'wp-security-audit-log' ); ?></h3>
|
1742 |
+
<p class="description"><?php esc_html_e( 'Click the Purge button below to delete all the data from the WordPress activity log and start afresh.', 'wp-security-audit-log' ); ?></p>
|
1743 |
+
<table class="form-table wsal-tab">
|
1744 |
+
<tbody>
|
1745 |
+
<tr>
|
1746 |
+
<th><?php esc_html_e( 'Purge Activity Log', 'wp-security-audit-log' ); ?></th>
|
1747 |
+
<td>
|
1748 |
+
<a href="#wsal_purge_activity" class="button-primary"><?php esc_html_e( 'PURGE', 'wp-security-audit-log' ); ?></a>
|
1749 |
+
</td>
|
1750 |
+
</tr>
|
1751 |
+
</tbody>
|
1752 |
+
</table>
|
1753 |
+
|
1754 |
+
<h3><?php esc_html_e( 'Do you want to delete the plugin data from the database upon uninstall?', 'wp-security-audit-log' ); ?></h3>
|
1755 |
+
<p class="description"><?php esc_html_e( 'The plugin saves the activity log data and settings in the WordPress database. By default upon uninstalling the plugin the data is kept in the database so if it is installed again, you can still access the data. If the data is deleted it is not possible to recover it so you won\'t be able to access it again even when you reinstall the plugin.', 'wp-security-audit-log' ); ?></p>
|
1756 |
+
<table class="form-table wsal-tab">
|
1757 |
+
<tbody>
|
1758 |
+
<tr>
|
1759 |
+
<th><label for="DeleteData"><?php esc_html_e( 'Remove Data on Uninstall', 'wp-security-audit-log' ); ?></label></th>
|
1760 |
+
<td>
|
1761 |
+
<fieldset>
|
1762 |
+
<label for="delete_data_yes">
|
1763 |
+
<input type="radio" name="DeleteData" value="1" id="delete_data_yes" onclick="return delete_confirm(this);"
|
1764 |
+
<?php checked( $this->_plugin->settings->IsDeleteData() ); ?>
|
1765 |
+
/>
|
1766 |
+
<?php esc_html_e( 'Yes', 'wp-security-audit-log' ); ?>
|
1767 |
+
</label>
|
1768 |
+
<br>
|
1769 |
+
<label for="delete_data_no">
|
1770 |
+
<input type="radio" name="DeleteData" value="0" id="delete_data_no"
|
1771 |
+
<?php checked( $this->_plugin->settings->IsDeleteData(), false ); ?>
|
1772 |
+
/>
|
1773 |
+
<?php esc_html_e( 'No', 'wp-security-audit-log' ); ?>
|
1774 |
+
</label>
|
1775 |
+
</fieldset>
|
1776 |
+
</td>
|
1777 |
+
</tr>
|
1778 |
+
<!-- / Remove Data on Uninstall -->
|
1779 |
+
</tbody>
|
1780 |
+
</table>
|
1781 |
+
|
1782 |
+
<div class="remodal" data-remodal-id="wsal_reset_settings">
|
1783 |
+
<button data-remodal-action="close" class="remodal-close"></button>
|
1784 |
+
<h3><?php esc_html_e( 'Are you sure you want to reset all the plugin settings to default?', 'wp-security-audit-log' ); ?></h3>
|
1785 |
+
<br>
|
1786 |
+
<input type="hidden" id="wsal-reset-settings-nonce" value="<?php echo esc_attr( wp_create_nonce( 'wsal-reset-settings' ) ); ?>">
|
1787 |
+
<button data-remodal-action="confirm" class="remodal-confirm"><?php esc_html_e( 'Yes', 'wp-security-audit-log' ); ?></button>
|
1788 |
+
<button data-remodal-action="cancel" class="remodal-cancel"><?php esc_html_e( 'No', 'wp-security-audit-log' ); ?></button>
|
1789 |
+
</div>
|
1790 |
+
<!-- Reset Settings Modal -->
|
1791 |
+
|
1792 |
+
<div class="remodal" data-remodal-id="wsal_purge_activity">
|
1793 |
+
<button data-remodal-action="close" class="remodal-close"></button>
|
1794 |
+
<h3><?php esc_html_e( 'Are you sure you want to purge all the activity log data?', 'wp-security-audit-log' ); ?></h3>
|
1795 |
+
<br>
|
1796 |
+
<input type="hidden" id="wsal-purge-activity-nonce" value="<?php echo esc_attr( wp_create_nonce( 'wsal-purge-activity' ) ); ?>">
|
1797 |
+
<button data-remodal-action="confirm" class="remodal-confirm"><?php esc_html_e( 'Yes', 'wp-security-audit-log' ); ?></button>
|
1798 |
+
<button data-remodal-action="cancel" class="remodal-cancel"><?php esc_html_e( 'No', 'wp-security-audit-log' ); ?></button>
|
1799 |
+
</div>
|
1800 |
+
<!-- Purge Activity Log Modal -->
|
1801 |
<?php
|
1802 |
}
|
1803 |
|
1804 |
+
/**
|
1805 |
+
* Save: `Advanced Settings`
|
1806 |
+
*/
|
1807 |
+
private function tab_advanced_settings_save() {
|
1808 |
+
// Get $_POST global array.
|
1809 |
+
$post_array = filter_input_array( INPUT_POST );
|
1810 |
+
|
1811 |
+
$this->_plugin->settings->SetDeleteData( isset( $post_array['DeleteData'] ) ? sanitize_text_field( $post_array['DeleteData'] ) : false );
|
1812 |
+
$this->_plugin->settings->ClearDevOptions();
|
1813 |
+
if ( isset( $post_array['DevOptions'] ) && 'r' === $post_array['DevOptions'] ) {
|
1814 |
+
$this->_plugin->settings->SetDevOptionEnabled( 'r', true );
|
1815 |
+
} else {
|
1816 |
+
$this->_plugin->settings->SetDevOptionEnabled( 'r', false );
|
1817 |
+
}
|
1818 |
+
}
|
1819 |
+
|
1820 |
/**
|
1821 |
* Method: Get View Header.
|
1822 |
*/
|
1827 |
array(),
|
1828 |
filemtime( $this->_plugin->GetBaseDir() . '/css/settings.css' )
|
1829 |
);
|
1830 |
+
|
1831 |
+
// Check current tab.
|
1832 |
+
if ( ! empty( $this->current_tab ) && 'advanced-settings' === $this->current_tab ) {
|
1833 |
+
// Remodal styles.
|
1834 |
+
wp_enqueue_style( 'wsal-remodal', WSAL_BASE_URL . 'css/remodal.css', array(), '1.1.1' );
|
1835 |
+
wp_enqueue_style( 'wsal-remodal-theme', WSAL_BASE_URL . 'css/remodal-default-theme.css', array(), '1.1.1' );
|
1836 |
+
}
|
1837 |
?>
|
1838 |
<style type="text/css">
|
1839 |
.wsal-tab {
|
1840 |
+
/* display: none; */
|
1841 |
}
|
1842 |
.wsal-tab tr.alert-incomplete td {
|
1843 |
color: #9BE;
|
1862 |
false
|
1863 |
);
|
1864 |
|
1865 |
+
// Check current tab.
|
1866 |
+
if ( ! empty( $this->current_tab ) && 'advanced-settings' === $this->current_tab ) {
|
1867 |
+
// Remodal script.
|
1868 |
+
wp_enqueue_script(
|
1869 |
+
'wsal-remodal-js',
|
1870 |
+
WSAL_BASE_URL . 'js/remodal.min.js',
|
1871 |
+
array(),
|
1872 |
+
'1.1.1',
|
1873 |
+
true
|
1874 |
+
);
|
1875 |
+
}
|
1876 |
+
|
1877 |
// Register settings script.
|
1878 |
wp_register_script(
|
1879 |
'settings',
|
1884 |
);
|
1885 |
// Passing nonce for security to JS file.
|
1886 |
$wsal_data = array(
|
1887 |
+
'wp_nonce' => wp_create_nonce( 'wsal-exclude-nonce' ),
|
1888 |
+
'invalidURL' => esc_html__( 'The specified token is not a valid URL!', 'wp-security-audit-log' ),
|
1889 |
+
'invalidCPT' => esc_html__( 'The specified token is not a valid post type!', 'wp-security-audit-log' ),
|
1890 |
+
'invalidIP' => esc_html__( 'The specified token is not a valid IP address!', 'wp-security-audit-log' ),
|
1891 |
+
'invalidUser' => esc_html__( 'The specified token is not a user nor a role!', 'wp-security-audit-log' ),
|
1892 |
+
'invalidFile' => esc_html__( 'Filename cannot be added because it contains invalid characters.', 'wp-security-audit-log' ),
|
1893 |
+
'invalidFileExt' => esc_html__( 'File extension cannot be added because it contains invalid characters.', 'wp-security-audit-log' ),
|
1894 |
+
'invalidDir' => esc_html__( 'Directory cannot be added because it contains invalid characters.', 'wp-security-audit-log' ),
|
1895 |
+
'scanNow' => esc_html__( 'Scan Now', 'wp-security-audit-log' ),
|
1896 |
+
'scanFailed' => esc_html__( 'Scan Failed', 'wp-security-audit-log' ),
|
1897 |
+
'scanInProgress' => esc_html__( 'Scan in Progress', 'wp-security-audit-log' ),
|
1898 |
);
|
1899 |
wp_localize_script( 'settings', 'wsal_data', $wsal_data );
|
1900 |
wp_enqueue_script( 'settings' );
|
1901 |
?>
|
1902 |
<script type="text/javascript">
|
1903 |
+
jQuery( document ).ready( function() {
|
1904 |
+
jQuery( '.sel-columns' ).change( function() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1905 |
var notChecked = 1;
|
1906 |
+
jQuery( '.sel-columns' ).each( function() {
|
1907 |
+
if ( this.checked ) notChecked = 0;
|
1908 |
})
|
1909 |
+
if ( notChecked == 1 ) {
|
1910 |
+
alert( esc_html__( 'You have to select at least one column!', 'wp-security-audit-log' ) );
|
1911 |
}
|
1912 |
});
|
1913 |
});</script>
|
2311 |
) );
|
2312 |
exit();
|
2313 |
}
|
2314 |
+
|
2315 |
+
/**
|
2316 |
+
* Method: Reset plugin settings table.
|
2317 |
+
*/
|
2318 |
+
public function reset_settings() {
|
2319 |
+
// Die if user does not have permission to change settings.
|
2320 |
+
if ( ! $this->_plugin->settings->CurrentUserCan( 'view' ) ) {
|
2321 |
+
die( esc_html__( 'Access Denied.', 'wp-security-audit-log' ) );
|
2322 |
+
}
|
2323 |
+
|
2324 |
+
// Verify nonce.
|
2325 |
+
$nonce = filter_input( INPUT_POST, 'nonce', FILTER_SANITIZE_STRING );
|
2326 |
+
if ( ! empty( $nonce ) && wp_verify_nonce( $nonce, 'wsal-reset-settings' ) ) {
|
2327 |
+
global $wpdb;
|
2328 |
+
|
2329 |
+
$table_name = $wpdb->prefix . 'wsal_options';
|
2330 |
+
$result = $wpdb->query( "TRUNCATE {$table_name}" );
|
2331 |
+
|
2332 |
+
if ( $result ) {
|
2333 |
+
die( esc_html__( 'Tables has been reset.', 'wp-security-audit-log' ) );
|
2334 |
+
} else {
|
2335 |
+
die( esc_html__( 'Reset query failed.', 'wp-security-audit-log' ) );
|
2336 |
+
}
|
2337 |
+
} else {
|
2338 |
+
die( esc_html__( 'Nonce Verification Failed.', 'wp-security-audit-log' ) );
|
2339 |
+
}
|
2340 |
+
}
|
2341 |
+
|
2342 |
+
/**
|
2343 |
+
* Method: Purge plugin occurrence & meta tables.
|
2344 |
+
*/
|
2345 |
+
public function purge_activity() {
|
2346 |
+
// Die if user does not have permission to change settings.
|
2347 |
+
if ( ! $this->_plugin->settings->CurrentUserCan( 'view' ) ) {
|
2348 |
+
die( esc_html__( 'Access Denied.', 'wp-security-audit-log' ) );
|
2349 |
+
}
|
2350 |
+
|
2351 |
+
// Verify nonce.
|
2352 |
+
$nonce = filter_input( INPUT_POST, 'nonce', FILTER_SANITIZE_STRING );
|
2353 |
+
if ( ! empty( $nonce ) && wp_verify_nonce( $nonce, 'wsal-purge-activity' ) ) {
|
2354 |
+
$connector = WpSecurityAuditLog::getConnector();
|
2355 |
+
$result = $connector->purge_activity();
|
2356 |
+
|
2357 |
+
if ( $result ) {
|
2358 |
+
die( esc_html__( 'Tables has been reset.', 'wp-security-audit-log' ) );
|
2359 |
+
} else {
|
2360 |
+
die( esc_html__( 'Reset query failed.', 'wp-security-audit-log' ) );
|
2361 |
+
}
|
2362 |
+
} else {
|
2363 |
+
die( esc_html__( 'Nonce Verification Failed.', 'wp-security-audit-log' ) );
|
2364 |
+
}
|
2365 |
+
}
|
2366 |
}
|
classes/Views/SetupWizard.php
ADDED
@@ -0,0 +1,765 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* View: WSAL Setup
|
4 |
+
*
|
5 |
+
* WSAL setup class file.
|
6 |
+
*
|
7 |
+
* @since 3.2.3
|
8 |
+
* @package Wsal
|
9 |
+
*/
|
10 |
+
|
11 |
+
// Exit if accessed directly.
|
12 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
13 |
+
exit;
|
14 |
+
}
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Class: WSAL Setup Wizard.
|
18 |
+
*
|
19 |
+
* WSAL setup wizard class which manages the functionality
|
20 |
+
* related to setup.
|
21 |
+
*/
|
22 |
+
final class WSAL_Views_SetupWizard {
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Instance of WpSecurityAuditLog
|
26 |
+
*
|
27 |
+
* @var WpSecurityAuditLog
|
28 |
+
*/
|
29 |
+
private $wsal;
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Wizard Steps
|
33 |
+
*
|
34 |
+
* @var array
|
35 |
+
*/
|
36 |
+
private $wizard_steps;
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Current Step
|
40 |
+
*
|
41 |
+
* @var string
|
42 |
+
*/
|
43 |
+
private $current_step;
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Method: Constructor.
|
47 |
+
*
|
48 |
+
* @param WpSecurityAuditLog $wsal – Instance of main plugin.
|
49 |
+
*/
|
50 |
+
public function __construct( WpSecurityAuditLog &$wsal ) {
|
51 |
+
$this->wsal = $wsal;
|
52 |
+
|
53 |
+
add_action( 'admin_menu', array( $this, 'admin_menus' ), 10 );
|
54 |
+
add_action( 'admin_init', array( $this, 'setup_page' ), 10 );
|
55 |
+
add_action( 'wp_ajax_setup_check_security_token', array( $this, 'setup_check_security_token' ) );
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Ajax handler to verify setting token.
|
60 |
+
*/
|
61 |
+
public function setup_check_security_token() {
|
62 |
+
if ( ! $this->wsal->settings->CurrentUserCan( 'view' ) ) {
|
63 |
+
echo wp_json_encode(
|
64 |
+
array(
|
65 |
+
'success' => false,
|
66 |
+
'message' => esc_html__( 'Access Denied.', 'wp-security-audit-log' ),
|
67 |
+
)
|
68 |
+
);
|
69 |
+
die();
|
70 |
+
}
|
71 |
+
|
72 |
+
//@codingStandardsIgnoreStart
|
73 |
+
$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( $_POST['nonce'] ) : false;
|
74 |
+
$token = isset( $_POST['token'] ) ? sanitize_text_field( $_POST['token'] ) : false;
|
75 |
+
//@codingStandardsIgnoreEnd
|
76 |
+
|
77 |
+
if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'wsal-verify-wizard-page' ) ) {
|
78 |
+
echo wp_json_encode(
|
79 |
+
array(
|
80 |
+
'success' => false,
|
81 |
+
'message' => esc_html__( 'Nonce verification failed.', 'wp-security-audit-log' ),
|
82 |
+
)
|
83 |
+
);
|
84 |
+
die();
|
85 |
+
}
|
86 |
+
|
87 |
+
if ( empty( $token ) ) {
|
88 |
+
echo wp_json_encode(
|
89 |
+
array(
|
90 |
+
'success' => false,
|
91 |
+
'message' => esc_html__( 'Invalid input.', 'wp-security-audit-log' ),
|
92 |
+
)
|
93 |
+
);
|
94 |
+
die();
|
95 |
+
}
|
96 |
+
|
97 |
+
echo wp_json_encode(
|
98 |
+
array(
|
99 |
+
'success' => true,
|
100 |
+
'token' => $token,
|
101 |
+
'tokenType' => esc_html( $this->get_token_type( $token ) ),
|
102 |
+
)
|
103 |
+
);
|
104 |
+
die();
|
105 |
+
}
|
106 |
+
|
107 |
+
/**
|
108 |
+
* Add setup admin page.
|
109 |
+
*/
|
110 |
+
public function admin_menus() {
|
111 |
+
add_dashboard_page( '', '', 'manage_options', 'wsal-setup', '' );
|
112 |
+
}
|
113 |
+
|
114 |
+
/**
|
115 |
+
* Setup Page Start.
|
116 |
+
*/
|
117 |
+
public function setup_page() {
|
118 |
+
// Get page argument from $_GET array.
|
119 |
+
$page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
|
120 |
+
if ( empty( $page ) || 'wsal-setup' !== $page ) {
|
121 |
+
return;
|
122 |
+
}
|
123 |
+
|
124 |
+
/**
|
125 |
+
* Wizard Steps.
|
126 |
+
*/
|
127 |
+
$wizard_steps = array(
|
128 |
+
'welcome' => array(
|
129 |
+
'name' => __( 'Welcome', 'wp-security-audit-log' ),
|
130 |
+
'content' => array( $this, 'wsal_step_welcome' ),
|
131 |
+
),
|
132 |
+
'log_details' => array(
|
133 |
+
'name' => __( 'Log Details', 'wp-security-audit-log' ),
|
134 |
+
'content' => array( $this, 'wsal_step_log_details' ),
|
135 |
+
'save' => array( $this, 'wsal_step_log_details_save' ),
|
136 |
+
),
|
137 |
+
'log_retention' => array(
|
138 |
+
'name' => __( 'Log Retention', 'wp-security-audit-log' ),
|
139 |
+
'content' => array( $this, 'wsal_step_log_retention' ),
|
140 |
+
'save' => array( $this, 'wsal_step_log_retention_save' ),
|
141 |
+
),
|
142 |
+
'access' => array(
|
143 |
+
'name' => __( 'Access', 'wp-security-audit-log' ),
|
144 |
+
'content' => array( $this, 'wsal_step_access' ),
|
145 |
+
'save' => array( $this, 'wsal_step_access_save' ),
|
146 |
+
),
|
147 |
+
'exclude_object' => array(
|
148 |
+
'name' => __( 'Exclude Objects', 'wp-security-audit-log' ),
|
149 |
+
'content' => array( $this, 'wsal_step_exclude_object' ),
|
150 |
+
'save' => array( $this, 'wsal_step_exclude_object_save' ),
|
151 |
+
),
|
152 |
+
'finish' => array(
|
153 |
+
'name' => __( 'Finish', 'wp-security-audit-log' ),
|
154 |
+
'content' => array( $this, 'wsal_step_finish' ),
|
155 |
+
'save' => array( $this, 'wsal_step_finish_save' ),
|
156 |
+
),
|
157 |
+
);
|
158 |
+
|
159 |
+
/**
|
160 |
+
* Filter: `Wizard Default Steps`
|
161 |
+
*
|
162 |
+
* WSAL filter to filter wizard steps before they are displayed.
|
163 |
+
*
|
164 |
+
* @param array $wizard_steps – Wizard Steps.
|
165 |
+
*/
|
166 |
+
$this->wizard_steps = apply_filters( 'wsal_wizard_default_steps', $wizard_steps );
|
167 |
+
|
168 |
+
// Set current step.
|
169 |
+
$current_step = filter_input( INPUT_GET, 'current-step', FILTER_SANITIZE_STRING );
|
170 |
+
$this->current_step = ! empty( $current_step ) ? $current_step : current( array_keys( $this->wizard_steps ) );
|
171 |
+
|
172 |
+
/**
|
173 |
+
* Enqueue Styles.
|
174 |
+
*/
|
175 |
+
wp_enqueue_style(
|
176 |
+
'wsal-wizard-css',
|
177 |
+
$this->wsal->GetBaseUrl() . '/css/dist/wsal-wizard.build.css',
|
178 |
+
array( 'dashicons', 'install', 'forms' ),
|
179 |
+
filemtime( $this->wsal->GetBaseDir() . 'css/dist/wsal-wizard.build.css' )
|
180 |
+
);
|
181 |
+
|
182 |
+
/**
|
183 |
+
* Enqueue Scripts.
|
184 |
+
*/
|
185 |
+
wp_register_script(
|
186 |
+
'wsal-wizard-js',
|
187 |
+
$this->wsal->GetBaseUrl() . '/js/dist/wsal-wizard.min.js',
|
188 |
+
array(),
|
189 |
+
filemtime( $this->wsal->GetBaseDir() . 'js/dist/wsal-wizard.min.js' ),
|
190 |
+
false
|
191 |
+
);
|
192 |
+
|
193 |
+
// Data array.
|
194 |
+
$data_array = array(
|
195 |
+
'ajaxURL' => admin_url( 'admin-ajax.php' ),
|
196 |
+
'nonce' => wp_create_nonce( 'wsal-verify-wizard-page' ),
|
197 |
+
'usersError' => esc_html__( 'Specified token in not a user.', 'wp-security-audit-log' ),
|
198 |
+
'rolesError' => esc_html__( 'Specified token in not a role.', 'wp-security-audit-log' ),
|
199 |
+
'ipError' => esc_html__( 'Specified token in not an IP.', 'wp-security-audit-log' ),
|
200 |
+
);
|
201 |
+
wp_localize_script( 'wsal-wizard-js', 'wsalData', $data_array );
|
202 |
+
|
203 |
+
/**
|
204 |
+
* Save Wizard Settings.
|
205 |
+
*/
|
206 |
+
$save_step = filter_input( INPUT_POST, 'save_step', FILTER_SANITIZE_STRING );
|
207 |
+
if ( ! empty( $save_step ) && ! empty( $this->wizard_steps[ $this->current_step ]['save'] ) ) {
|
208 |
+
call_user_func( $this->wizard_steps[ $this->current_step ]['save'] );
|
209 |
+
}
|
210 |
+
|
211 |
+
ob_start();
|
212 |
+
$this->setup_page_header();
|
213 |
+
$this->setup_page_steps();
|
214 |
+
$this->setup_page_content();
|
215 |
+
$this->setup_page_footer();
|
216 |
+
exit;
|
217 |
+
}
|
218 |
+
|
219 |
+
/**
|
220 |
+
* Setup Page Header.
|
221 |
+
*/
|
222 |
+
private function setup_page_header() {
|
223 |
+
?>
|
224 |
+
<!DOCTYPE html>
|
225 |
+
<html <?php language_attributes(); ?>>
|
226 |
+
<head>
|
227 |
+
<meta name="viewport" content="width=device-width" />
|
228 |
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
229 |
+
<title><?php esc_html_e( 'WP Security Audit Log › Setup Wizard', 'wp-security-audit-log' ); ?></title>
|
230 |
+
<?php wp_print_scripts( 'wsal-wizard-js' ); ?>
|
231 |
+
<?php do_action( 'admin_print_styles' ); ?>
|
232 |
+
<?php do_action( 'admin_head' ); ?>
|
233 |
+
</head>
|
234 |
+
<body class="wsal-setup wp-core-ui">
|
235 |
+
<h1 id="wsal-logo"><a href="https://wpsecurityauditlog.com/" target="_blank"><img src="<?php echo esc_url( $this->wsal->GetBaseUrl() ); ?>/img/wsal-logo-full.png" alt="WP Security Audit Log" /></a></h1>
|
236 |
+
<?php
|
237 |
+
}
|
238 |
+
|
239 |
+
/**
|
240 |
+
* Setup Page Footer.
|
241 |
+
*/
|
242 |
+
private function setup_page_footer() {
|
243 |
+
?>
|
244 |
+
<div class="wsal-setup-footer">
|
245 |
+
<?php if ( 'welcome' !== $this->current_step && 'finish' !== $this->current_step ) : // Don't show the link on the first & last step. ?>
|
246 |
+
<a href="<?php echo esc_url( admin_url() ); ?>"><?php esc_html_e( 'Close Wizard', 'wp-security-audit-log' ); ?></a>
|
247 |
+
<?php endif; ?>
|
248 |
+
</div>
|
249 |
+
</body>
|
250 |
+
</html>
|
251 |
+
<?php
|
252 |
+
}
|
253 |
+
|
254 |
+
/**
|
255 |
+
* Setup Page Steps.
|
256 |
+
*/
|
257 |
+
private function setup_page_steps() {
|
258 |
+
?>
|
259 |
+
<ul class="steps">
|
260 |
+
<?php
|
261 |
+
foreach ( $this->wizard_steps as $key => $step ) :
|
262 |
+
if ( $key === $this->current_step ) :
|
263 |
+
?>
|
264 |
+
<li class="is-active"><?php echo esc_html( $step['name'] ); ?></li>
|
265 |
+
<?php
|
266 |
+
else :
|
267 |
+
?>
|
268 |
+
<li><?php echo esc_html( $step['name'] ); ?></li>
|
269 |
+
<?php
|
270 |
+
endif;
|
271 |
+
endforeach;
|
272 |
+
?>
|
273 |
+
</ul>
|
274 |
+
<?php
|
275 |
+
}
|
276 |
+
|
277 |
+
/**
|
278 |
+
* Get Next Step URL.
|
279 |
+
*
|
280 |
+
* @return string
|
281 |
+
*/
|
282 |
+
private function get_next_step() {
|
283 |
+
// Get current step.
|
284 |
+
$current_step = $this->current_step;
|
285 |
+
|
286 |
+
// Array of step keys.
|
287 |
+
$keys = array_keys( $this->wizard_steps );
|
288 |
+
if ( end( $keys ) === $current_step ) { // If last step is active then return WP Admin URL.
|
289 |
+
return admin_url();
|
290 |
+
}
|
291 |
+
|
292 |
+
// Search for step index in step keys.
|
293 |
+
$step_index = array_search( $current_step, $keys, true );
|
294 |
+
if ( false === $step_index ) { // If index is not found then return empty string.
|
295 |
+
return '';
|
296 |
+
}
|
297 |
+
|
298 |
+
// Return next step.
|
299 |
+
return add_query_arg( 'current-step', $keys[ $step_index + 1 ] );
|
300 |
+
}
|
301 |
+
|
302 |
+
/**
|
303 |
+
* Setup Page Content.
|
304 |
+
*/
|
305 |
+
private function setup_page_content() {
|
306 |
+
?>
|
307 |
+
<div class="wsal-setup-content">
|
308 |
+
<?php
|
309 |
+
if ( ! empty( $this->wizard_steps[ $this->current_step ]['content'] ) ) {
|
310 |
+
call_user_func( $this->wizard_steps[ $this->current_step ]['content'] );
|
311 |
+
}
|
312 |
+
?>
|
313 |
+
</div>
|
314 |
+
<?php
|
315 |
+
}
|
316 |
+
|
317 |
+
/**
|
318 |
+
* Step View: `Welcome`
|
319 |
+
*/
|
320 |
+
private function wsal_step_welcome() {
|
321 |
+
?>
|
322 |
+
<p><?php esc_html_e( 'Thank you for installing the WP Security Audit Log plugin.', 'wp-security-audit-log' ); ?></p>
|
323 |
+
<p><?php esc_html_e( 'This wizard will help you configure your WordPress activity log plugin and get you started quickly.', 'wp-security-audit-log' ); ?></p>
|
324 |
+
<p><?php esc_html_e( 'Anything that can be configured in this wizard can be changed at a later stage from the plugin settings. If you are an experienced user of this plugin you can exit this wizard and configure all the settings manually.', 'wp-security-audit-log' ); ?></p>
|
325 |
+
|
326 |
+
<div class="wsal-setup-actions">
|
327 |
+
<a class="button button-primary"
|
328 |
+
href="<?php echo esc_url( $this->get_next_step() ); ?>">
|
329 |
+
<?php esc_html_e( 'Start Configuring the Plugin', 'wp-security-audit-log' ); ?>
|
330 |
+
</a>
|
331 |
+
<a class="button button-secondary"
|
332 |
+
href="<?php echo esc_url( admin_url() ); ?>">
|
333 |
+
<?php esc_html_e( 'Exit Wizard', 'wp-security-audit-log' ); ?>
|
334 |
+
</a>
|
335 |
+
</div>
|
336 |
+
<?php
|
337 |
+
}
|
338 |
+
|
339 |
+
/**
|
340 |
+
* Step View: `Log Details`
|
341 |
+
*/
|
342 |
+
private function wsal_step_log_details() {
|
343 |
+
?>
|
344 |
+
<form method="post" class="wsal-setup-form">
|
345 |
+
<?php wp_nonce_field( 'wsal-step-log-details' ); ?>
|
346 |
+
<h4>
|
347 |
+
<?php esc_html_e( 'Please select the level of detail for your WordPress activity logs:', 'wp-security-audit-log' ); ?>
|
348 |
+
</h4>
|
349 |
+
<fieldset>
|
350 |
+
<label for="basic">
|
351 |
+
<input id="basic" name="wsal-details-level" type="radio" value="basic">
|
352 |
+
<?php esc_html_e( 'Basic (I want a high level overview and I am not interested in the detail)', 'wp-security-audit-log' ); ?>
|
353 |
+
</label>
|
354 |
+
<br />
|
355 |
+
<label for="geek">
|
356 |
+
<input id="geek" name="wsal-details-level" type="radio" value="geek" checked>
|
357 |
+
<?php esc_html_e( 'Geek (I want to know everything that is happening on my WordPress)', 'wp-security-audit-log' ); ?>
|
358 |
+
</label>
|
359 |
+
<p class="description">
|
360 |
+
<?php esc_html_e( 'Note: You can change the WordPress logging level from the plugin’s settings anytime.', 'wp-security-audit-log' ); ?>
|
361 |
+
</p>
|
362 |
+
</fieldset>
|
363 |
+
|
364 |
+
<div class="wsal-setup-actions">
|
365 |
+
<button class="button button-primary"
|
366 |
+
type="submit"
|
367 |
+
name="save_step"
|
368 |
+
value="<?php esc_attr_e( 'Next', 'wp-security-audit-log' ); ?>">
|
369 |
+
<?php esc_html_e( 'Next', 'wp-security-audit-log' ); ?>
|
370 |
+
</button>
|
371 |
+
</div>
|
372 |
+
</form>
|
373 |
+
<?php
|
374 |
+
}
|
375 |
+
|
376 |
+
/**
|
377 |
+
* Step Save: `Log Details`
|
378 |
+
*/
|
379 |
+
private function wsal_step_log_details_save() {
|
380 |
+
// Check nonce.
|
381 |
+
check_admin_referer( 'wsal-step-log-details' );
|
382 |
+
|
383 |
+
// Save Log Details Step setting.
|
384 |
+
// @codingStandardsIgnoreStart
|
385 |
+
$log_details = isset( $_POST['wsal-details-level'] ) ? sanitize_text_field( $_POST['wsal-details-level'] ) : false;
|
386 |
+
// @codingStandardsIgnoreEnd
|
387 |
+
|
388 |
+
// Save log details option.
|
389 |
+
$this->wsal->SetGlobalOption( 'details-level', $log_details );
|
390 |
+
if ( ! empty( $log_details ) && 'basic' === $log_details ) {
|
391 |
+
$this->wsal->settings->set_basic_mode();
|
392 |
+
} elseif ( ! empty( $log_details ) && 'geek' === $log_details ) {
|
393 |
+
$this->wsal->settings->set_geek_mode();
|
394 |
+
}
|
395 |
+
|
396 |
+
wp_safe_redirect( esc_url_raw( $this->get_next_step() ) );
|
397 |
+
exit();
|
398 |
+
}
|
399 |
+
|
400 |
+
/**
|
401 |
+
* Step View: `Log Retention`
|
402 |
+
*/
|
403 |
+
private function wsal_step_log_retention() {
|
404 |
+
?>
|
405 |
+
<form method="post" class="wsal-setup-form">
|
406 |
+
<?php wp_nonce_field( 'wsal-step-log-retention' ); ?>
|
407 |
+
<h4>
|
408 |
+
<?php esc_html_e( 'How long do you want to keep the data in the WordPress activity Log?', 'wp-security-audit-log' ); ?>
|
409 |
+
</h4>
|
410 |
+
<fieldset>
|
411 |
+
<label for="6">
|
412 |
+
<input id="6" name="wsal-pruning-limit" type="radio" value="6" checked />
|
413 |
+
<?php esc_html_e( '6 months (data older than 6 months will be deleted)', 'wp-security-audit-log' ); ?>
|
414 |
+
</label>
|
415 |
+
<br />
|
416 |
+
<label for="12">
|
417 |
+
<input id="12" name="wsal-pruning-limit" type="radio" value="12" />
|
418 |
+
<?php esc_html_e( '12 months (data older than 12 months will be deleted)', 'wp-security-audit-log' ); ?>
|
419 |
+
</label>
|
420 |
+
<br />
|
421 |
+
<label for="none">
|
422 |
+
<input id="none" name="wsal-pruning-limit" type="radio" value="none" />
|
423 |
+
<?php esc_html_e( 'Keep all data.', 'wp-security-audit-log' ); ?>
|
424 |
+
</label>
|
425 |
+
<p class="description">
|
426 |
+
<?php esc_html_e( 'Note: You can change the WordPress activity log retention settings at any time from the plugin settings later on.', 'wp-security-audit-log' ); ?>
|
427 |
+
</p>
|
428 |
+
</fieldset>
|
429 |
+
|
430 |
+
<div class="wsal-setup-actions">
|
431 |
+
<button class="button button-primary"
|
432 |
+
type="submit"
|
433 |
+
name="save_step"
|
434 |
+
value="<?php esc_attr_e( 'Next', 'wp-security-audit-log' ); ?>">
|
435 |
+
<?php esc_html_e( 'Next', 'wp-security-audit-log' ); ?>
|
436 |
+
</button>
|
437 |
+
</div>
|
438 |
+
</form>
|
439 |
+
|
440 |
+
<p class="description">
|
441 |
+
<em>
|
442 |
+
<?php
|
443 |
+
// Step help text.
|
444 |
+
$step_help = __( 'The plugin stores the data in the WordPress database in a very efficient way, though the more data you keep the more hard disk space it will consume. If you need need to retain a lot of data we would recommend you to <a href="https://www.wpsecurityauditlog.com/premium-features/" target="_blank">upgrade to Premium</a> and use the Database tools to store the WordPress activity log in an external database.', 'wp-security-audit-log' );
|
445 |
+
|
446 |
+
echo wp_kses( $step_help, $this->wsal->allowed_html_tags );
|
447 |
+
?>
|
448 |
+
</em>
|
449 |
+
</p>
|
450 |
+
<?php
|
451 |
+
}
|
452 |
+
|
453 |
+
/**
|
454 |
+
* Step Save: `Log Retention`
|
455 |
+
*/
|
456 |
+
private function wsal_step_log_retention_save() {
|
457 |
+
// Verify nonce.
|
458 |
+
check_admin_referer( 'wsal-step-log-retention' );
|
459 |
+
|
460 |
+
// Save Log Retention Step setting.
|
461 |
+
// @codingStandardsIgnoreStart
|
462 |
+
$pruning_limit = isset( $_POST['wsal-pruning-limit'] ) ? sanitize_text_field( $_POST['wsal-pruning-limit'] ) : false;
|
463 |
+
// @codingStandardsIgnoreEnd
|
464 |
+
|
465 |
+
// Save log retention setting.
|
466 |
+
if ( ! empty( $pruning_limit ) ) {
|
467 |
+
switch ( $pruning_limit ) {
|
468 |
+
case '6':
|
469 |
+
// 6 months.
|
470 |
+
$this->wsal->SetGlobalOption( 'pruning-date-e', true );
|
471 |
+
$this->wsal->SetGlobalOption( 'pruning-date', $pruning_limit . ' months' );
|
472 |
+
break;
|
473 |
+
|
474 |
+
case '12':
|
475 |
+
// 12 months.
|
476 |
+
$this->wsal->SetGlobalOption( 'pruning-date-e', true );
|
477 |
+
$this->wsal->SetGlobalOption( 'pruning-date', $pruning_limit . ' months' );
|
478 |
+
break;
|
479 |
+
|
480 |
+
case 'none':
|
481 |
+
// None.
|
482 |
+
$this->wsal->SetGlobalOption( 'pruning-date-e', false );
|
483 |
+
break;
|
484 |
+
|
485 |
+
default:
|
486 |
+
break;
|
487 |
+
}
|
488 |
+
}
|
489 |
+
|
490 |
+
wp_safe_redirect( esc_url_raw( $this->get_next_step() ) );
|
491 |
+
exit();
|
492 |
+
}
|
493 |
+
|
494 |
+
/**
|
495 |
+
* Get Token Type.
|
496 |
+
*
|
497 |
+
* @param string $token - Token type.
|
498 |
+
*/
|
499 |
+
protected function get_token_type( $token ) {
|
500 |
+
return $this->wsal->settings->get_token_type( $token );
|
501 |
+
}
|
502 |
+
|
503 |
+
/**
|
504 |
+
* Step View: `Access`
|
505 |
+
*/
|
506 |
+
private function wsal_step_access() {
|
507 |
+
?>
|
508 |
+
<form method="post" class="wsal-setup-form">
|
509 |
+
<?php wp_nonce_field( 'wsal-step-access' ); ?>
|
510 |
+
<h4>
|
511 |
+
<?php esc_html_e( 'By default only the users with administrator role can access the WordPress activity log. Would you like to allow any other user or users with a role to access the WordPress activity log?', 'wp-security-audit-log' ); ?>
|
512 |
+
</h4>
|
513 |
+
<fieldset>
|
514 |
+
<label for="no">
|
515 |
+
<input id="no" name="wsal-access" type="radio" value="no" checked />
|
516 |
+
<?php esc_html_e( 'No', 'wp-security-audit-log' ); ?>
|
517 |
+
</label>
|
518 |
+
<br />
|
519 |
+
<label for="yes">
|
520 |
+
<input id="yes" name="wsal-access" type="radio" value="yes" />
|
521 |
+
<?php esc_html_e( 'Yes', 'wp-security-audit-log' ); ?>
|
522 |
+
</label>
|
523 |
+
</fieldset>
|
524 |
+
|
525 |
+
<fieldset>
|
526 |
+
<label for="editor-users-box">
|
527 |
+
<span><?php esc_html_e( 'Usernames: ', 'wp-security-audit-log' ); ?></span>
|
528 |
+
<input id="editor-users-box" class="editor-query-box" name="editor-users-box" type="text" />
|
529 |
+
<a href="javascript:;" class="button button-primary" id="editor-users-add">
|
530 |
+
<?php esc_html_e( 'ADD', 'wp-security-audit-log' ); ?>
|
531 |
+
</a>
|
532 |
+
</label>
|
533 |
+
<br />
|
534 |
+
<label for="editor-roles-box">
|
535 |
+
<span><?php esc_html_e( 'Roles: ', 'wp-security-audit-log' ); ?></span>
|
536 |
+
<input id="editor-roles-box" class="editor-query-box" name="editor-roles-box" type="text" />
|
537 |
+
<a href="javascript:;" class="button button-primary" id="editor-roles-add">
|
538 |
+
<?php esc_html_e( 'ADD', 'wp-security-audit-log' ); ?>
|
539 |
+
</a>
|
540 |
+
</label>
|
541 |
+
<br />
|
542 |
+
<div id="editor-list">
|
543 |
+
<?php foreach ( $this->wsal->settings->GetAllowedPluginEditors() as $item ) : ?>
|
544 |
+
<span class="sectoken-<?php echo esc_attr( $this->get_token_type( $item ) ); ?>">
|
545 |
+
<input type="hidden" name="editors[]" value="<?php echo esc_attr( $item ); ?>"/>
|
546 |
+
<?php echo esc_html( $item ); ?>
|
547 |
+
<?php if ( wp_get_current_user()->user_login !== $item ) { ?>
|
548 |
+
<a href="javascript:;" title="Remove">×</a>
|
549 |
+
<?php } ?>
|
550 |
+
</span>
|
551 |
+
<?php endforeach; ?>
|
552 |
+
</div>
|
553 |
+
</fieldset>
|
554 |
+
|
555 |
+
<p class="description">
|
556 |
+
<?php esc_html_e( 'Note: you can change the WordPress activity log privileges settings at any time from the plugin settings.', 'wp-security-audit-log' ); ?>
|
557 |
+
</p>
|
558 |
+
|
559 |
+
<div class="wsal-setup-actions">
|
560 |
+
<button class="button button-primary"
|
561 |
+
type="submit"
|
562 |
+
name="save_step"
|
563 |
+
value="<?php esc_attr_e( 'Next', 'wp-security-audit-log' ); ?>">
|
564 |
+
<?php esc_html_e( 'Next', 'wp-security-audit-log' ); ?>
|
565 |
+
</button>
|
566 |
+
</div>
|
567 |
+
</form>
|
568 |
+
|
569 |
+
<p class="description">
|
570 |
+
<em><?php echo esc_html__( 'The WordPress activity log contains sensitive data such as who logged in, from where, when, and what they did.', 'wp-security-audit-log' ); ?></em>
|
571 |
+
</p>
|
572 |
+
<?php
|
573 |
+
}
|
574 |
+
|
575 |
+
/**
|
576 |
+
* Step Save: `Access`
|
577 |
+
*/
|
578 |
+
private function wsal_step_access_save() {
|
579 |
+
// Verify nonce.
|
580 |
+
check_admin_referer( 'wsal-step-access' );
|
581 |
+
|
582 |
+
// Get Access Step setting.
|
583 |
+
// @codingStandardsIgnoreStart
|
584 |
+
$wsal_access = isset( $_POST['wsal-access'] ) ? sanitize_text_field( $_POST['wsal-access'] ) : false;
|
585 |
+
$wsal_editors = isset( $_POST['editors'] ) ? array_map( 'sanitize_text_field', $_POST['editors'] ) : false;
|
586 |
+
// @codingStandardsIgnoreEnd
|
587 |
+
|
588 |
+
if ( ! empty( $wsal_access ) && 'yes' === $wsal_access ) {
|
589 |
+
$this->wsal->settings->SetAllowedPluginEditors( ! empty( $wsal_editors ) ? $wsal_editors : array() );
|
590 |
+
} elseif ( ! empty( $wsal_access ) && 'no' === $wsal_access ) {
|
591 |
+
$this->wsal->settings->SetAllowedPluginEditors( array() );
|
592 |
+
}
|
593 |
+
|
594 |
+
wp_safe_redirect( esc_url_raw( $this->get_next_step() ) );
|
595 |
+
exit();
|
596 |
+
}
|
597 |
+
|
598 |
+
/**
|
599 |
+
* Step View: `Exclude Objects`
|
600 |
+
*/
|
601 |
+
private function wsal_step_exclude_object() {
|
602 |
+
?>
|
603 |
+
<form method="post" class="wsal-setup-form">
|
604 |
+
<?php wp_nonce_field( 'wsal-step-exclude-objects' ); ?>
|
605 |
+
<p>
|
606 |
+
<?php esc_html_e( 'The plugin will keep a log of everything that happens on your WordPress website. If you would like to exclude a particular user, users with a role or an IP address from the log specify them below. If not just click the Next button.', 'wp-security-audit-log' ); ?>
|
607 |
+
</p>
|
608 |
+
|
609 |
+
<fieldset>
|
610 |
+
<label for="exuser-query-box">
|
611 |
+
<span><?php esc_html_e( 'Usernames: ', 'wp-security-audit-log' ); ?></span>
|
612 |
+
<input id="exuser-query-box" class="exuser-query-box" name="exuser-query-box" type="text" />
|
613 |
+
<a href="javascript:;" class="button button-primary" id="exuser-query-add">
|
614 |
+
<?php esc_html_e( 'ADD', 'wp-security-audit-log' ); ?>
|
615 |
+
</a>
|
616 |
+
</label>
|
617 |
+
<div id="exuser-list">
|
618 |
+
<?php foreach ( $this->wsal->settings->GetExcludedMonitoringUsers() as $item ) : ?>
|
619 |
+
<span class="sectoken-<?php echo esc_attr( $this->get_token_type( $item ) ); ?>">
|
620 |
+
<input type="hidden" name="exusers[]" value="<?php echo esc_attr( $item ); ?>"/>
|
621 |
+
<?php echo esc_html( $item ); ?>
|
622 |
+
<a href="javascript:;" title="Remove">×</a>
|
623 |
+
</span>
|
624 |
+
<?php endforeach; ?>
|
625 |
+
</div>
|
626 |
+
</fieldset>
|
627 |
+
|
628 |
+
<fieldset>
|
629 |
+
<label for="exrole-query-box">
|
630 |
+
<span><?php esc_html_e( 'Roles: ', 'wp-security-audit-log' ); ?></span>
|
631 |
+
<input id="exrole-query-box" class="exrole-query-box" name="exrole-query-box" type="text" />
|
632 |
+
<a href="javascript:;" class="button button-primary" id="exrole-query-add">
|
633 |
+
<?php esc_html_e( 'ADD', 'wp-security-audit-log' ); ?>
|
634 |
+
</a>
|
635 |
+
</label>
|
636 |
+
<div id="exrole-list">
|
637 |
+
<?php foreach ( $this->wsal->settings->GetExcludedMonitoringRoles() as $item ) : ?>
|
638 |
+
<span class="sectoken-<?php echo esc_attr( $this->get_token_type( $item ) ); ?>">
|
639 |
+
<input type="hidden" name="exroles[]" value="<?php echo esc_attr( $item ); ?>"/>
|
640 |
+
<?php echo esc_html( $item ); ?>
|
641 |
+
<a href="javascript:;" title="Remove">×</a>
|
642 |
+
</span>
|
643 |
+
<?php endforeach; ?>
|
644 |
+
</div>
|
645 |
+
</fieldset>
|
646 |
+
|
647 |
+
<fieldset>
|
648 |
+
<label for="ipaddr-query-box">
|
649 |
+
<span><?php esc_html_e( 'IP Address: ', 'wp-security-audit-log' ); ?></span>
|
650 |
+
<input id="ipaddr-query-box" class="ipaddr-query-box" name="ipaddr-query-box" type="text" />
|
651 |
+
<a href="javascript:;" class="button button-primary" id="ipaddr-query-add">
|
652 |
+
<?php esc_html_e( 'ADD', 'wp-security-audit-log' ); ?>
|
653 |
+
</a>
|
654 |
+
</label>
|
655 |
+
<div id="ipaddr-list">
|
656 |
+
<?php foreach ( $this->wsal->settings->GetExcludedMonitoringIP() as $item ) : ?>
|
657 |
+
<span class="sectoken-<?php echo esc_attr( $this->get_token_type( $item ) ); ?>">
|
658 |
+
<input type="hidden" name="ipaddrs[]" value="<?php echo esc_attr( $item ); ?>"/>
|
659 |
+
<?php echo esc_html( $item ); ?>
|
660 |
+
<a href="javascript:;" title="Remove">×</a>
|
661 |
+
</span>
|
662 |
+
<?php endforeach; ?>
|
663 |
+
</div>
|
664 |
+
</fieldset>
|
665 |
+
|
666 |
+
<p class="description">
|
667 |
+
<?php esc_html_e( 'Note: You can change these exclusions anytime from the plugin settings.', 'wp-security-audit-log' ); ?>
|
668 |
+
</p>
|
669 |
+
|
670 |
+
<div class="wsal-setup-actions">
|
671 |
+
<button class="button button-primary"
|
672 |
+
type="submit"
|
673 |
+
name="save_step"
|
674 |
+
value="<?php esc_attr_e( 'Next', 'wp-security-audit-log' ); ?>">
|
675 |
+
<?php esc_html_e( 'Next', 'wp-security-audit-log' ); ?>
|
676 |
+
</button>
|
677 |
+
</div>
|
678 |
+
</form>
|
679 |
+
|
680 |
+
<p class="description">
|
681 |
+
<em><?php echo esc_html__( 'The WordPress activity log contains sensitive data such as who logged in, from where, when and what they did.', 'wp-security-audit-log' ); ?></em>
|
682 |
+
</p>
|
683 |
+
<?php
|
684 |
+
}
|
685 |
+
|
686 |
+
/**
|
687 |
+
* Step Save: `Exclude Objects`
|
688 |
+
*/
|
689 |
+
private function wsal_step_exclude_object_save() {
|
690 |
+
// Verify nonce.
|
691 |
+
check_admin_referer( 'wsal-step-exclude-objects' );
|
692 |
+
|
693 |
+
// Get exclude objects step settings.
|
694 |
+
// @codingStandardsIgnoreStart
|
695 |
+
$wsal_exusers = isset( $_POST['exusers'] ) ? array_map( 'sanitize_text_field', $_POST['exusers'] ) : false;
|
696 |
+
$wsal_exroles = isset( $_POST['exroles'] ) ? array_map( 'sanitize_text_field', $_POST['exroles'] ) : false;
|
697 |
+
$wsal_ipaddrs = isset( $_POST['ipaddrs'] ) ? array_map( 'sanitize_text_field', $_POST['ipaddrs'] ) : false;
|
698 |
+
// @codingStandardsIgnoreEnd
|
699 |
+
|
700 |
+
// Save the settings.
|
701 |
+
$this->wsal->settings->SetExcludedMonitoringUsers( ! empty( $wsal_exusers ) ? $wsal_exusers : array() );
|
702 |
+
$this->wsal->settings->SetExcludedMonitoringRoles( ! empty( $wsal_exroles ) ? $wsal_exroles : array() );
|
703 |
+
$this->wsal->settings->SetExcludedMonitoringIP( ! empty( $wsal_ipaddrs ) ? $wsal_ipaddrs : array() );
|
704 |
+
|
705 |
+
wp_safe_redirect( esc_url_raw( $this->get_next_step() ) );
|
706 |
+
exit();
|
707 |
+
}
|
708 |
+
|
709 |
+
/**
|
710 |
+
* Step View: `Finish`
|
711 |
+
*/
|
712 |
+
private function wsal_step_finish() {
|
713 |
+
?>
|
714 |
+
<p><?php esc_html_e( 'Your plugin is all set and it is ready to start keeping a record of everything that is happening on your WordPress in a WordPress activity log.', 'wp-security-audit-log' ); ?></p>
|
715 |
+
<p><?php esc_html_e( 'Below are a few useful links you might need to refer to:', 'wp-security-audit-log' ); ?></p>
|
716 |
+
|
717 |
+
<ul>
|
718 |
+
<li>
|
719 |
+
<a href="https://www.wpsecurityauditlog.com/support-documentation/getting-started-wp-security-audit-log/" target="_blank">
|
720 |
+
<?php esc_html_e( 'Getting started with the WP Security Audit Log plugin', 'wp-security-audit-log' ); ?>
|
721 |
+
</a>
|
722 |
+
</li>
|
723 |
+
<li>
|
724 |
+
<a href="https://www.wpsecurityauditlog.com/support-documentation/" target="_blank">
|
725 |
+
<?php esc_html_e( 'Knowledge Base & Support Documents', 'wp-security-audit-log' ); ?>
|
726 |
+
</a>
|
727 |
+
</li>
|
728 |
+
<li>
|
729 |
+
<a href="https://www.wpsecurityauditlog.com/benefits-wordpress-activity-log/" target="_blank">
|
730 |
+
<?php esc_html_e( 'Benefits of keeping a WordPress activity log', 'wp-security-audit-log' ); ?>
|
731 |
+
</a>
|
732 |
+
</li>
|
733 |
+
</ul>
|
734 |
+
|
735 |
+
<p><?php echo wp_kses( __( 'We trust this plugin meets all your activity log requirements. Should you encounter any problems, have feature requests or would like to share some feedback, <a href="https://www.wpsecurityauditlog.com/contact/" target="_blank">please get in touch!</a>', 'wp-security-audit-log' ), $this->wsal->allowed_html_tags ); ?></p>
|
736 |
+
|
737 |
+
<form method="post" class="wsal-setup-form">
|
738 |
+
<?php wp_nonce_field( 'wsal-step-finish' ); ?>
|
739 |
+
<div class="wsal-setup-actions">
|
740 |
+
<button class="button button-primary"
|
741 |
+
type="submit"
|
742 |
+
name="save_step"
|
743 |
+
value="<?php esc_attr_e( 'Finish', 'wp-security-audit-log' ); ?>">
|
744 |
+
<?php esc_html_e( 'Finish', 'wp-security-audit-log' ); ?>
|
745 |
+
</button>
|
746 |
+
</div>
|
747 |
+
</form>
|
748 |
+
<?php
|
749 |
+
}
|
750 |
+
|
751 |
+
/**
|
752 |
+
* Step Save: `Finish`
|
753 |
+
*/
|
754 |
+
private function wsal_step_finish_save() {
|
755 |
+
// Verify nonce.
|
756 |
+
check_admin_referer( 'wsal-step-finish' );
|
757 |
+
|
758 |
+
// Mark the finish of the setup.
|
759 |
+
$this->wsal->SetGlobalOption( 'wsal-setup-complete', 'yes' );
|
760 |
+
|
761 |
+
wp_safe_redirect( esc_url_raw( $this->get_next_step() ) );
|
762 |
+
exit();
|
763 |
+
}
|
764 |
+
}
|
765 |
+
|
classes/Views/ToggleAlerts.php
CHANGED
@@ -69,7 +69,7 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
|
|
69 |
}
|
70 |
|
71 |
$alert = new WSAL_Alert(); // IDE type hinting.
|
72 |
-
$grouped_alerts = $this->_plugin->alerts->GetCategorizedAlerts();
|
73 |
$safe_names = array_map( array( $this, 'GetSafeCatgName' ), array_keys( $grouped_alerts ) );
|
74 |
$safe_names = array_combine( array_keys( $grouped_alerts ), $safe_names );
|
75 |
|
@@ -131,7 +131,54 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
|
|
131 |
// Set the option.
|
132 |
$this->_plugin->SetGlobalOption( 'scan-file-changes', $file_change_toggle );
|
133 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
134 |
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
135 |
<h2 id="wsal-tabs" class="nav-tab-wrapper">
|
136 |
<?php foreach ( $safe_names as $name => $safe ) : ?>
|
137 |
<a href="#tab-<?php echo esc_attr( $safe ); ?>" class="nav-tab"><?php echo esc_html( $name ); ?></a>
|
@@ -227,7 +274,7 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
|
|
227 |
<tr>
|
228 |
<th width="48"><input type="checkbox" <?php checked( $allactive ); ?> <?php echo esc_attr( $disabled ); ?> /></th>
|
229 |
<th width="80"><?php esc_html_e( 'Code', 'wp-security-audit-log' ); ?></th>
|
230 |
-
<th width="100"><?php esc_html_e( '
|
231 |
<th><?php esc_html_e( 'Description', 'wp-security-audit-log' ); ?></th>
|
232 |
</tr>
|
233 |
</thead>
|
@@ -409,15 +456,19 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
|
|
409 |
// File integrity scan link.
|
410 |
if ( __( 'File Changes', 'wp-security-audit-log' ) === $subname ) :
|
411 |
$wsal_settings_page = '';
|
|
|
|
|
|
|
|
|
412 |
if ( ! is_multisite() ) {
|
413 |
-
$wsal_settings_page = add_query_arg(
|
414 |
} else {
|
415 |
-
$wsal_settings_page = add_query_arg(
|
416 |
}
|
417 |
?>
|
418 |
<tr>
|
419 |
<td colspan="4">
|
420 |
-
<a href="<?php echo esc_url( $wsal_settings_page
|
421 |
<?php esc_html_e( 'Configure the file integrity scan settings.', 'wp-security-audit-log' ); ?>
|
422 |
</a>
|
423 |
</td>
|
69 |
}
|
70 |
|
71 |
$alert = new WSAL_Alert(); // IDE type hinting.
|
72 |
+
$grouped_alerts = $this->_plugin->alerts->GetCategorizedAlerts( false );
|
73 |
$safe_names = array_map( array( $this, 'GetSafeCatgName' ), array_keys( $grouped_alerts ) );
|
74 |
$safe_names = array_combine( array_keys( $grouped_alerts ), $safe_names );
|
75 |
|
131 |
// Set the option.
|
132 |
$this->_plugin->SetGlobalOption( 'scan-file-changes', $file_change_toggle );
|
133 |
}
|
134 |
+
|
135 |
+
// Log level form submission.
|
136 |
+
$log_level = isset( $post_array['wsal-log-level'] ) ? sanitize_text_field( $post_array['wsal-log-level'] ) : false;
|
137 |
+
$log_level_nonce = isset( $post_array['wsal-log-level-nonce'] ) ? sanitize_text_field( $post_array['wsal-log-level-nonce'] ) : false;
|
138 |
+
|
139 |
+
if ( wp_verify_nonce( $log_level_nonce, 'wsal-log-level' ) ) {
|
140 |
+
$this->_plugin->SetGlobalOption( 'details-level', $log_level );
|
141 |
+
|
142 |
+
if ( 'basic' === $log_level ) {
|
143 |
+
$this->_plugin->settings->set_basic_mode();
|
144 |
+
} elseif ( 'geek' === $log_level ) {
|
145 |
+
$this->_plugin->settings->set_geek_mode();
|
146 |
+
}
|
147 |
+
}
|
148 |
+
|
149 |
+
$disabled_events = $this->_plugin->GetGlobalOption( 'disabled-alerts' ); // Get disabled events.
|
150 |
+
$disabled_events = explode( ',', $disabled_events );
|
151 |
+
$events_diff = array_diff( $disabled_events, $this->_plugin->settings->geek_alerts ); // Calculate the difference of events.
|
152 |
+
$events_diff = array_filter( $events_diff ); // Remove empty values.
|
153 |
+
$is_custom = ! empty( $events_diff ) ? true : false; // If difference is not empty then mode is custom.
|
154 |
+
$log_details = $this->_plugin->GetGlobalOption( 'details-level', false ); // Get log level option.
|
155 |
?>
|
156 |
+
<p>
|
157 |
+
<form method="post" id="wsal-alerts-level">
|
158 |
+
<?php wp_nonce_field( 'wsal-log-level', 'wsal-log-level-nonce' ); ?>
|
159 |
+
<fieldset>
|
160 |
+
<label for="wsal-log-level"><?php esc_html_e( 'Log Level: ', 'wp-security-audit-log' ); ?></label>
|
161 |
+
<select name="wsal-log-level" id="wsal-log-level" onchange="this.form.submit()">
|
162 |
+
<option value="basic"
|
163 |
+
<?php echo ( ! empty( $log_details ) && 'basic' === $log_details ) ? esc_attr( 'selected' ) : false; ?>
|
164 |
+
>
|
165 |
+
<?php esc_html_e( 'Basic', 'wp-security-audit-log' ); ?>
|
166 |
+
</option>
|
167 |
+
<option value="geek"
|
168 |
+
<?php echo ( ! empty( $log_details ) && 'geek' === $log_details ) ? esc_attr( 'selected' ) : false; ?>
|
169 |
+
>
|
170 |
+
<?php esc_html_e( 'Geek', 'wp-security-audit-log' ); ?>
|
171 |
+
</option>
|
172 |
+
<option value="custom" <?php echo ( $is_custom ) ? esc_attr( 'selected' ) : false; ?>>
|
173 |
+
<?php esc_html_e( 'Custom', 'wp-security-audit-log' ); ?>
|
174 |
+
</option>
|
175 |
+
</select>
|
176 |
+
<p class="description">
|
177 |
+
<?php echo wp_kses( __( 'Use the Log level drop down menu above to use one of our preset log levels. Alternatively you can enable or disable any of the individual events from the below tabs. Refer to <a href="https://www.wpsecurityauditlog.com/support-documentation/list-wordpress-audit-trail-alerts/" target="_blank">the complete list of WordPress activity log event IDs</a> for reference on all the events the plugin can keep a log of.', 'wp-security-audit-log' ), $this->_plugin->allowed_html_tags ); ?>
|
178 |
+
</p>
|
179 |
+
</fieldset>
|
180 |
+
</form>
|
181 |
+
</p>
|
182 |
<h2 id="wsal-tabs" class="nav-tab-wrapper">
|
183 |
<?php foreach ( $safe_names as $name => $safe ) : ?>
|
184 |
<a href="#tab-<?php echo esc_attr( $safe ); ?>" class="nav-tab"><?php echo esc_html( $name ); ?></a>
|
274 |
<tr>
|
275 |
<th width="48"><input type="checkbox" <?php checked( $allactive ); ?> <?php echo esc_attr( $disabled ); ?> /></th>
|
276 |
<th width="80"><?php esc_html_e( 'Code', 'wp-security-audit-log' ); ?></th>
|
277 |
+
<th width="100"><?php esc_html_e( 'Severity', 'wp-security-audit-log' ); ?></th>
|
278 |
<th><?php esc_html_e( 'Description', 'wp-security-audit-log' ); ?></th>
|
279 |
</tr>
|
280 |
</thead>
|
456 |
// File integrity scan link.
|
457 |
if ( __( 'File Changes', 'wp-security-audit-log' ) === $subname ) :
|
458 |
$wsal_settings_page = '';
|
459 |
+
$redirect_args = array(
|
460 |
+
'page' => 'wsal-settings',
|
461 |
+
'tab' => 'file-changes',
|
462 |
+
);
|
463 |
if ( ! is_multisite() ) {
|
464 |
+
$wsal_settings_page = add_query_arg( $redirect_args, admin_url( 'admin.php' ) );
|
465 |
} else {
|
466 |
+
$wsal_settings_page = add_query_arg( $redirect_args, network_admin_url( 'admin.php' ) );
|
467 |
}
|
468 |
?>
|
469 |
<tr>
|
470 |
<td colspan="4">
|
471 |
+
<a href="<?php echo esc_url( $wsal_settings_page ); ?>" class="wsal-tab-help">
|
472 |
<?php esc_html_e( 'Configure the file integrity scan settings.', 'wp-security-audit-log' ); ?>
|
473 |
</a>
|
474 |
</td>
|
css/auditlog.css
CHANGED
@@ -3,11 +3,10 @@
|
|
3 |
*
|
4 |
*/
|
5 |
|
6 |
-
.top .wsal-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
margin-left: 0;
|
11 |
}
|
12 |
|
13 |
.wsal-ipp,
|
@@ -303,5 +302,5 @@ div.wsal_notice__wrapper p {
|
|
303 |
}
|
304 |
|
305 |
.wp-list-table #type {
|
306 |
-
width:
|
307 |
}
|
3 |
*
|
4 |
*/
|
5 |
|
6 |
+
.top .wsal-ssa select {
|
7 |
+
margin: 0 3px 0 0;
|
8 |
+
vertical-align: top;
|
9 |
+
height: 30px;
|
|
|
10 |
}
|
11 |
|
12 |
.wsal-ipp,
|
302 |
}
|
303 |
|
304 |
.wp-list-table #type {
|
305 |
+
width: 92px;
|
306 |
}
|
css/dist/wsal-wizard.build.css
ADDED
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* WSAL Wizard Styles
|
3 |
+
*/
|
4 |
+
body {
|
5 |
+
margin: 65px auto 24px;
|
6 |
+
-webkit-box-shadow: none;
|
7 |
+
box-shadow: none;
|
8 |
+
background: #f1f1f1;
|
9 |
+
padding: 0; }
|
10 |
+
|
11 |
+
#wsal-logo {
|
12 |
+
border: 0;
|
13 |
+
margin: 0 0 24px;
|
14 |
+
padding: 0;
|
15 |
+
text-align: center; }
|
16 |
+
#wsal-logo img {
|
17 |
+
width: 400px; }
|
18 |
+
|
19 |
+
.steps {
|
20 |
+
display: -ms-flexbox;
|
21 |
+
display: flex;
|
22 |
+
list-style-type: none;
|
23 |
+
margin: 0;
|
24 |
+
padding: 0 0 25px;
|
25 |
+
text-align: center; }
|
26 |
+
.steps li {
|
27 |
+
-ms-flex: 1 0 auto;
|
28 |
+
flex: 1 0 auto;
|
29 |
+
font-weight: 700;
|
30 |
+
margin: 0 0 5px;
|
31 |
+
color: #b4b9be;
|
32 |
+
padding-bottom: 15px;
|
33 |
+
position: relative; }
|
34 |
+
.steps li.is-active {
|
35 |
+
color: #009344; }
|
36 |
+
.steps li.is-active::before {
|
37 |
+
border: 4px solid #009344;
|
38 |
+
background: #009344; }
|
39 |
+
.steps li::before {
|
40 |
+
content: '';
|
41 |
+
border: 4px solid #b4b9be;
|
42 |
+
border-radius: 100%;
|
43 |
+
width: 4px;
|
44 |
+
height: 4px;
|
45 |
+
position: absolute;
|
46 |
+
bottom: 0;
|
47 |
+
left: 50%;
|
48 |
+
margin-left: -6px;
|
49 |
+
margin-bottom: -8px;
|
50 |
+
background: #b4b9be; }
|
51 |
+
|
52 |
+
.wsal-setup-content {
|
53 |
+
-webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.13);
|
54 |
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.13);
|
55 |
+
padding: 2em;
|
56 |
+
margin: 0 0 20px;
|
57 |
+
background: #fff;
|
58 |
+
overflow: hidden;
|
59 |
+
zoom: 1;
|
60 |
+
text-align: left; }
|
61 |
+
.wsal-setup-content h4,
|
62 |
+
.wsal-setup-content fieldset {
|
63 |
+
line-height: 1.5; }
|
64 |
+
|
65 |
+
.wsal-setup-actions {
|
66 |
+
text-align: center; }
|
67 |
+
.wsal-setup-actions .button {
|
68 |
+
-webkit-box-shadow: none;
|
69 |
+
box-shadow: none;
|
70 |
+
font-size: 14px;
|
71 |
+
height: auto;
|
72 |
+
padding: 8px 20px;
|
73 |
+
min-width: 12em;
|
74 |
+
min-width: auto;
|
75 |
+
-webkit-transition: 0.1s all linear;
|
76 |
+
-o-transition: 0.1s all linear;
|
77 |
+
transition: 0.1s all linear; }
|
78 |
+
.wsal-setup-actions .button-primary {
|
79 |
+
background-color: #009344;
|
80 |
+
border-color: #009344;
|
81 |
+
-webkit-box-shadow: none;
|
82 |
+
box-shadow: none;
|
83 |
+
text-shadow: none;
|
84 |
+
margin: 0;
|
85 |
+
opacity: 1; }
|
86 |
+
.wsal-setup-actions .button-primary:hover, .wsal-setup-actions .button-primary:focus {
|
87 |
+
background: #00ad50;
|
88 |
+
border-color: #00ad50;
|
89 |
+
-webkit-box-shadow: none;
|
90 |
+
box-shadow: none;
|
91 |
+
color: #fff; }
|
92 |
+
|
93 |
+
.wsal-setup-footer {
|
94 |
+
text-align: center; }
|
95 |
+
.wsal-setup-footer a {
|
96 |
+
color: #009344;
|
97 |
+
font-size: 14px;
|
98 |
+
text-decoration: none; }
|
99 |
+
|
100 |
+
.wsal-setup-form label[for="editor-users-box"],
|
101 |
+
.wsal-setup-form label[for="editor-roles-box"],
|
102 |
+
.wsal-setup-form label[for="exuser-query-box"],
|
103 |
+
.wsal-setup-form label[for="exrole-query-box"],
|
104 |
+
.wsal-setup-form label[for="ipaddr-query-box"] {
|
105 |
+
display: inline-block;
|
106 |
+
margin: 5px 0; }
|
107 |
+
.wsal-setup-form label[for="editor-users-box"] span,
|
108 |
+
.wsal-setup-form label[for="editor-roles-box"] span,
|
109 |
+
.wsal-setup-form label[for="exuser-query-box"] span,
|
110 |
+
.wsal-setup-form label[for="exrole-query-box"] span,
|
111 |
+
.wsal-setup-form label[for="ipaddr-query-box"] span {
|
112 |
+
display: inline-block;
|
113 |
+
min-width: 100px; }
|
114 |
+
|
115 |
+
.sectoken-user,
|
116 |
+
.sectoken-role,
|
117 |
+
.sectoken-ip,
|
118 |
+
.sectoken-other {
|
119 |
+
display: inline-block;
|
120 |
+
border-width: 1px;
|
121 |
+
border-style: solid;
|
122 |
+
padding: 2px 4px;
|
123 |
+
margin: 2px 0 0 2px;
|
124 |
+
border-radius: 3px;
|
125 |
+
cursor: default;
|
126 |
+
line-height: 1.3;
|
127 |
+
font-size: 14px; }
|
128 |
+
.sectoken-user a,
|
129 |
+
.sectoken-role a,
|
130 |
+
.sectoken-ip a,
|
131 |
+
.sectoken-other a {
|
132 |
+
text-decoration: none;
|
133 |
+
font-size: 12px;
|
134 |
+
font-weight: bold;
|
135 |
+
color: #FFF;
|
136 |
+
margin-left: 2px;
|
137 |
+
background: #BBB;
|
138 |
+
border-radius: 25px;
|
139 |
+
height: 14px;
|
140 |
+
display: inline-block;
|
141 |
+
vertical-align: middle;
|
142 |
+
width: 14px;
|
143 |
+
text-align: center;
|
144 |
+
line-height: 12px; }
|
145 |
+
.sectoken-user a:hover,
|
146 |
+
.sectoken-role a:hover,
|
147 |
+
.sectoken-ip a:hover,
|
148 |
+
.sectoken-other a:hover {
|
149 |
+
background: #FB9; }
|
150 |
+
|
151 |
+
.sectoken-other {
|
152 |
+
display: table;
|
153 |
+
border-collapse: separate; }
|
154 |
+
|
155 |
+
.sectoken-role {
|
156 |
+
background: #EFE;
|
157 |
+
border-color: #5B5; }
|
158 |
+
|
159 |
+
.sectoken-user {
|
160 |
+
background: #EFF;
|
161 |
+
border-color: #5BE; }
|
162 |
+
|
163 |
+
.sectoken-ip {
|
164 |
+
background: #FFE;
|
165 |
+
border-color: #ED5; }
|
166 |
+
|
167 |
+
.sectoken-other {
|
168 |
+
background: #FFE;
|
169 |
+
border-color: #ED5; }
|
css/settings.css
CHANGED
@@ -1,5 +1,4 @@
|
|
1 |
#audit-log-settings {
|
2 |
-
padding-right: 256px;
|
3 |
position: relative;
|
4 |
}
|
5 |
|
@@ -23,6 +22,7 @@
|
|
23 |
.sectoken-role,
|
24 |
.sectoken-cpts,
|
25 |
.sectoken-urls,
|
|
|
26 |
.sectoken-other {
|
27 |
display: inline-block;
|
28 |
border-width: 1px;
|
@@ -41,6 +41,7 @@
|
|
41 |
.sectoken-role a,
|
42 |
.sectoken-cpts a,
|
43 |
.sectoken-urls a,
|
|
|
44 |
.sectoken-other a {
|
45 |
text-decoration: none;
|
46 |
font-size: 12px;
|
@@ -61,6 +62,7 @@
|
|
61 |
.sectoken-role a:hover,
|
62 |
.sectoken-cpts a:hover,
|
63 |
.sectoken-urls a:hover,
|
|
|
64 |
.sectoken-other a:hover {
|
65 |
background: #FB9;
|
66 |
}
|
@@ -69,14 +71,18 @@
|
|
69 |
.sectoken-role { background: #EFE; border-color: #5B5; }
|
70 |
.sectoken-cpts { background: #EFF; border-color: #5BE; }
|
71 |
.sectoken-urls { background: #EFF; border-color: #5BE; }
|
|
|
72 |
.sectoken-other { background: #FFE; border-color: #ED5; }
|
73 |
.sectoken-del { background: #FEE; border-color: #EBB; }
|
74 |
|
|
|
|
|
|
|
75 |
.wsal-tab {
|
76 |
margin-top: 0px;
|
77 |
}
|
78 |
.wsal-tab th {
|
79 |
-
padding-left: 20px;
|
80 |
}
|
81 |
.wsal-tab td {
|
82 |
padding-left: 20px;
|
@@ -91,6 +97,18 @@
|
|
91 |
.wsal-tab .error.hide {
|
92 |
display: none;
|
93 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
|
95 |
/*
|
96 |
* IOS button
|
@@ -188,10 +206,11 @@ a.disabled {
|
|
188 |
#wsal_files,
|
189 |
#wsal_files_types,
|
190 |
#wsal_dirs {
|
|
|
191 |
width: 250px;
|
192 |
height: 230px;
|
193 |
overflow-y: scroll;
|
194 |
-
border: 1px solid #
|
195 |
padding: 10px 5px;
|
196 |
margin-right: 10px;
|
197 |
}
|
1 |
#audit-log-settings {
|
|
|
2 |
position: relative;
|
3 |
}
|
4 |
|
22 |
.sectoken-role,
|
23 |
.sectoken-cpts,
|
24 |
.sectoken-urls,
|
25 |
+
.sectoken-ip,
|
26 |
.sectoken-other {
|
27 |
display: inline-block;
|
28 |
border-width: 1px;
|
41 |
.sectoken-role a,
|
42 |
.sectoken-cpts a,
|
43 |
.sectoken-urls a,
|
44 |
+
.sectoken-ip a,
|
45 |
.sectoken-other a {
|
46 |
text-decoration: none;
|
47 |
font-size: 12px;
|
62 |
.sectoken-role a:hover,
|
63 |
.sectoken-cpts a:hover,
|
64 |
.sectoken-urls a:hover,
|
65 |
+
.sectoken-ip a:hover,
|
66 |
.sectoken-other a:hover {
|
67 |
background: #FB9;
|
68 |
}
|
71 |
.sectoken-role { background: #EFE; border-color: #5B5; }
|
72 |
.sectoken-cpts { background: #EFF; border-color: #5BE; }
|
73 |
.sectoken-urls { background: #EFF; border-color: #5BE; }
|
74 |
+
.sectoken-ip { background: #FFE; border-color: #ED5; }
|
75 |
.sectoken-other { background: #FFE; border-color: #ED5; }
|
76 |
.sectoken-del { background: #FEE; border-color: #EBB; }
|
77 |
|
78 |
+
#wsal-tabs {
|
79 |
+
margin: 0 0 1.5em;
|
80 |
+
}
|
81 |
.wsal-tab {
|
82 |
margin-top: 0px;
|
83 |
}
|
84 |
.wsal-tab th {
|
85 |
+
/* padding-left: 20px; */
|
86 |
}
|
87 |
.wsal-tab td {
|
88 |
padding-left: 20px;
|
97 |
.wsal-tab .error.hide {
|
98 |
display: none;
|
99 |
}
|
100 |
+
.wsal-tab input[type=text],
|
101 |
+
.wsal-tab input[type=email] {
|
102 |
+
display: inline-block;
|
103 |
+
width: 350px;
|
104 |
+
padding: 5px;
|
105 |
+
margin: 0;
|
106 |
+
}
|
107 |
+
.wsal-tab input[type=button],
|
108 |
+
.wsal-tab button {
|
109 |
+
display: inline-block;
|
110 |
+
vertical-align: top;
|
111 |
+
}
|
112 |
|
113 |
/*
|
114 |
* IOS button
|
206 |
#wsal_files,
|
207 |
#wsal_files_types,
|
208 |
#wsal_dirs {
|
209 |
+
background: #fff;
|
210 |
width: 250px;
|
211 |
height: 230px;
|
212 |
overflow-y: scroll;
|
213 |
+
border: 1px solid #ddd;
|
214 |
padding: 10px 5px;
|
215 |
margin-right: 10px;
|
216 |
}
|
css/src/common.scss
ADDED
File without changes
|
css/src/wsal-wizard.scss
ADDED
@@ -0,0 +1,182 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* WSAL Wizard Styles
|
3 |
+
*/
|
4 |
+
|
5 |
+
$color-primary: #009344;
|
6 |
+
$color-secondary: #bdd63a;
|
7 |
+
$color-disable: #b4b9be;
|
8 |
+
|
9 |
+
body {
|
10 |
+
margin: 65px auto 24px;
|
11 |
+
-webkit-box-shadow: none;
|
12 |
+
box-shadow: none;
|
13 |
+
background: #f1f1f1;
|
14 |
+
padding: 0;
|
15 |
+
}
|
16 |
+
|
17 |
+
// Header logo.
|
18 |
+
#wsal-logo {
|
19 |
+
border: 0;
|
20 |
+
margin: 0 0 24px;
|
21 |
+
padding: 0;
|
22 |
+
text-align: center;
|
23 |
+
|
24 |
+
img {
|
25 |
+
width: 400px;
|
26 |
+
}
|
27 |
+
}
|
28 |
+
|
29 |
+
// Wizard steps.
|
30 |
+
.steps {
|
31 |
+
display: flex;
|
32 |
+
list-style-type: none;
|
33 |
+
margin: 0;
|
34 |
+
padding: 0 0 25px;
|
35 |
+
text-align: center;
|
36 |
+
|
37 |
+
li {
|
38 |
+
flex: 1 0 auto;
|
39 |
+
font-weight: 700;
|
40 |
+
margin: 0 0 5px;
|
41 |
+
color: $color-disable;
|
42 |
+
padding-bottom: 15px;
|
43 |
+
position: relative;
|
44 |
+
|
45 |
+
&.is-active {
|
46 |
+
color: $color-primary;
|
47 |
+
|
48 |
+
&::before {
|
49 |
+
border: 4px solid $color-primary;
|
50 |
+
background: $color-primary;
|
51 |
+
}
|
52 |
+
}
|
53 |
+
|
54 |
+
&::before {
|
55 |
+
content: '';
|
56 |
+
border: 4px solid $color-disable;
|
57 |
+
border-radius: 100%;
|
58 |
+
width: 4px;
|
59 |
+
height: 4px;
|
60 |
+
position: absolute;
|
61 |
+
bottom: 0;
|
62 |
+
left: 50%;
|
63 |
+
margin-left: -6px;
|
64 |
+
margin-bottom: -8px;
|
65 |
+
background: $color-disable;
|
66 |
+
}
|
67 |
+
}
|
68 |
+
}
|
69 |
+
|
70 |
+
// Wizard Content.
|
71 |
+
.wsal-setup-content {
|
72 |
+
box-shadow: 0 1px 3px rgba(0,0,0,.13);
|
73 |
+
padding: 2em;
|
74 |
+
margin: 0 0 20px;
|
75 |
+
background: #fff;
|
76 |
+
overflow: hidden;
|
77 |
+
zoom: 1;
|
78 |
+
text-align: left;
|
79 |
+
|
80 |
+
h4,
|
81 |
+
fieldset {
|
82 |
+
line-height: 1.5;
|
83 |
+
}
|
84 |
+
}
|
85 |
+
|
86 |
+
.wsal-setup-actions {
|
87 |
+
text-align: center;
|
88 |
+
|
89 |
+
.button {
|
90 |
+
box-shadow: none;
|
91 |
+
font-size: 14px;
|
92 |
+
height: auto;
|
93 |
+
padding: 8px 20px;
|
94 |
+
min-width: 12em;
|
95 |
+
min-width: auto;
|
96 |
+
transition: 0.1s all linear;
|
97 |
+
}
|
98 |
+
|
99 |
+
.button-primary {
|
100 |
+
background-color: $color-primary;
|
101 |
+
border-color: $color-primary;
|
102 |
+
box-shadow: none;
|
103 |
+
text-shadow: none;
|
104 |
+
margin: 0;
|
105 |
+
opacity: 1;
|
106 |
+
|
107 |
+
&:hover,
|
108 |
+
&:focus {
|
109 |
+
background: lighten($color: $color-primary, $amount: 5%);
|
110 |
+
border-color: lighten($color: $color-primary, $amount: 5%);
|
111 |
+
box-shadow: none;
|
112 |
+
color: #fff;
|
113 |
+
}
|
114 |
+
}
|
115 |
+
}
|
116 |
+
|
117 |
+
// Wizard footer.
|
118 |
+
.wsal-setup-footer {
|
119 |
+
text-align: center;
|
120 |
+
|
121 |
+
a {
|
122 |
+
color: $color-primary;
|
123 |
+
font-size: 14px;
|
124 |
+
text-decoration: none;
|
125 |
+
}
|
126 |
+
}
|
127 |
+
|
128 |
+
.wsal-setup-form {
|
129 |
+
label[for="editor-users-box"],
|
130 |
+
label[for="editor-roles-box"],
|
131 |
+
label[for="exuser-query-box"],
|
132 |
+
label[for="exrole-query-box"],
|
133 |
+
label[for="ipaddr-query-box"] {
|
134 |
+
display: inline-block;
|
135 |
+
margin: 5px 0;
|
136 |
+
|
137 |
+
span {
|
138 |
+
display: inline-block;
|
139 |
+
min-width: 100px;
|
140 |
+
}
|
141 |
+
}
|
142 |
+
}
|
143 |
+
|
144 |
+
.sectoken-user,
|
145 |
+
.sectoken-role,
|
146 |
+
.sectoken-ip,
|
147 |
+
.sectoken-other {
|
148 |
+
display: inline-block;
|
149 |
+
border-width: 1px;
|
150 |
+
border-style: solid;
|
151 |
+
padding: 2px 4px;
|
152 |
+
margin: 2px 0 0 2px;
|
153 |
+
border-radius: 3px;
|
154 |
+
cursor: default;
|
155 |
+
line-height: 1.3;
|
156 |
+
font-size: 14px;
|
157 |
+
|
158 |
+
a {
|
159 |
+
text-decoration: none;
|
160 |
+
font-size: 12px;
|
161 |
+
font-weight: bold;
|
162 |
+
color: #FFF;
|
163 |
+
margin-left: 2px;
|
164 |
+
background: #BBB;
|
165 |
+
border-radius: 25px;
|
166 |
+
height: 14px;
|
167 |
+
display: inline-block;
|
168 |
+
vertical-align: middle;
|
169 |
+
width: 14px;
|
170 |
+
text-align: center;
|
171 |
+
line-height: 12px;
|
172 |
+
|
173 |
+
&:hover {
|
174 |
+
background: #FB9;
|
175 |
+
}
|
176 |
+
}
|
177 |
+
}
|
178 |
+
.sectoken-other { display: table; border-collapse: separate; }
|
179 |
+
.sectoken-role { background: #EFE; border-color: #5B5; }
|
180 |
+
.sectoken-user { background: #EFF; border-color: #5BE; }
|
181 |
+
.sectoken-ip { background: #FFE; border-color: #ED5; }
|
182 |
+
.sectoken-other { background: #FFE; border-color: #ED5; }
|
defaults.php
CHANGED
@@ -129,6 +129,48 @@ function wsaldefaults_wsal_init( WpSecurityAuditLog $wsal ) {
|
|
129 |
// Create list of default alerts.
|
130 |
$wsal->alerts->RegisterGroup(
|
131 |
array(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
132 |
/**
|
133 |
* Section: Content & Comments
|
134 |
*/
|
@@ -273,9 +315,9 @@ function wsaldefaults_wsal_init( WpSecurityAuditLog $wsal ) {
|
|
273 |
),
|
274 |
|
275 |
/**
|
276 |
-
* Section: WordPress
|
277 |
*/
|
278 |
-
__( 'WordPress
|
279 |
/**
|
280 |
* Alerts: Database
|
281 |
*/
|
@@ -291,26 +333,6 @@ function wsaldefaults_wsal_init( WpSecurityAuditLog $wsal ) {
|
|
291 |
array( 5018, E_CRITICAL, __( 'Unknown component deleted tables', 'wp-security-audit-log' ), __( 'An unknown component deleted the following tables from the database: %TableNames%.', 'wp-security-audit-log' ) ),
|
292 |
),
|
293 |
|
294 |
-
/**
|
295 |
-
* Alerts: MultiSite
|
296 |
-
*/
|
297 |
-
__( 'MultiSite', 'wp-security-audit-log' ) => array(
|
298 |
-
array( 4008, E_CRITICAL, __( 'User granted Super Admin privileges', 'wp-security-audit-log' ), __( 'Granted Super Admin privileges to %TargetUsername%.', 'wp-security-audit-log' ) ),
|
299 |
-
array( 4009, E_CRITICAL, __( 'User revoked from Super Admin privileges', 'wp-security-audit-log' ), __( 'Revoked Super Admin privileges from %TargetUsername%.', 'wp-security-audit-log' ) ),
|
300 |
-
array( 4010, E_CRITICAL, __( 'Existing user added to a site', 'wp-security-audit-log' ), __( 'Added the existing user %TargetUsername% with %TargetUserRole% role to site %SiteName%.', 'wp-security-audit-log' ) ),
|
301 |
-
array( 4011, E_CRITICAL, __( 'User removed from site', 'wp-security-audit-log' ), __( 'Removed the user %TargetUsername% with role %TargetUserRole% from %SiteName% site.', 'wp-security-audit-log' ) ),
|
302 |
-
array( 4012, E_CRITICAL, __( 'New network user created', 'wp-security-audit-log' ), __( 'Created a new network user %NewUserData->Username%.', 'wp-security-audit-log' ) ),
|
303 |
-
array( 4013, E_CRITICAL, __( 'The forum role of a user was changed by another WordPress user', 'wp-security-audit-log' ), __( 'Change the forum role of the user %TargetUsername% from %OldRole% to %NewRole% by %UserChanger%.', 'wp-security-audit-log' ) ),
|
304 |
-
array( 7000, E_CRITICAL, __( 'New site added on the network', 'wp-security-audit-log' ), __( 'Added the site %SiteName% to the network.', 'wp-security-audit-log' ) ),
|
305 |
-
array( 7001, E_CRITICAL, __( 'Existing site archived', 'wp-security-audit-log' ), __( 'Archived the site %SiteName%.', 'wp-security-audit-log' ) ),
|
306 |
-
array( 7002, E_CRITICAL, __( 'Archived site has been unarchived', 'wp-security-audit-log' ), __( 'Unarchived the site %SiteName%.', 'wp-security-audit-log' ) ),
|
307 |
-
array( 7003, E_CRITICAL, __( 'Deactivated site has been activated', 'wp-security-audit-log' ), __( 'Activated the site %SiteName%.', 'wp-security-audit-log' ) ),
|
308 |
-
array( 7004, E_CRITICAL, __( 'Site has been deactivated', 'wp-security-audit-log' ), __( 'Deactivated the site %SiteName%.', 'wp-security-audit-log' ) ),
|
309 |
-
array( 7005, E_CRITICAL, __( 'Existing site deleted from network', 'wp-security-audit-log' ), __( 'Deleted the site %SiteName%.', 'wp-security-audit-log' ) ),
|
310 |
-
array( 5008, E_CRITICAL, __( 'Activated theme on network', 'wp-security-audit-log' ), __( 'Network activated the theme %Theme->Name% installed in %Theme->get_template_directory%.', 'wp-security-audit-log' ) ),
|
311 |
-
array( 5009, E_CRITICAL, __( 'Deactivated theme from network', 'wp-security-audit-log' ), __( 'Network deactivated the theme %Theme->Name% installed in %Theme->get_template_directory%.', 'wp-security-audit-log' ) ),
|
312 |
-
),
|
313 |
-
|
314 |
/**
|
315 |
* Alerts: Plugins & Themes
|
316 |
*/
|
@@ -416,51 +438,34 @@ function wsaldefaults_wsal_init( WpSecurityAuditLog $wsal ) {
|
|
416 |
),
|
417 |
|
418 |
/**
|
419 |
-
* Section:
|
420 |
*/
|
421 |
-
__( '
|
422 |
-
/**
|
423 |
-
* Alerts: Other User Activity
|
424 |
-
*/
|
425 |
-
__( 'Other User Activity', 'wp-security-audit-log' ) => array(
|
426 |
-
array( 1000, E_NOTICE, __( 'User logged in', 'wp-security-audit-log' ), __( 'Successfully logged in.', 'wp-security-audit-log' ) ),
|
427 |
-
array( 1001, E_NOTICE, __( 'User logged out', 'wp-security-audit-log' ), __( 'Successfully logged out.', 'wp-security-audit-log' ) ),
|
428 |
-
array( 1002, E_WARNING, __( 'Login failed', 'wp-security-audit-log' ), __( '%Attempts% failed login(s) detected.', 'wp-security-audit-log' ) ),
|
429 |
-
array( 1003, E_WARNING, __( 'Login failed / non existing user', 'wp-security-audit-log' ), __( '%Attempts% failed login(s) detected using non existing user. %LogFileText%', 'wp-security-audit-log' ) ),
|
430 |
-
array( 1004, E_WARNING, __( 'Login blocked', 'wp-security-audit-log' ), __( 'Blocked from logging in because the same WordPress user is logged in from %ClientIP%.', 'wp-security-audit-log' ) ),
|
431 |
-
array( 1005, E_WARNING, __( 'User logged in with existing session(s)', 'wp-security-audit-log' ), __( 'Successfully logged in. Another session from %IPAddress% for this user already exist.', 'wp-security-audit-log' ) ),
|
432 |
-
array( 1006, E_CRITICAL, __( 'User logged out all other sessions with the same username', 'wp-security-audit-log' ), __( 'Logged out all other sessions with the same username.', 'wp-security-audit-log' ) ),
|
433 |
-
array( 1007, E_CRITICAL, __( 'User session destroyed and logged out.', 'wp-security-audit-log' ), __( 'Logged out session %TargetSessionID% which belonged to %TargetUserName%', 'wp-security-audit-log' ) ),
|
434 |
-
array( 2010, E_NOTICE, __( 'User uploaded file from Uploads directory', 'wp-security-audit-log' ), __( 'Uploaded the file %FileName% in %FilePath%.', 'wp-security-audit-log' ) ),
|
435 |
-
array( 2011, E_WARNING, __( 'User deleted file from Uploads directory', 'wp-security-audit-log' ), __( 'Deleted the file %FileName% from %FilePath%.', 'wp-security-audit-log' ) ),
|
436 |
-
),
|
437 |
-
|
438 |
/**
|
439 |
-
* Alerts:
|
440 |
*/
|
441 |
-
__( '
|
442 |
-
array(
|
443 |
-
array(
|
444 |
-
array(
|
445 |
-
array(
|
446 |
-
array(
|
447 |
-
array(
|
448 |
-
array(
|
449 |
-
array(
|
450 |
-
array(
|
451 |
-
array(
|
452 |
-
array(
|
453 |
-
array(
|
454 |
-
array(
|
455 |
-
array(
|
456 |
-
array( 4020, E_WARNING, __( 'User changed the display name for a user', 'wp-security-audit-log' ), __( 'Changed the Display name publicly of user %TargetUsername% from %old_displayname% to %new_displayname%', 'wp-security-audit-log' ) ),
|
457 |
),
|
458 |
),
|
459 |
|
460 |
/**
|
461 |
* Section: Third Party Support
|
462 |
*/
|
463 |
-
__( 'Third Party
|
464 |
/**
|
465 |
* Alerts: BBPress Forum
|
466 |
*/
|
129 |
// Create list of default alerts.
|
130 |
$wsal->alerts->RegisterGroup(
|
131 |
array(
|
132 |
+
/**
|
133 |
+
* Section: Users Profiles & Activity
|
134 |
+
*/
|
135 |
+
__( 'Users Profiles & Activity', 'wp-security-audit-log' ) => array(
|
136 |
+
/**
|
137 |
+
* Alerts: Other User Activity
|
138 |
+
*/
|
139 |
+
__( 'Other User Activity', 'wp-security-audit-log' ) => array(
|
140 |
+
array( 1000, E_NOTICE, __( 'User logged in', 'wp-security-audit-log' ), __( 'Successfully logged in.', 'wp-security-audit-log' ) ),
|
141 |
+
array( 1001, E_NOTICE, __( 'User logged out', 'wp-security-audit-log' ), __( 'Successfully logged out.', 'wp-security-audit-log' ) ),
|
142 |
+
array( 1002, E_WARNING, __( 'Login failed', 'wp-security-audit-log' ), __( '%Attempts% failed login(s) detected.', 'wp-security-audit-log' ) ),
|
143 |
+
array( 1003, E_WARNING, __( 'Login failed / non existing user', 'wp-security-audit-log' ), __( '%Attempts% failed login(s) detected using non existing user. %LogFileText%', 'wp-security-audit-log' ) ),
|
144 |
+
array( 1004, E_WARNING, __( 'Login blocked', 'wp-security-audit-log' ), __( 'Blocked from logging in because the same WordPress user is logged in from %ClientIP%.', 'wp-security-audit-log' ) ),
|
145 |
+
array( 1005, E_WARNING, __( 'User logged in with existing session(s)', 'wp-security-audit-log' ), __( 'Successfully logged in. Another session from %IPAddress% for this user already exist.', 'wp-security-audit-log' ) ),
|
146 |
+
array( 1006, E_CRITICAL, __( 'User logged out all other sessions with the same username', 'wp-security-audit-log' ), __( 'Logged out all other sessions with the same username.', 'wp-security-audit-log' ) ),
|
147 |
+
array( 1007, E_CRITICAL, __( 'User session destroyed and logged out.', 'wp-security-audit-log' ), __( 'Logged out session %TargetSessionID% which belonged to %TargetUserName%', 'wp-security-audit-log' ) ),
|
148 |
+
array( 2010, E_NOTICE, __( 'User uploaded file from Uploads directory', 'wp-security-audit-log' ), __( 'Uploaded the file %FileName% in %FilePath%.', 'wp-security-audit-log' ) ),
|
149 |
+
array( 2011, E_WARNING, __( 'User deleted file from Uploads directory', 'wp-security-audit-log' ), __( 'Deleted the file %FileName% from %FilePath%.', 'wp-security-audit-log' ) ),
|
150 |
+
),
|
151 |
+
|
152 |
+
/**
|
153 |
+
* Alerts: User Profiles
|
154 |
+
*/
|
155 |
+
__( 'User Profiles', 'wp-security-audit-log' ) => array(
|
156 |
+
array( 4000, E_CRITICAL, __( 'New user was created on WordPress', 'wp-security-audit-log' ), __( 'A new user %NewUserData->Username% was created with role of %NewUserData->Roles%.', 'wp-security-audit-log' ) ),
|
157 |
+
array( 4001, E_CRITICAL, __( 'User created another WordPress user', 'wp-security-audit-log' ), __( '%UserChanger% created a new user %NewUserData->Username% with the role of %NewUserData->Roles%.', 'wp-security-audit-log' ) ),
|
158 |
+
array( 4002, E_CRITICAL, __( 'The role of a user was changed by another WordPress user', 'wp-security-audit-log' ), __( 'Changed the role of the user %TargetUsername% from %OldRole% to %NewRole%%multisite_text%.', 'wp-security-audit-log' ) ),
|
159 |
+
array( 4003, E_CRITICAL, __( 'User has changed his or her password', 'wp-security-audit-log' ), __( 'Changed the password.', 'wp-security-audit-log' ) ),
|
160 |
+
array( 4004, E_CRITICAL, __( 'User changed another user\'s password', 'wp-security-audit-log' ), __( 'Changed the password for the user %TargetUserData->Username% with the role of %TargetUserData->Roles%.', 'wp-security-audit-log' ) ),
|
161 |
+
array( 4005, E_NOTICE, __( 'User changed his or her email address', 'wp-security-audit-log' ), __( 'Changed the email address from %OldEmail% to %NewEmail%.', 'wp-security-audit-log' ) ),
|
162 |
+
array( 4006, E_NOTICE, __( 'User changed another user\'s email address', 'wp-security-audit-log' ), __( 'Changed the email address of the user %TargetUsername% from %OldEmail% to %NewEmail%.', 'wp-security-audit-log' ) ),
|
163 |
+
array( 4007, E_CRITICAL, __( 'User was deleted by another user', 'wp-security-audit-log' ), __( 'Deleted the user %TargetUserData->Username% with the role of %TargetUserData->Roles%.', 'wp-security-audit-log' ) ),
|
164 |
+
array( 4014, E_NOTICE, __( 'User opened the profile page of another user', 'wp-security-audit-log' ), __( '%UserChanger% opened the profile page of the user %TargetUsername%.', 'wp-security-audit-log' ) ),
|
165 |
+
array( 4015, E_NOTICE, __( 'User updated a custom field value for a user', 'wp-security-audit-log' ), __( 'Changed the value of the custom field %custom_field_name%%ReportText% for the user %TargetUsername%.%ChangeText%', 'wp-security-audit-log' ) ),
|
166 |
+
array( 4016, E_NOTICE, __( 'User created a custom field value for a user', 'wp-security-audit-log' ), __( 'Created the value of the custom field %custom_field_name% with %new_value% for the user %TargetUsername%.', 'wp-security-audit-log' ) ),
|
167 |
+
array( 4017, E_NOTICE, __( 'User changed first name for a user', 'wp-security-audit-log' ), __( 'Changed the first name of the user %TargetUsername% from %old_firstname% to %new_firstname%', 'wp-security-audit-log' ) ),
|
168 |
+
array( 4018, E_NOTICE, __( 'User changed last name for a user', 'wp-security-audit-log' ), __( 'Changed the last name of the user %TargetUsername% from %old_lastname% to %new_lastname%', 'wp-security-audit-log' ) ),
|
169 |
+
array( 4019, E_NOTICE, __( 'User changed nickname for a user', 'wp-security-audit-log' ), __( 'Changed the nickname of the user %TargetUsername% from %old_nickname% to %new_nickname%', 'wp-security-audit-log' ) ),
|
170 |
+
array( 4020, E_WARNING, __( 'User changed the display name for a user', 'wp-security-audit-log' ), __( 'Changed the Display name publicly of user %TargetUsername% from %old_displayname% to %new_displayname%', 'wp-security-audit-log' ) ),
|
171 |
+
),
|
172 |
+
),
|
173 |
+
|
174 |
/**
|
175 |
* Section: Content & Comments
|
176 |
*/
|
315 |
),
|
316 |
|
317 |
/**
|
318 |
+
* Section: WordPress Install
|
319 |
*/
|
320 |
+
__( 'WordPress Install', 'wp-security-audit-log' ) => array(
|
321 |
/**
|
322 |
* Alerts: Database
|
323 |
*/
|
333 |
array( 5018, E_CRITICAL, __( 'Unknown component deleted tables', 'wp-security-audit-log' ), __( 'An unknown component deleted the following tables from the database: %TableNames%.', 'wp-security-audit-log' ) ),
|
334 |
),
|
335 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
336 |
/**
|
337 |
* Alerts: Plugins & Themes
|
338 |
*/
|
438 |
),
|
439 |
|
440 |
/**
|
441 |
+
* Section: Multisite Network
|
442 |
*/
|
443 |
+
__( 'Multisite Network', 'wp-security-audit-log' ) => array(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
444 |
/**
|
445 |
+
* Alerts: MultiSite
|
446 |
*/
|
447 |
+
__( 'MultiSite', 'wp-security-audit-log' ) => array(
|
448 |
+
array( 4008, E_CRITICAL, __( 'User granted Super Admin privileges', 'wp-security-audit-log' ), __( 'Granted Super Admin privileges to %TargetUsername%.', 'wp-security-audit-log' ) ),
|
449 |
+
array( 4009, E_CRITICAL, __( 'User revoked from Super Admin privileges', 'wp-security-audit-log' ), __( 'Revoked Super Admin privileges from %TargetUsername%.', 'wp-security-audit-log' ) ),
|
450 |
+
array( 4010, E_CRITICAL, __( 'Existing user added to a site', 'wp-security-audit-log' ), __( 'Added the existing user %TargetUsername% with %TargetUserRole% role to site %SiteName%.', 'wp-security-audit-log' ) ),
|
451 |
+
array( 4011, E_CRITICAL, __( 'User removed from site', 'wp-security-audit-log' ), __( 'Removed the user %TargetUsername% with role %TargetUserRole% from %SiteName% site.', 'wp-security-audit-log' ) ),
|
452 |
+
array( 4012, E_CRITICAL, __( 'New network user created', 'wp-security-audit-log' ), __( 'Created a new network user %NewUserData->Username%.', 'wp-security-audit-log' ) ),
|
453 |
+
array( 4013, E_CRITICAL, __( 'The forum role of a user was changed by another WordPress user', 'wp-security-audit-log' ), __( 'Change the forum role of the user %TargetUsername% from %OldRole% to %NewRole% by %UserChanger%.', 'wp-security-audit-log' ) ),
|
454 |
+
array( 7000, E_CRITICAL, __( 'New site added on the network', 'wp-security-audit-log' ), __( 'Added the site %SiteName% to the network.', 'wp-security-audit-log' ) ),
|
455 |
+
array( 7001, E_CRITICAL, __( 'Existing site archived', 'wp-security-audit-log' ), __( 'Archived the site %SiteName%.', 'wp-security-audit-log' ) ),
|
456 |
+
array( 7002, E_CRITICAL, __( 'Archived site has been unarchived', 'wp-security-audit-log' ), __( 'Unarchived the site %SiteName%.', 'wp-security-audit-log' ) ),
|
457 |
+
array( 7003, E_CRITICAL, __( 'Deactivated site has been activated', 'wp-security-audit-log' ), __( 'Activated the site %SiteName%.', 'wp-security-audit-log' ) ),
|
458 |
+
array( 7004, E_CRITICAL, __( 'Site has been deactivated', 'wp-security-audit-log' ), __( 'Deactivated the site %SiteName%.', 'wp-security-audit-log' ) ),
|
459 |
+
array( 7005, E_CRITICAL, __( 'Existing site deleted from network', 'wp-security-audit-log' ), __( 'Deleted the site %SiteName%.', 'wp-security-audit-log' ) ),
|
460 |
+
array( 5008, E_CRITICAL, __( 'Activated theme on network', 'wp-security-audit-log' ), __( 'Network activated the theme %Theme->Name% installed in %Theme->get_template_directory%.', 'wp-security-audit-log' ) ),
|
461 |
+
array( 5009, E_CRITICAL, __( 'Deactivated theme from network', 'wp-security-audit-log' ), __( 'Network deactivated the theme %Theme->Name% installed in %Theme->get_template_directory%.', 'wp-security-audit-log' ) ),
|
|
|
462 |
),
|
463 |
),
|
464 |
|
465 |
/**
|
466 |
* Section: Third Party Support
|
467 |
*/
|
468 |
+
__( 'Third Party Plugins', 'wp-security-audit-log' ) => array(
|
469 |
/**
|
470 |
* Alerts: BBPress Forum
|
471 |
*/
|
img/wsal-logo-full.png
ADDED
Binary file
|
img/wsal-logo-full@2x.png
ADDED
Binary file
|
js/auditlog.js
CHANGED
@@ -381,11 +381,12 @@ function wsal_exclude_url(element) {
|
|
381 |
}
|
382 |
|
383 |
jQuery( document ).ready( function() {
|
|
|
384 |
/**
|
385 |
* Dismiss DB disconnect issue notice.
|
386 |
*/
|
387 |
jQuery( '#wsal-notice-connect-issue' ).click( function() {
|
388 |
-
jQuery.ajax(
|
389 |
type: 'POST',
|
390 |
url: ajaxurl,
|
391 |
async: true,
|
@@ -401,6 +402,6 @@ jQuery( document ).ready( function() {
|
|
401 |
console.log( textStatus );
|
402 |
console.log( error );
|
403 |
}
|
404 |
-
}
|
405 |
-
}
|
406 |
-
}
|
381 |
}
|
382 |
|
383 |
jQuery( document ).ready( function() {
|
384 |
+
|
385 |
/**
|
386 |
* Dismiss DB disconnect issue notice.
|
387 |
*/
|
388 |
jQuery( '#wsal-notice-connect-issue' ).click( function() {
|
389 |
+
jQuery.ajax({
|
390 |
type: 'POST',
|
391 |
url: ajaxurl,
|
392 |
async: true,
|
402 |
console.log( textStatus );
|
403 |
console.log( error );
|
404 |
}
|
405 |
+
});
|
406 |
+
});
|
407 |
+
});
|
js/dist/wsal-wizard.js
ADDED
@@ -0,0 +1,10592 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/******/ (function(modules) { // webpackBootstrap
|
2 |
+
/******/ // The module cache
|
3 |
+
/******/ var installedModules = {};
|
4 |
+
/******/
|
5 |
+
/******/ // The require function
|
6 |
+
/******/ function __webpack_require__(moduleId) {
|
7 |
+
/******/
|
8 |
+
/******/ // Check if module is in cache
|
9 |
+
/******/ if(installedModules[moduleId]) {
|
10 |
+
/******/ return installedModules[moduleId].exports;
|
11 |
+
/******/ }
|
12 |
+
/******/ // Create a new module (and put it into the cache)
|
13 |
+
/******/ var module = installedModules[moduleId] = {
|
14 |
+
/******/ i: moduleId,
|
15 |
+
/******/ l: false,
|
16 |
+
/******/ exports: {}
|
17 |
+
/******/ };
|
18 |
+
/******/
|
19 |
+
/******/ // Execute the module function
|
20 |
+
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
21 |
+
/******/
|
22 |
+
/******/ // Flag the module as loaded
|
23 |
+
/******/ module.l = true;
|
24 |
+
/******/
|
25 |
+
/******/ // Return the exports of the module
|
26 |
+
/******/ return module.exports;
|
27 |
+
/******/ }
|
28 |
+
/******/
|
29 |
+
/******/
|
30 |
+
/******/ // expose the modules object (__webpack_modules__)
|
31 |
+
/******/ __webpack_require__.m = modules;
|
32 |
+
/******/
|
33 |
+
/******/ // expose the module cache
|
34 |
+
/******/ __webpack_require__.c = installedModules;
|
35 |
+
/******/
|
36 |
+
/******/ // define getter function for harmony exports
|
37 |
+
/******/ __webpack_require__.d = function(exports, name, getter) {
|
38 |
+
/******/ if(!__webpack_require__.o(exports, name)) {
|
39 |
+
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
|
40 |
+
/******/ }
|
41 |
+
/******/ };
|
42 |
+
/******/
|
43 |
+
/******/ // define __esModule on exports
|
44 |
+
/******/ __webpack_require__.r = function(exports) {
|
45 |
+
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
46 |
+
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
47 |
+
/******/ }
|
48 |
+
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
49 |
+
/******/ };
|
50 |
+
/******/
|
51 |
+
/******/ // create a fake namespace object
|
52 |
+
/******/ // mode & 1: value is a module id, require it
|
53 |
+
/******/ // mode & 2: merge all properties of value into the ns
|
54 |
+
/******/ // mode & 4: return value when already ns object
|
55 |
+
/******/ // mode & 8|1: behave like require
|
56 |
+
/******/ __webpack_require__.t = function(value, mode) {
|
57 |
+
/******/ if(mode & 1) value = __webpack_require__(value);
|
58 |
+
/******/ if(mode & 8) return value;
|
59 |
+
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
|
60 |
+
/******/ var ns = Object.create(null);
|
61 |
+
/******/ __webpack_require__.r(ns);
|
62 |
+
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
|
63 |
+
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
|
64 |
+
/******/ return ns;
|
65 |
+
/******/ };
|
66 |
+
/******/
|
67 |
+
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
68 |
+
/******/ __webpack_require__.n = function(module) {
|
69 |
+
/******/ var getter = module && module.__esModule ?
|
70 |
+
/******/ function getDefault() { return module['default']; } :
|
71 |
+
/******/ function getModuleExports() { return module; };
|
72 |
+
/******/ __webpack_require__.d(getter, 'a', getter);
|
73 |
+
/******/ return getter;
|
74 |
+
/******/ };
|
75 |
+
/******/
|
76 |
+
/******/ // Object.prototype.hasOwnProperty.call
|
77 |
+
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
78 |
+
/******/
|
79 |
+
/******/ // __webpack_public_path__
|
80 |
+
/******/ __webpack_require__.p = "";
|
81 |
+
/******/
|
82 |
+
/******/
|
83 |
+
/******/ // Load entry module and return exports
|
84 |
+
/******/ return __webpack_require__(__webpack_require__.s = "./js/src/wsal-wizard.js");
|
85 |
+
/******/ })
|
86 |
+
/************************************************************************/
|
87 |
+
/******/ ({
|
88 |
+
|
89 |
+
/***/ "./css/src/wsal-wizard.scss":
|
90 |
+
/*!**********************************!*\
|
91 |
+
!*** ./css/src/wsal-wizard.scss ***!
|
92 |
+
\**********************************/
|
93 |
+
/*! no static exports found */
|
94 |
+
/***/ (function(module, exports) {
|
95 |
+
|
96 |
+
// removed by extract-text-webpack-plugin
|
97 |
+
|
98 |
+
/***/ }),
|
99 |
+
|
100 |
+
/***/ "./js/src/wsal-wizard.js":
|
101 |
+
/*!*******************************!*\
|
102 |
+
!*** ./js/src/wsal-wizard.js ***!
|
103 |
+
\*******************************/
|
104 |
+
/*! no static exports found */
|
105 |
+
/***/ (function(module, exports, __webpack_require__) {
|
106 |
+
|
107 |
+
"use strict";
|
108 |
+
|
109 |
+
|
110 |
+
__webpack_require__(/*! ../../css/src/wsal-wizard.scss */ "./css/src/wsal-wizard.scss");
|
111 |
+
|
112 |
+
var _jquery = __webpack_require__(/*! jquery */ "./node_modules/jquery/dist/jquery.js");
|
113 |
+
|
114 |
+
var _jquery2 = _interopRequireDefault(_jquery);
|
115 |
+
|
116 |
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
117 |
+
|
118 |
+
/**
|
119 |
+
* WSAL Wizard
|
120 |
+
*
|
121 |
+
* Entry file for webpack.
|
122 |
+
*
|
123 |
+
* @since 3.2.3
|
124 |
+
*/
|
125 |
+
|
126 |
+
// Wizard styles.
|
127 |
+
(0, _jquery2.default)(document).ready(function () {
|
128 |
+
|
129 |
+
/**
|
130 |
+
* Step: `Access`
|
131 |
+
*
|
132 |
+
* Usernames & roles access setting.
|
133 |
+
*/
|
134 |
+
(0, _jquery2.default)('#editor-users-add, #editor-roles-add, #exuser-query-add, #exrole-query-add, #ipaddr-query-add').click(function () {
|
135 |
+
var type = (0, _jquery2.default)(this).attr('id').substr(0, 6);
|
136 |
+
var tokenType = (0, _jquery2.default)(this).attr('id').substr(7, 5);
|
137 |
+
var tokenValue = _jquery2.default.trim((0, _jquery2.default)('#' + type + '-' + tokenType + '-box').val());
|
138 |
+
var existing = (0, _jquery2.default)('#' + type + '-list input').filter(function () {
|
139 |
+
return this.value === tokenValue;
|
140 |
+
});
|
141 |
+
|
142 |
+
if (!tokenValue || existing.length) {
|
143 |
+
return;
|
144 |
+
} // if value is empty or already used, stop here
|
145 |
+
|
146 |
+
// checkDataToken( 'user' );
|
147 |
+
(0, _jquery2.default)('#' + type + '-' + tokenType + '-box, #' + type + '-' + tokenType + '-add').attr('disabled', true);
|
148 |
+
|
149 |
+
_jquery2.default.ajax({
|
150 |
+
type: 'POST',
|
151 |
+
url: wsalData.ajaxURL,
|
152 |
+
async: true,
|
153 |
+
data: {
|
154 |
+
action: 'setup_check_security_token',
|
155 |
+
token: tokenValue,
|
156 |
+
nonce: wsalData.nonce
|
157 |
+
},
|
158 |
+
dataType: 'json',
|
159 |
+
success: function success(data) {
|
160 |
+
|
161 |
+
// Remove disabled attribute.
|
162 |
+
(0, _jquery2.default)('#' + type + '-' + tokenType + '-box, #' + type + '-' + tokenType + '-add').removeAttr('disabled');
|
163 |
+
(0, _jquery2.default)('#' + type + '-' + tokenType + '-box').val('');
|
164 |
+
|
165 |
+
if (data.success) {
|
166 |
+
|
167 |
+
// Error handling.
|
168 |
+
if ('other' === data.tokenType && ('users' === tokenType || 'exuser' === type)) {
|
169 |
+
alert(wsalData.usersError);
|
170 |
+
return;
|
171 |
+
} else if ('other' === data.tokenType && ('roles' === tokenType || 'exrole' === type)) {
|
172 |
+
alert(wsalData.rolesError);
|
173 |
+
return;
|
174 |
+
} else if ('other' === data.tokenType && ('ip' === tokenType || 'ipaddr' === type)) {
|
175 |
+
alert(wsalData.ipError);
|
176 |
+
return;
|
177 |
+
}
|
178 |
+
|
179 |
+
(0, _jquery2.default)('#' + type + '-list').append((0, _jquery2.default)('<span class="sectoken-' + data.tokenType + '"/>').text(data.token).append((0, _jquery2.default)('<input type="hidden" name="' + type + 's[]"/>').val(data.token), (0, _jquery2.default)('<a href="javascript:;" title="Remove">×</a>').click(removeSecToken)));
|
180 |
+
} else {
|
181 |
+
alert(data.message);
|
182 |
+
}
|
183 |
+
},
|
184 |
+
error: function error(xhr, textStatus, _error) {
|
185 |
+
console.log(xhr.statusText);
|
186 |
+
console.log(textStatus);
|
187 |
+
console.log(_error);
|
188 |
+
}
|
189 |
+
});
|
190 |
+
});
|
191 |
+
|
192 |
+
(0, _jquery2.default)('#editor-users-box, #editor-roles-box, #exuser-query-box, #exrole-query-box, #ipaddr-query-box').keydown(function (event) {
|
193 |
+
if (13 === event.keyCode) {
|
194 |
+
var type = (0, _jquery2.default)(this).attr('id').substr(0, 6);
|
195 |
+
var tokenType = (0, _jquery2.default)(this).attr('id').substr(7, 5);
|
196 |
+
(0, _jquery2.default)('#' + type + '-' + tokenType + '-add').click();
|
197 |
+
return false;
|
198 |
+
}
|
199 |
+
});
|
200 |
+
|
201 |
+
/**
|
202 |
+
* Remove access settings token.
|
203 |
+
*/
|
204 |
+
(0, _jquery2.default)('#editor-list>span>a, #exuser-list>span>a, #exrole-list>span>a, #ipaddr-list>span>a').click(removeSecToken);
|
205 |
+
function removeSecToken() {
|
206 |
+
var token = (0, _jquery2.default)(this).parents('span:first');
|
207 |
+
token.addClass('sectoken-del').fadeOut('fast', function () {
|
208 |
+
token.remove();
|
209 |
+
});
|
210 |
+
};
|
211 |
+
});
|
212 |
+
|
213 |
+
/***/ }),
|
214 |
+
|
215 |
+
/***/ "./node_modules/jquery/dist/jquery.js":
|
216 |
+
/*!********************************************!*\
|
217 |
+
!*** ./node_modules/jquery/dist/jquery.js ***!
|
218 |
+
\********************************************/
|
219 |
+
/*! no static exports found */
|
220 |
+
/***/ (function(module, exports, __webpack_require__) {
|
221 |
+
|
222 |
+
var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!
|
223 |
+
* jQuery JavaScript Library v3.3.1
|
224 |
+
* https://jquery.com/
|
225 |
+
*
|
226 |
+
* Includes Sizzle.js
|
227 |
+
* https://sizzlejs.com/
|
228 |
+
*
|
229 |
+
* Copyright JS Foundation and other contributors
|
230 |
+
* Released under the MIT license
|
231 |
+
* https://jquery.org/license
|
232 |
+
*
|
233 |
+
* Date: 2018-01-20T17:24Z
|
234 |
+
*/
|
235 |
+
( function( global, factory ) {
|
236 |
+
|
237 |
+
"use strict";
|
238 |
+
|
239 |
+
if ( typeof module === "object" && typeof module.exports === "object" ) {
|
240 |
+
|
241 |
+
// For CommonJS and CommonJS-like environments where a proper `window`
|
242 |
+
// is present, execute the factory and get jQuery.
|
243 |
+
// For environments that do not have a `window` with a `document`
|
244 |
+
// (such as Node.js), expose a factory as module.exports.
|
245 |
+
// This accentuates the need for the creation of a real `window`.
|
246 |
+
// e.g. var jQuery = require("jquery")(window);
|
247 |
+
// See ticket #14549 for more info.
|
248 |
+
module.exports = global.document ?
|
249 |
+
factory( global, true ) :
|
250 |
+
function( w ) {
|
251 |
+
if ( !w.document ) {
|
252 |
+
throw new Error( "jQuery requires a window with a document" );
|
253 |
+
}
|
254 |
+
return factory( w );
|
255 |
+
};
|
256 |
+
} else {
|
257 |
+
factory( global );
|
258 |
+
}
|
259 |
+
|
260 |
+
// Pass this if window is not defined yet
|
261 |
+
} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
|
262 |
+
|
263 |
+
// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
|
264 |
+
// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
|
265 |
+
// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
|
266 |
+
// enough that all such attempts are guarded in a try block.
|
267 |
+
"use strict";
|
268 |
+
|
269 |
+
var arr = [];
|
270 |
+
|
271 |
+
var document = window.document;
|
272 |
+
|
273 |
+
var getProto = Object.getPrototypeOf;
|
274 |
+
|
275 |
+
var slice = arr.slice;
|
276 |
+
|
277 |
+
var concat = arr.concat;
|
278 |
+
|
279 |
+
var push = arr.push;
|
280 |
+
|
281 |
+
var indexOf = arr.indexOf;
|
282 |
+
|
283 |
+
var class2type = {};
|
284 |
+
|
285 |
+
var toString = class2type.toString;
|
286 |
+
|
287 |
+
var hasOwn = class2type.hasOwnProperty;
|
288 |
+
|
289 |
+
var fnToString = hasOwn.toString;
|
290 |
+
|
291 |
+
var ObjectFunctionString = fnToString.call( Object );
|
292 |
+
|
293 |
+
var support = {};
|
294 |
+
|
295 |
+
var isFunction = function isFunction( obj ) {
|
296 |
+
|
297 |
+
// Support: Chrome <=57, Firefox <=52
|
298 |
+
// In some browsers, typeof returns "function" for HTML <object> elements
|
299 |
+
// (i.e., `typeof document.createElement( "object" ) === "function"`).
|
300 |
+
// We don't want to classify *any* DOM node as a function.
|
301 |
+
return typeof obj === "function" && typeof obj.nodeType !== "number";
|
302 |
+
};
|
303 |
+
|
304 |
+
|
305 |
+
var isWindow = function isWindow( obj ) {
|
306 |
+
return obj != null && obj === obj.window;
|
307 |
+
};
|
308 |
+
|
309 |
+
|
310 |
+
|
311 |
+
|
312 |
+
var preservedScriptAttributes = {
|
313 |
+
type: true,
|
314 |
+
src: true,
|
315 |
+
noModule: true
|
316 |
+
};
|
317 |
+
|
318 |
+
function DOMEval( code, doc, node ) {
|
319 |
+
doc = doc || document;
|
320 |
+
|
321 |
+
var i,
|
322 |
+
script = doc.createElement( "script" );
|
323 |
+
|
324 |
+
script.text = code;
|
325 |
+
if ( node ) {
|
326 |
+
for ( i in preservedScriptAttributes ) {
|
327 |
+
if ( node[ i ] ) {
|
328 |
+
script[ i ] = node[ i ];
|
329 |
+
}
|
330 |
+
}
|
331 |
+
}
|
332 |
+
doc.head.appendChild( script ).parentNode.removeChild( script );
|
333 |
+
}
|
334 |
+
|
335 |
+
|
336 |
+
function toType( obj ) {
|
337 |
+
if ( obj == null ) {
|
338 |
+
return obj + "";
|
339 |
+
}
|
340 |
+
|
341 |
+
// Support: Android <=2.3 only (functionish RegExp)
|
342 |
+
return typeof obj === "object" || typeof obj === "function" ?
|
343 |
+
class2type[ toString.call( obj ) ] || "object" :
|
344 |
+
typeof obj;
|
345 |
+
}
|
346 |
+
/* global Symbol */
|
347 |
+
// Defining this global in .eslintrc.json would create a danger of using the global
|
348 |
+
// unguarded in another place, it seems safer to define global only for this module
|
349 |
+
|
350 |
+
|
351 |
+
|
352 |
+
var
|
353 |
+
version = "3.3.1",
|
354 |
+
|
355 |
+
// Define a local copy of jQuery
|
356 |
+
jQuery = function( selector, context ) {
|
357 |
+
|
358 |
+
// The jQuery object is actually just the init constructor 'enhanced'
|
359 |
+
// Need init if jQuery is called (just allow error to be thrown if not included)
|
360 |
+
return new jQuery.fn.init( selector, context );
|
361 |
+
},
|
362 |
+
|
363 |
+
// Support: Android <=4.0 only
|
364 |
+
// Make sure we trim BOM and NBSP
|
365 |
+
rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
|
366 |
+
|
367 |
+
jQuery.fn = jQuery.prototype = {
|
368 |
+
|
369 |
+
// The current version of jQuery being used
|
370 |
+
jquery: version,
|
371 |
+
|
372 |
+
constructor: jQuery,
|
373 |
+
|
374 |
+
// The default length of a jQuery object is 0
|
375 |
+
length: 0,
|
376 |
+
|
377 |
+
toArray: function() {
|
378 |
+
return slice.call( this );
|
379 |
+
},
|
380 |
+
|
381 |
+
// Get the Nth element in the matched element set OR
|
382 |
+
// Get the whole matched element set as a clean array
|
383 |
+
get: function( num ) {
|
384 |
+
|
385 |
+
// Return all the elements in a clean array
|
386 |
+
if ( num == null ) {
|
387 |
+
return slice.call( this );
|
388 |
+
}
|
389 |
+
|
390 |
+
// Return just the one element from the set
|
391 |
+
return num < 0 ? this[ num + this.length ] : this[ num ];
|
392 |
+
},
|
393 |
+
|
394 |
+
// Take an array of elements and push it onto the stack
|
395 |
+
// (returning the new matched element set)
|
396 |
+
pushStack: function( elems ) {
|
397 |
+
|
398 |
+
// Build a new jQuery matched element set
|
399 |
+
var ret = jQuery.merge( this.constructor(), elems );
|
400 |
+
|
401 |
+
// Add the old object onto the stack (as a reference)
|
402 |
+
ret.prevObject = this;
|
403 |
+
|
404 |
+
// Return the newly-formed element set
|
405 |
+
return ret;
|
406 |
+
},
|
407 |
+
|
408 |
+
// Execute a callback for every element in the matched set.
|
409 |
+
each: function( callback ) {
|
410 |
+
return jQuery.each( this, callback );
|
411 |
+
},
|
412 |
+
|
413 |
+
map: function( callback ) {
|
414 |
+
return this.pushStack( jQuery.map( this, function( elem, i ) {
|
415 |
+
return callback.call( elem, i, elem );
|
416 |
+
} ) );
|
417 |
+
},
|
418 |
+
|
419 |
+
slice: function() {
|
420 |
+
return this.pushStack( slice.apply( this, arguments ) );
|
421 |
+
},
|
422 |
+
|
423 |
+
first: function() {
|
424 |
+
return this.eq( 0 );
|
425 |
+
},
|
426 |
+
|
427 |
+
last: function() {
|
428 |
+
return this.eq( -1 );
|
429 |
+
},
|
430 |
+
|
431 |
+
eq: function( i ) {
|
432 |
+
var len = this.length,
|
433 |
+
j = +i + ( i < 0 ? len : 0 );
|
434 |
+
return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
|
435 |
+
},
|
436 |
+
|
437 |
+
end: function() {
|
438 |
+
return this.prevObject || this.constructor();
|
439 |
+
},
|
440 |
+
|
441 |
+
// For internal use only.
|
442 |
+
// Behaves like an Array's method, not like a jQuery method.
|
443 |
+
push: push,
|
444 |
+
sort: arr.sort,
|
445 |
+
splice: arr.splice
|
446 |
+
};
|
447 |
+
|
448 |
+
jQuery.extend = jQuery.fn.extend = function() {
|
449 |
+
var options, name, src, copy, copyIsArray, clone,
|
450 |
+
target = arguments[ 0 ] || {},
|
451 |
+
i = 1,
|
452 |
+
length = arguments.length,
|
453 |
+
deep = false;
|
454 |
+
|
455 |
+
// Handle a deep copy situation
|
456 |
+
if ( typeof target === "boolean" ) {
|
457 |
+
deep = target;
|
458 |
+
|
459 |
+
// Skip the boolean and the target
|
460 |
+
target = arguments[ i ] || {};
|
461 |
+
i++;
|
462 |
+
}
|
463 |
+
|
464 |
+
// Handle case when target is a string or something (possible in deep copy)
|
465 |
+
if ( typeof target !== "object" && !isFunction( target ) ) {
|
466 |
+
target = {};
|
467 |
+
}
|
468 |
+
|
469 |
+
// Extend jQuery itself if only one argument is passed
|
470 |
+
if ( i === length ) {
|
471 |
+
target = this;
|
472 |
+
i--;
|
473 |
+
}
|
474 |
+
|
475 |
+
for ( ; i < length; i++ ) {
|
476 |
+
|
477 |
+
// Only deal with non-null/undefined values
|
478 |
+
if ( ( options = arguments[ i ] ) != null ) {
|
479 |
+
|
480 |
+
// Extend the base object
|
481 |
+
for ( name in options ) {
|
482 |
+
src = target[ name ];
|
483 |
+
copy = options[ name ];
|
484 |
+
|
485 |
+
// Prevent never-ending loop
|
486 |
+
if ( target === copy ) {
|
487 |
+
continue;
|
488 |
+
}
|
489 |
+
|
490 |
+
// Recurse if we're merging plain objects or arrays
|
491 |
+
if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
|
492 |
+
( copyIsArray = Array.isArray( copy ) ) ) ) {
|
493 |
+
|
494 |
+
if ( copyIsArray ) {
|
495 |
+
copyIsArray = false;
|
496 |
+
clone = src && Array.isArray( src ) ? src : [];
|
497 |
+
|
498 |
+
} else {
|
499 |
+
clone = src && jQuery.isPlainObject( src ) ? src : {};
|
500 |
+
}
|
501 |
+
|
502 |
+
// Never move original objects, clone them
|
503 |
+
target[ name ] = jQuery.extend( deep, clone, copy );
|
504 |
+
|
505 |
+
// Don't bring in undefined values
|
506 |
+
} else if ( copy !== undefined ) {
|
507 |
+
target[ name ] = copy;
|
508 |
+
}
|
509 |
+
}
|
510 |
+
}
|
511 |
+
}
|
512 |
+
|
513 |
+
// Return the modified object
|
514 |
+
return target;
|
515 |
+
};
|
516 |
+
|
517 |
+
jQuery.extend( {
|
518 |
+
|
519 |
+
// Unique for each copy of jQuery on the page
|
520 |
+
expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
|
521 |
+
|
522 |
+
// Assume jQuery is ready without the ready module
|
523 |
+
isReady: true,
|
524 |
+
|
525 |
+
error: function( msg ) {
|
526 |
+
throw new Error( msg );
|
527 |
+
},
|
528 |
+
|
529 |
+
noop: function() {},
|
530 |
+
|
531 |
+
isPlainObject: function( obj ) {
|
532 |
+
var proto, Ctor;
|
533 |
+
|
534 |
+
// Detect obvious negatives
|
535 |
+
// Use toString instead of jQuery.type to catch host objects
|
536 |
+
if ( !obj || toString.call( obj ) !== "[object Object]" ) {
|
537 |
+
return false;
|
538 |
+
}
|
539 |
+
|
540 |
+
proto = getProto( obj );
|
541 |
+
|
542 |
+
// Objects with no prototype (e.g., `Object.create( null )`) are plain
|
543 |
+
if ( !proto ) {
|
544 |
+
return true;
|
545 |
+
}
|
546 |
+
|
547 |
+
// Objects with prototype are plain iff they were constructed by a global Object function
|
548 |
+
Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
|
549 |
+
return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
|
550 |
+
},
|
551 |
+
|
552 |
+
isEmptyObject: function( obj ) {
|
553 |
+
|
554 |
+
/* eslint-disable no-unused-vars */
|
555 |
+
// See https://github.com/eslint/eslint/issues/6125
|
556 |
+
var name;
|
557 |
+
|
558 |
+
for ( name in obj ) {
|
559 |
+
return false;
|
560 |
+
}
|
561 |
+
return true;
|
562 |
+
},
|
563 |
+
|
564 |
+
// Evaluates a script in a global context
|
565 |
+
globalEval: function( code ) {
|
566 |
+
DOMEval( code );
|
567 |
+
},
|
568 |
+
|
569 |
+
each: function( obj, callback ) {
|
570 |
+
var length, i = 0;
|
571 |
+
|
572 |
+
if ( isArrayLike( obj ) ) {
|
573 |
+
length = obj.length;
|
574 |
+
for ( ; i < length; i++ ) {
|
575 |
+
if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
|
576 |
+
break;
|
577 |
+
}
|
578 |
+
}
|
579 |
+
} else {
|
580 |
+
for ( i in obj ) {
|
581 |
+
if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
|
582 |
+
break;
|
583 |
+
}
|
584 |
+
}
|
585 |
+
}
|
586 |
+
|
587 |
+
return obj;
|
588 |
+
},
|
589 |
+
|
590 |
+
// Support: Android <=4.0 only
|
591 |
+
trim: function( text ) {
|
592 |
+
return text == null ?
|
593 |
+
"" :
|
594 |
+
( text + "" ).replace( rtrim, "" );
|
595 |
+
},
|
596 |
+
|
597 |
+
// results is for internal usage only
|
598 |
+
makeArray: function( arr, results ) {
|
599 |
+
var ret = results || [];
|
600 |
+
|
601 |
+
if ( arr != null ) {
|
602 |
+
if ( isArrayLike( Object( arr ) ) ) {
|
603 |
+
jQuery.merge( ret,
|
604 |
+
typeof arr === "string" ?
|
605 |
+
[ arr ] : arr
|
606 |
+
);
|
607 |
+
} else {
|
608 |
+
push.call( ret, arr );
|
609 |
+
}
|
610 |
+
}
|
611 |
+
|
612 |
+
return ret;
|
613 |
+
},
|
614 |
+
|
615 |
+
inArray: function( elem, arr, i ) {
|
616 |
+
return arr == null ? -1 : indexOf.call( arr, elem, i );
|
617 |
+
},
|
618 |
+
|
619 |
+
// Support: Android <=4.0 only, PhantomJS 1 only
|
620 |
+
// push.apply(_, arraylike) throws on ancient WebKit
|
621 |
+
merge: function( first, second ) {
|
622 |
+
var len = +second.length,
|
623 |
+
j = 0,
|
624 |
+
i = first.length;
|
625 |
+
|
626 |
+
for ( ; j < len; j++ ) {
|
627 |
+
first[ i++ ] = second[ j ];
|
628 |
+
}
|
629 |
+
|
630 |
+
first.length = i;
|
631 |
+
|
632 |
+
return first;
|
633 |
+
},
|
634 |
+
|
635 |
+
grep: function( elems, callback, invert ) {
|
636 |
+
var callbackInverse,
|
637 |
+
matches = [],
|
638 |
+
i = 0,
|
639 |
+
length = elems.length,
|
640 |
+
callbackExpect = !invert;
|
641 |
+
|
642 |
+
// Go through the array, only saving the items
|
643 |
+
// that pass the validator function
|
644 |
+
for ( ; i < length; i++ ) {
|
645 |
+
callbackInverse = !callback( elems[ i ], i );
|
646 |
+
if ( callbackInverse !== callbackExpect ) {
|
647 |
+
matches.push( elems[ i ] );
|
648 |
+
}
|
649 |
+
}
|
650 |
+
|
651 |
+
return matches;
|
652 |
+
},
|
653 |
+
|
654 |
+
// arg is for internal usage only
|
655 |
+
map: function( elems, callback, arg ) {
|
656 |
+
var length, value,
|
657 |
+
i = 0,
|
658 |
+
ret = [];
|
659 |
+
|
660 |
+
// Go through the array, translating each of the items to their new values
|
661 |
+
if ( isArrayLike( elems ) ) {
|
662 |
+
length = elems.length;
|
663 |
+
for ( ; i < length; i++ ) {
|
664 |
+
value = callback( elems[ i ], i, arg );
|
665 |
+
|
666 |
+
if ( value != null ) {
|
667 |
+
ret.push( value );
|
668 |
+
}
|
669 |
+
}
|
670 |
+
|
671 |
+
// Go through every key on the object,
|
672 |
+
} else {
|
673 |
+
for ( i in elems ) {
|
674 |
+
value = callback( elems[ i ], i, arg );
|
675 |
+
|
676 |
+
if ( value != null ) {
|
677 |
+
ret.push( value );
|
678 |
+
}
|
679 |
+
}
|
680 |
+
}
|
681 |
+
|
682 |
+
// Flatten any nested arrays
|
683 |
+
return concat.apply( [], ret );
|
684 |
+
},
|
685 |
+
|
686 |
+
// A global GUID counter for objects
|
687 |
+
guid: 1,
|
688 |
+
|
689 |
+
// jQuery.support is not used in Core but other projects attach their
|
690 |
+
// properties to it so it needs to exist.
|
691 |
+
support: support
|
692 |
+
} );
|
693 |
+
|
694 |
+
if ( typeof Symbol === "function" ) {
|
695 |
+
jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];
|
696 |
+
}
|
697 |
+
|
698 |
+
// Populate the class2type map
|
699 |
+
jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
|
700 |
+
function( i, name ) {
|
701 |
+
class2type[ "[object " + name + "]" ] = name.toLowerCase();
|
702 |
+
} );
|
703 |
+
|
704 |
+
function isArrayLike( obj ) {
|
705 |
+
|
706 |
+
// Support: real iOS 8.2 only (not reproducible in simulator)
|
707 |
+
// `in` check used to prevent JIT error (gh-2145)
|
708 |
+
// hasOwn isn't used here due to false negatives
|
709 |
+
// regarding Nodelist length in IE
|
710 |
+
var length = !!obj && "length" in obj && obj.length,
|
711 |
+
type = toType( obj );
|
712 |
+
|
713 |
+
if ( isFunction( obj ) || isWindow( obj ) ) {
|
714 |
+
return false;
|
715 |
+
}
|
716 |
+
|
717 |
+
return type === "array" || length === 0 ||
|
718 |
+
typeof length === "number" && length > 0 && ( length - 1 ) in obj;
|
719 |
+
}
|
720 |
+
var Sizzle =
|
721 |
+
/*!
|
722 |
+
* Sizzle CSS Selector Engine v2.3.3
|
723 |
+
* https://sizzlejs.com/
|
724 |
+
*
|
725 |
+
* Copyright jQuery Foundation and other contributors
|
726 |
+
* Released under the MIT license
|
727 |
+
* http://jquery.org/license
|
728 |
+
*
|
729 |
+
* Date: 2016-08-08
|
730 |
+
*/
|
731 |
+
(function( window ) {
|
732 |
+
|
733 |
+
var i,
|
734 |
+
support,
|
735 |
+
Expr,
|
736 |
+
getText,
|
737 |
+
isXML,
|
738 |
+
tokenize,
|
739 |
+
compile,
|
740 |
+
select,
|
741 |
+
outermostContext,
|
742 |
+
sortInput,
|
743 |
+
hasDuplicate,
|
744 |
+
|
745 |
+
// Local document vars
|
746 |
+
setDocument,
|
747 |
+
document,
|
748 |
+
docElem,
|
749 |
+
documentIsHTML,
|
750 |
+
rbuggyQSA,
|
751 |
+
rbuggyMatches,
|
752 |
+
matches,
|
753 |
+
contains,
|
754 |
+
|
755 |
+
// Instance-specific data
|
756 |
+
expando = "sizzle" + 1 * new Date(),
|
757 |
+
preferredDoc = window.document,
|
758 |
+
dirruns = 0,
|
759 |
+
done = 0,
|
760 |
+
classCache = createCache(),
|
761 |
+
tokenCache = createCache(),
|
762 |
+
compilerCache = createCache(),
|
763 |
+
sortOrder = function( a, b ) {
|
764 |
+
if ( a === b ) {
|
765 |
+
hasDuplicate = true;
|
766 |
+
}
|
767 |
+
return 0;
|
768 |
+
},
|
769 |
+
|
770 |
+
// Instance methods
|
771 |
+
hasOwn = ({}).hasOwnProperty,
|
772 |
+
arr = [],
|
773 |
+
pop = arr.pop,
|
774 |
+
push_native = arr.push,
|
775 |
+
push = arr.push,
|
776 |
+
slice = arr.slice,
|
777 |
+
// Use a stripped-down indexOf as it's faster than native
|
778 |
+
// https://jsperf.com/thor-indexof-vs-for/5
|
779 |
+
indexOf = function( list, elem ) {
|
780 |
+
var i = 0,
|
781 |
+
len = list.length;
|
782 |
+
for ( ; i < len; i++ ) {
|
783 |
+
if ( list[i] === elem ) {
|
784 |
+
return i;
|
785 |
+
}
|
786 |
+
}
|
787 |
+
return -1;
|
788 |
+
},
|
789 |
+
|
790 |
+
booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
|
791 |
+
|
792 |
+
// Regular expressions
|
793 |
+
|
794 |
+
// http://www.w3.org/TR/css3-selectors/#whitespace
|
795 |
+
whitespace = "[\\x20\\t\\r\\n\\f]",
|
796 |
+
|
797 |
+
// http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
|
798 |
+
identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+",
|
799 |
+
|
800 |
+
// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
|
801 |
+
attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
|
802 |
+
// Operator (capture 2)
|
803 |
+
"*([*^$|!~]?=)" + whitespace +
|
804 |
+
// "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
|
805 |
+
"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
|
806 |
+
"*\\]",
|
807 |
+
|
808 |
+
pseudos = ":(" + identifier + ")(?:\\((" +
|
809 |
+
// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
|
810 |
+
// 1. quoted (capture 3; capture 4 or capture 5)
|
811 |
+
"('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
|
812 |
+
// 2. simple (capture 6)
|
813 |
+
"((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
|
814 |
+
// 3. anything else (capture 2)
|
815 |
+
".*" +
|
816 |
+
")\\)|)",
|
817 |
+
|
818 |
+
// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
|
819 |
+
rwhitespace = new RegExp( whitespace + "+", "g" ),
|
820 |
+
rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
|
821 |
+
|
822 |
+
rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
|
823 |
+
rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
|
824 |
+
|
825 |
+
rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
|
826 |
+
|
827 |
+
rpseudo = new RegExp( pseudos ),
|
828 |
+
ridentifier = new RegExp( "^" + identifier + "$" ),
|
829 |
+
|
830 |
+
matchExpr = {
|
831 |
+
"ID": new RegExp( "^#(" + identifier + ")" ),
|
832 |
+
"CLASS": new RegExp( "^\\.(" + identifier + ")" ),
|
833 |
+
"TAG": new RegExp( "^(" + identifier + "|[*])" ),
|
834 |
+
"ATTR": new RegExp( "^" + attributes ),
|
835 |
+
"PSEUDO": new RegExp( "^" + pseudos ),
|
836 |
+
"CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
|
837 |
+
"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
|
838 |
+
"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
|
839 |
+
"bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
|
840 |
+
// For use in libraries implementing .is()
|
841 |
+
// We use this for POS matching in `select`
|
842 |
+
"needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
|
843 |
+
whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
|
844 |
+
},
|
845 |
+
|
846 |
+
rinputs = /^(?:input|select|textarea|button)$/i,
|
847 |
+
rheader = /^h\d$/i,
|
848 |
+
|
849 |
+
rnative = /^[^{]+\{\s*\[native \w/,
|
850 |
+
|
851 |
+
// Easily-parseable/retrievable ID or TAG or CLASS selectors
|
852 |
+
rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
|
853 |
+
|
854 |
+
rsibling = /[+~]/,
|
855 |
+
|
856 |
+
// CSS escapes
|
857 |
+
// http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
|
858 |
+
runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
|
859 |
+
funescape = function( _, escaped, escapedWhitespace ) {
|
860 |
+
var high = "0x" + escaped - 0x10000;
|
861 |
+
// NaN means non-codepoint
|
862 |
+
// Support: Firefox<24
|
863 |
+
// Workaround erroneous numeric interpretation of +"0x"
|
864 |
+
return high !== high || escapedWhitespace ?
|
865 |
+
escaped :
|
866 |
+
high < 0 ?
|
867 |
+
// BMP codepoint
|
868 |
+
String.fromCharCode( high + 0x10000 ) :
|
869 |
+
// Supplemental Plane codepoint (surrogate pair)
|
870 |
+
String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
|
871 |
+
},
|
872 |
+
|
873 |
+
// CSS string/identifier serialization
|
874 |
+
// https://drafts.csswg.org/cssom/#common-serializing-idioms
|
875 |
+
rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,
|
876 |
+
fcssescape = function( ch, asCodePoint ) {
|
877 |
+
if ( asCodePoint ) {
|
878 |
+
|
879 |
+
// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
|
880 |
+
if ( ch === "\0" ) {
|
881 |
+
return "\uFFFD";
|
882 |
+
}
|
883 |
+
|
884 |
+
// Control characters and (dependent upon position) numbers get escaped as code points
|
885 |
+
return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
|
886 |
+
}
|
887 |
+
|
888 |
+
// Other potentially-special ASCII characters get backslash-escaped
|
889 |
+
return "\\" + ch;
|
890 |
+
},
|
891 |
+
|
892 |
+
// Used for iframes
|
893 |
+
// See setDocument()
|
894 |
+
// Removing the function wrapper causes a "Permission Denied"
|
895 |
+
// error in IE
|
896 |
+
unloadHandler = function() {
|
897 |
+
setDocument();
|
898 |
+
},
|
899 |
+
|
900 |
+
disabledAncestor = addCombinator(
|
901 |
+
function( elem ) {
|
902 |
+
return elem.disabled === true && ("form" in elem || "label" in elem);
|
903 |
+
},
|
904 |
+
{ dir: "parentNode", next: "legend" }
|
905 |
+
);
|
906 |
+
|
907 |
+
// Optimize for push.apply( _, NodeList )
|
908 |
+
try {
|
909 |
+
push.apply(
|
910 |
+
(arr = slice.call( preferredDoc.childNodes )),
|
911 |
+
preferredDoc.childNodes
|
912 |
+
);
|
913 |
+
// Support: Android<4.0
|
914 |
+
// Detect silently failing push.apply
|
915 |
+
arr[ preferredDoc.childNodes.length ].nodeType;
|
916 |
+
} catch ( e ) {
|
917 |
+
push = { apply: arr.length ?
|
918 |
+
|
919 |
+
// Leverage slice if possible
|
920 |
+
function( target, els ) {
|
921 |
+
push_native.apply( target, slice.call(els) );
|
922 |
+
} :
|
923 |
+
|
924 |
+
// Support: IE<9
|
925 |
+
// Otherwise append directly
|
926 |
+
function( target, els ) {
|
927 |
+
var j = target.length,
|
928 |
+
i = 0;
|
929 |
+
// Can't trust NodeList.length
|
930 |
+
while ( (target[j++] = els[i++]) ) {}
|
931 |
+
target.length = j - 1;
|
932 |
+
}
|
933 |
+
};
|
934 |
+
}
|
935 |
+
|
936 |
+
function Sizzle( selector, context, results, seed ) {
|
937 |
+
var m, i, elem, nid, match, groups, newSelector,
|
938 |
+
newContext = context && context.ownerDocument,
|
939 |
+
|
940 |
+
// nodeType defaults to 9, since context defaults to document
|
941 |
+
nodeType = context ? context.nodeType : 9;
|
942 |
+
|
943 |
+
results = results || [];
|
944 |
+
|
945 |
+
// Return early from calls with invalid selector or context
|
946 |
+
if ( typeof selector !== "string" || !selector ||
|
947 |
+
nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
|
948 |
+
|
949 |
+
return results;
|
950 |
+
}
|
951 |
+
|
952 |
+
// Try to shortcut find operations (as opposed to filters) in HTML documents
|
953 |
+
if ( !seed ) {
|
954 |
+
|
955 |
+
if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
|
956 |
+
setDocument( context );
|
957 |
+
}
|
958 |
+
context = context || document;
|
959 |
+
|
960 |
+
if ( documentIsHTML ) {
|
961 |
+
|
962 |
+
// If the selector is sufficiently simple, try using a "get*By*" DOM method
|
963 |
+
// (excepting DocumentFragment context, where the methods don't exist)
|
964 |
+
if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
|
965 |
+
|
966 |
+
// ID selector
|
967 |
+
if ( (m = match[1]) ) {
|
968 |
+
|
969 |
+
// Document context
|
970 |
+
if ( nodeType === 9 ) {
|
971 |
+
if ( (elem = context.getElementById( m )) ) {
|
972 |
+
|
973 |
+
// Support: IE, Opera, Webkit
|
974 |
+
// TODO: identify versions
|
975 |
+
// getElementById can match elements by name instead of ID
|
976 |
+
if ( elem.id === m ) {
|
977 |
+
results.push( elem );
|
978 |
+
return results;
|
979 |
+
}
|
980 |
+
} else {
|
981 |
+
return results;
|
982 |
+
}
|
983 |
+
|
984 |
+
// Element context
|
985 |
+
} else {
|
986 |
+
|
987 |
+
// Support: IE, Opera, Webkit
|
988 |
+
// TODO: identify versions
|
989 |
+
// getElementById can match elements by name instead of ID
|
990 |
+
if ( newContext && (elem = newContext.getElementById( m )) &&
|
991 |
+
contains( context, elem ) &&
|
992 |
+
elem.id === m ) {
|
993 |
+
|
994 |
+
results.push( elem );
|
995 |
+
return results;
|
996 |
+
}
|
997 |
+
}
|
998 |
+
|
999 |
+
// Type selector
|
1000 |
+
} else if ( match[2] ) {
|
1001 |
+
push.apply( results, context.getElementsByTagName( selector ) );
|
1002 |
+
return results;
|
1003 |
+
|
1004 |
+
// Class selector
|
1005 |
+
} else if ( (m = match[3]) && support.getElementsByClassName &&
|
1006 |
+
context.getElementsByClassName ) {
|
1007 |
+
|
1008 |
+
push.apply( results, context.getElementsByClassName( m ) );
|
1009 |
+
return results;
|
1010 |
+
}
|
1011 |
+
}
|
1012 |
+
|
1013 |
+
// Take advantage of querySelectorAll
|
1014 |
+
if ( support.qsa &&
|
1015 |
+
!compilerCache[ selector + " " ] &&
|
1016 |
+
(!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
|
1017 |
+
|
1018 |
+
if ( nodeType !== 1 ) {
|
1019 |
+
newContext = context;
|
1020 |
+
newSelector = selector;
|
1021 |
+
|
1022 |
+
// qSA looks outside Element context, which is not what we want
|
1023 |
+
// Thanks to Andrew Dupont for this workaround technique
|
1024 |
+
// Support: IE <=8
|
1025 |
+
// Exclude object elements
|
1026 |
+
} else if ( context.nodeName.toLowerCase() !== "object" ) {
|
1027 |
+
|
1028 |
+
// Capture the context ID, setting it first if necessary
|
1029 |
+
if ( (nid = context.getAttribute( "id" )) ) {
|
1030 |
+
nid = nid.replace( rcssescape, fcssescape );
|
1031 |
+
} else {
|
1032 |
+
context.setAttribute( "id", (nid = expando) );
|
1033 |
+
}
|
1034 |
+
|
1035 |
+
// Prefix every selector in the list
|
1036 |
+
groups = tokenize( selector );
|
1037 |
+
i = groups.length;
|
1038 |
+
while ( i-- ) {
|
1039 |
+
groups[i] = "#" + nid + " " + toSelector( groups[i] );
|
1040 |
+
}
|
1041 |
+
newSelector = groups.join( "," );
|
1042 |
+
|
1043 |
+
// Expand context for sibling selectors
|
1044 |
+
newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
|
1045 |
+
context;
|
1046 |
+
}
|
1047 |
+
|
1048 |
+
if ( newSelector ) {
|
1049 |
+
try {
|
1050 |
+
push.apply( results,
|
1051 |
+
newContext.querySelectorAll( newSelector )
|
1052 |
+
);
|
1053 |
+
return results;
|
1054 |
+
} catch ( qsaError ) {
|
1055 |
+
} finally {
|
1056 |
+
if ( nid === expando ) {
|
1057 |
+
context.removeAttribute( "id" );
|
1058 |
+
}
|
1059 |
+
}
|
1060 |
+
}
|
1061 |
+
}
|
1062 |
+
}
|
1063 |
+
}
|
1064 |
+
|
1065 |
+
// All others
|
1066 |
+
return select( selector.replace( rtrim, "$1" ), context, results, seed );
|
1067 |
+
}
|
1068 |
+
|
1069 |
+
/**
|
1070 |
+
* Create key-value caches of limited size
|
1071 |
+
* @returns {function(string, object)} Returns the Object data after storing it on itself with
|
1072 |
+
* property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
|
1073 |
+
* deleting the oldest entry
|
1074 |
+
*/
|
1075 |
+
function createCache() {
|
1076 |
+
var keys = [];
|
1077 |
+
|
1078 |
+
function cache( key, value ) {
|
1079 |
+
// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
|
1080 |
+
if ( keys.push( key + " " ) > Expr.cacheLength ) {
|
1081 |
+
// Only keep the most recent entries
|
1082 |
+
delete cache[ keys.shift() ];
|
1083 |
+
}
|
1084 |
+
return (cache[ key + " " ] = value);
|
1085 |
+
}
|
1086 |
+
return cache;
|
1087 |
+
}
|
1088 |
+
|
1089 |
+
/**
|
1090 |
+
* Mark a function for special use by Sizzle
|
1091 |
+
* @param {Function} fn The function to mark
|
1092 |
+
*/
|
1093 |
+
function markFunction( fn ) {
|
1094 |
+
fn[ expando ] = true;
|
1095 |
+
return fn;
|
1096 |
+
}
|
1097 |
+
|
1098 |
+
/**
|
1099 |
+
* Support testing using an element
|
1100 |
+
* @param {Function} fn Passed the created element and returns a boolean result
|
1101 |
+
*/
|
1102 |
+
function assert( fn ) {
|
1103 |
+
var el = document.createElement("fieldset");
|
1104 |
+
|
1105 |
+
try {
|
1106 |
+
return !!fn( el );
|
1107 |
+
} catch (e) {
|
1108 |
+
return false;
|
1109 |
+
} finally {
|
1110 |
+
// Remove from its parent by default
|
1111 |
+
if ( el.parentNode ) {
|
1112 |
+
el.parentNode.removeChild( el );
|
1113 |
+
}
|
1114 |
+
// release memory in IE
|
1115 |
+
el = null;
|
1116 |
+
}
|
1117 |
+
}
|
1118 |
+
|
1119 |
+
/**
|
1120 |
+
* Adds the same handler for all of the specified attrs
|
1121 |
+
* @param {String} attrs Pipe-separated list of attributes
|
1122 |
+
* @param {Function} handler The method that will be applied
|
1123 |
+
*/
|
1124 |
+
function addHandle( attrs, handler ) {
|
1125 |
+
var arr = attrs.split("|"),
|
1126 |
+
i = arr.length;
|
1127 |
+
|
1128 |
+
while ( i-- ) {
|
1129 |
+
Expr.attrHandle[ arr[i] ] = handler;
|
1130 |
+
}
|
1131 |
+
}
|
1132 |
+
|
1133 |
+
/**
|
1134 |
+
* Checks document order of two siblings
|
1135 |
+
* @param {Element} a
|
1136 |
+
* @param {Element} b
|
1137 |
+
* @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
|
1138 |
+
*/
|
1139 |
+
function siblingCheck( a, b ) {
|
1140 |
+
var cur = b && a,
|
1141 |
+
diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
|
1142 |
+
a.sourceIndex - b.sourceIndex;
|
1143 |
+
|
1144 |
+
// Use IE sourceIndex if available on both nodes
|
1145 |
+
if ( diff ) {
|
1146 |
+
return diff;
|
1147 |
+
}
|
1148 |
+
|
1149 |
+
// Check if b follows a
|
1150 |
+
if ( cur ) {
|
1151 |
+
while ( (cur = cur.nextSibling) ) {
|
1152 |
+
if ( cur === b ) {
|
1153 |
+
return -1;
|
1154 |
+
}
|
1155 |
+
}
|
1156 |
+
}
|
1157 |
+
|
1158 |
+
return a ? 1 : -1;
|
1159 |
+
}
|
1160 |
+
|
1161 |
+
/**
|
1162 |
+
* Returns a function to use in pseudos for input types
|
1163 |
+
* @param {String} type
|
1164 |
+
*/
|
1165 |
+
function createInputPseudo( type ) {
|
1166 |
+
return function( elem ) {
|
1167 |
+
var name = elem.nodeName.toLowerCase();
|
1168 |
+
return name === "input" && elem.type === type;
|
1169 |
+
};
|
1170 |
+
}
|
1171 |
+
|
1172 |
+
/**
|
1173 |
+
* Returns a function to use in pseudos for buttons
|
1174 |
+
* @param {String} type
|
1175 |
+
*/
|
1176 |
+
function createButtonPseudo( type ) {
|
1177 |
+
return function( elem ) {
|
1178 |
+
var name = elem.nodeName.toLowerCase();
|
1179 |
+
return (name === "input" || name === "button") && elem.type === type;
|
1180 |
+
};
|
1181 |
+
}
|
1182 |
+
|
1183 |
+
/**
|
1184 |
+
* Returns a function to use in pseudos for :enabled/:disabled
|
1185 |
+
* @param {Boolean} disabled true for :disabled; false for :enabled
|
1186 |
+
*/
|
1187 |
+
function createDisabledPseudo( disabled ) {
|
1188 |
+
|
1189 |
+
// Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable
|
1190 |
+
return function( elem ) {
|
1191 |
+
|
1192 |
+
// Only certain elements can match :enabled or :disabled
|
1193 |
+
// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled
|
1194 |
+
// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled
|
1195 |
+
if ( "form" in elem ) {
|
1196 |
+
|
1197 |
+
// Check for inherited disabledness on relevant non-disabled elements:
|
1198 |
+
// * listed form-associated elements in a disabled fieldset
|
1199 |
+
// https://html.spec.whatwg.org/multipage/forms.html#category-listed
|
1200 |
+
// https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled
|
1201 |
+
// * option elements in a disabled optgroup
|
1202 |
+
// https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled
|
1203 |
+
// All such elements have a "form" property.
|
1204 |
+
if ( elem.parentNode && elem.disabled === false ) {
|
1205 |
+
|
1206 |
+
// Option elements defer to a parent optgroup if present
|
1207 |
+
if ( "label" in elem ) {
|
1208 |
+
if ( "label" in elem.parentNode ) {
|
1209 |
+
return elem.parentNode.disabled === disabled;
|
1210 |
+
} else {
|
1211 |
+
return elem.disabled === disabled;
|
1212 |
+
}
|
1213 |
+
}
|
1214 |
+
|
1215 |
+
// Support: IE 6 - 11
|
1216 |
+
// Use the isDisabled shortcut property to check for disabled fieldset ancestors
|
1217 |
+
return elem.isDisabled === disabled ||
|
1218 |
+
|
1219 |
+
// Where there is no isDisabled, check manually
|
1220 |
+
/* jshint -W018 */
|
1221 |
+
elem.isDisabled !== !disabled &&
|
1222 |
+
disabledAncestor( elem ) === disabled;
|
1223 |
+
}
|
1224 |
+
|
1225 |
+
return elem.disabled === disabled;
|
1226 |
+
|
1227 |
+
// Try to winnow out elements that can't be disabled before trusting the disabled property.
|
1228 |
+
// Some victims get caught in our net (label, legend, menu, track), but it shouldn't
|
1229 |
+
// even exist on them, let alone have a boolean value.
|
1230 |
+
} else if ( "label" in elem ) {
|
1231 |
+
return elem.disabled === disabled;
|
1232 |
+
}
|
1233 |
+
|
1234 |
+
// Remaining elements are neither :enabled nor :disabled
|
1235 |
+
return false;
|
1236 |
+
};
|
1237 |
+
}
|
1238 |
+
|
1239 |
+
/**
|
1240 |
+
* Returns a function to use in pseudos for positionals
|
1241 |
+
* @param {Function} fn
|
1242 |
+
*/
|
1243 |
+
function createPositionalPseudo( fn ) {
|
1244 |
+
return markFunction(function( argument ) {
|
1245 |
+
argument = +argument;
|
1246 |
+
return markFunction(function( seed, matches ) {
|
1247 |
+
var j,
|
1248 |
+
matchIndexes = fn( [], seed.length, argument ),
|
1249 |
+
i = matchIndexes.length;
|
1250 |
+
|
1251 |
+
// Match elements found at the specified indexes
|
1252 |
+
while ( i-- ) {
|
1253 |
+
if ( seed[ (j = matchIndexes[i]) ] ) {
|
1254 |
+
seed[j] = !(matches[j] = seed[j]);
|
1255 |
+
}
|
1256 |
+
}
|
1257 |
+
});
|
1258 |
+
});
|
1259 |
+
}
|
1260 |
+
|
1261 |
+
/**
|
1262 |
+
* Checks a node for validity as a Sizzle context
|
1263 |
+
* @param {Element|Object=} context
|
1264 |
+
* @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
|
1265 |
+
*/
|
1266 |
+
function testContext( context ) {
|
1267 |
+
return context && typeof context.getElementsByTagName !== "undefined" && context;
|
1268 |
+
}
|
1269 |
+
|
1270 |
+
// Expose support vars for convenience
|
1271 |
+
support = Sizzle.support = {};
|
1272 |
+
|
1273 |
+
/**
|
1274 |
+
* Detects XML nodes
|
1275 |
+
* @param {Element|Object} elem An element or a document
|
1276 |
+
* @returns {Boolean} True iff elem is a non-HTML XML node
|
1277 |
+
*/
|
1278 |
+
isXML = Sizzle.isXML = function( elem ) {
|
1279 |
+
// documentElement is verified for cases where it doesn't yet exist
|
1280 |
+
// (such as loading iframes in IE - #4833)
|
1281 |
+
var documentElement = elem && (elem.ownerDocument || elem).documentElement;
|
1282 |
+
return documentElement ? documentElement.nodeName !== "HTML" : false;
|
1283 |
+
};
|
1284 |
+
|
1285 |
+
/**
|
1286 |
+
* Sets document-related variables once based on the current document
|
1287 |
+
* @param {Element|Object} [doc] An element or document object to use to set the document
|
1288 |
+
* @returns {Object} Returns the current document
|
1289 |
+
*/
|
1290 |
+
setDocument = Sizzle.setDocument = function( node ) {
|
1291 |
+
var hasCompare, subWindow,
|
1292 |
+
doc = node ? node.ownerDocument || node : preferredDoc;
|
1293 |
+
|
1294 |
+
// Return early if doc is invalid or already selected
|
1295 |
+
if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
|
1296 |
+
return document;
|
1297 |
+
}
|
1298 |
+
|
1299 |
+
// Update global variables
|
1300 |
+
document = doc;
|
1301 |
+
docElem = document.documentElement;
|
1302 |
+
documentIsHTML = !isXML( document );
|
1303 |
+
|
1304 |
+
// Support: IE 9-11, Edge
|
1305 |
+
// Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
|
1306 |
+
if ( preferredDoc !== document &&
|
1307 |
+
(subWindow = document.defaultView) && subWindow.top !== subWindow ) {
|
1308 |
+
|
1309 |
+
// Support: IE 11, Edge
|
1310 |
+
if ( subWindow.addEventListener ) {
|
1311 |
+
subWindow.addEventListener( "unload", unloadHandler, false );
|
1312 |
+
|
1313 |
+
// Support: IE 9 - 10 only
|
1314 |
+
} else if ( subWindow.attachEvent ) {
|
1315 |
+
subWindow.attachEvent( "onunload", unloadHandler );
|
1316 |
+
}
|
1317 |
+
}
|
1318 |
+
|
1319 |
+
/* Attributes
|
1320 |
+
---------------------------------------------------------------------- */
|
1321 |
+
|
1322 |
+
// Support: IE<8
|
1323 |
+
// Verify that getAttribute really returns attributes and not properties
|
1324 |
+
// (excepting IE8 booleans)
|
1325 |
+
support.attributes = assert(function( el ) {
|
1326 |
+
el.className = "i";
|
1327 |
+
return !el.getAttribute("className");
|
1328 |
+
});
|
1329 |
+
|
1330 |
+
/* getElement(s)By*
|
1331 |
+
---------------------------------------------------------------------- */
|
1332 |
+
|
1333 |
+
// Check if getElementsByTagName("*") returns only elements
|
1334 |
+
support.getElementsByTagName = assert(function( el ) {
|
1335 |
+
el.appendChild( document.createComment("") );
|
1336 |
+
return !el.getElementsByTagName("*").length;
|
1337 |
+
});
|
1338 |
+
|
1339 |
+
// Support: IE<9
|
1340 |
+
support.getElementsByClassName = rnative.test( document.getElementsByClassName );
|
1341 |
+
|
1342 |
+
// Support: IE<10
|
1343 |
+
// Check if getElementById returns elements by name
|
1344 |
+
// The broken getElementById methods don't pick up programmatically-set names,
|
1345 |
+
// so use a roundabout getElementsByName test
|
1346 |
+
support.getById = assert(function( el ) {
|
1347 |
+
docElem.appendChild( el ).id = expando;
|
1348 |
+
return !document.getElementsByName || !document.getElementsByName( expando ).length;
|
1349 |
+
});
|
1350 |
+
|
1351 |
+
// ID filter and find
|
1352 |
+
if ( support.getById ) {
|
1353 |
+
Expr.filter["ID"] = function( id ) {
|
1354 |
+
var attrId = id.replace( runescape, funescape );
|
1355 |
+
return function( elem ) {
|
1356 |
+
return elem.getAttribute("id") === attrId;
|
1357 |
+
};
|
1358 |
+
};
|
1359 |
+
Expr.find["ID"] = function( id, context ) {
|
1360 |
+
if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
|
1361 |
+
var elem = context.getElementById( id );
|
1362 |
+
return elem ? [ elem ] : [];
|
1363 |
+
}
|
1364 |
+
};
|
1365 |
+
} else {
|
1366 |
+
Expr.filter["ID"] = function( id ) {
|
1367 |
+
var attrId = id.replace( runescape, funescape );
|
1368 |
+
return function( elem ) {
|
1369 |
+
var node = typeof elem.getAttributeNode !== "undefined" &&
|
1370 |
+
elem.getAttributeNode("id");
|
1371 |
+
return node && node.value === attrId;
|
1372 |
+
};
|
1373 |
+
};
|
1374 |
+
|
1375 |
+
// Support: IE 6 - 7 only
|
1376 |
+
// getElementById is not reliable as a find shortcut
|
1377 |
+
Expr.find["ID"] = function( id, context ) {
|
1378 |
+
if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
|
1379 |
+
var node, i, elems,
|
1380 |
+
elem = context.getElementById( id );
|
1381 |
+
|
1382 |
+
if ( elem ) {
|
1383 |
+
|
1384 |
+
// Verify the id attribute
|
1385 |
+
node = elem.getAttributeNode("id");
|
1386 |
+
if ( node && node.value === id ) {
|
1387 |
+
return [ elem ];
|
1388 |
+
}
|
1389 |
+
|
1390 |
+
// Fall back on getElementsByName
|
1391 |
+
elems = context.getElementsByName( id );
|
1392 |
+
i = 0;
|
1393 |
+
while ( (elem = elems[i++]) ) {
|
1394 |
+
node = elem.getAttributeNode("id");
|
1395 |
+
if ( node && node.value === id ) {
|
1396 |
+
return [ elem ];
|
1397 |
+
}
|
1398 |
+
}
|
1399 |
+
}
|
1400 |
+
|
1401 |
+
return [];
|
1402 |
+
}
|
1403 |
+
};
|
1404 |
+
}
|
1405 |
+
|
1406 |
+
// Tag
|
1407 |
+
Expr.find["TAG"] = support.getElementsByTagName ?
|
1408 |
+
function( tag, context ) {
|
1409 |
+
if ( typeof context.getElementsByTagName !== "undefined" ) {
|
1410 |
+
return context.getElementsByTagName( tag );
|
1411 |
+
|
1412 |
+
// DocumentFragment nodes don't have gEBTN
|
1413 |
+
} else if ( support.qsa ) {
|
1414 |
+
return context.querySelectorAll( tag );
|
1415 |
+
}
|
1416 |
+
} :
|
1417 |
+
|
1418 |
+
function( tag, context ) {
|
1419 |
+
var elem,
|
1420 |
+
tmp = [],
|
1421 |
+
i = 0,
|
1422 |
+
// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
|
1423 |
+
results = context.getElementsByTagName( tag );
|
1424 |
+
|
1425 |
+
// Filter out possible comments
|
1426 |
+
if ( tag === "*" ) {
|
1427 |
+
while ( (elem = results[i++]) ) {
|
1428 |
+
if ( elem.nodeType === 1 ) {
|
1429 |
+
tmp.push( elem );
|
1430 |
+
}
|
1431 |
+
}
|
1432 |
+
|
1433 |
+
return tmp;
|
1434 |
+
}
|
1435 |
+
return results;
|
1436 |
+
};
|
1437 |
+
|
1438 |
+
// Class
|
1439 |
+
Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
|
1440 |
+
if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
|
1441 |
+
return context.getElementsByClassName( className );
|
1442 |
+
}
|
1443 |
+
};
|
1444 |
+
|
1445 |
+
/* QSA/matchesSelector
|
1446 |
+
---------------------------------------------------------------------- */
|
1447 |
+
|
1448 |
+
// QSA and matchesSelector support
|
1449 |
+
|
1450 |
+
// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
|
1451 |
+
rbuggyMatches = [];
|
1452 |
+
|
1453 |
+
// qSa(:focus) reports false when true (Chrome 21)
|
1454 |
+
// We allow this because of a bug in IE8/9 that throws an error
|
1455 |
+
// whenever `document.activeElement` is accessed on an iframe
|
1456 |
+
// So, we allow :focus to pass through QSA all the time to avoid the IE error
|
1457 |
+
// See https://bugs.jquery.com/ticket/13378
|
1458 |
+
rbuggyQSA = [];
|
1459 |
+
|
1460 |
+
if ( (support.qsa = rnative.test( document.querySelectorAll )) ) {
|
1461 |
+
// Build QSA regex
|
1462 |
+
// Regex strategy adopted from Diego Perini
|
1463 |
+
assert(function( el ) {
|
1464 |
+
// Select is set to empty string on purpose
|
1465 |
+
// This is to test IE's treatment of not explicitly
|
1466 |
+
// setting a boolean content attribute,
|
1467 |
+
// since its presence should be enough
|
1468 |
+
// https://bugs.jquery.com/ticket/12359
|
1469 |
+
docElem.appendChild( el ).innerHTML = "<a id='" + expando + "'></a>" +
|
1470 |
+
"<select id='" + expando + "-\r\\' msallowcapture=''>" +
|
1471 |
+
"<option selected=''></option></select>";
|
1472 |
+
|
1473 |
+
// Support: IE8, Opera 11-12.16
|
1474 |
+
// Nothing should be selected when empty strings follow ^= or $= or *=
|
1475 |
+
// The test attribute must be unknown in Opera but "safe" for WinRT
|
1476 |
+
// https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
|
1477 |
+
if ( el.querySelectorAll("[msallowcapture^='']").length ) {
|
1478 |
+
rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
|
1479 |
+
}
|
1480 |
+
|
1481 |
+
// Support: IE8
|
1482 |
+
// Boolean attributes and "value" are not treated correctly
|
1483 |
+
if ( !el.querySelectorAll("[selected]").length ) {
|
1484 |
+
rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
|
1485 |
+
}
|
1486 |
+
|
1487 |
+
// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
|
1488 |
+
if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
|
1489 |
+
rbuggyQSA.push("~=");
|
1490 |
+
}
|
1491 |
+
|
1492 |
+
// Webkit/Opera - :checked should return selected option elements
|
1493 |
+
// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
|
1494 |
+
// IE8 throws error here and will not see later tests
|
1495 |
+
if ( !el.querySelectorAll(":checked").length ) {
|
1496 |
+
rbuggyQSA.push(":checked");
|
1497 |
+
}
|
1498 |
+
|
1499 |
+
// Support: Safari 8+, iOS 8+
|
1500 |
+
// https://bugs.webkit.org/show_bug.cgi?id=136851
|
1501 |
+
// In-page `selector#id sibling-combinator selector` fails
|
1502 |
+
if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) {
|
1503 |
+
rbuggyQSA.push(".#.+[+~]");
|
1504 |
+
}
|
1505 |
+
});
|
1506 |
+
|
1507 |
+
assert(function( el ) {
|
1508 |
+
el.innerHTML = "<a href='' disabled='disabled'></a>" +
|
1509 |
+
"<select disabled='disabled'><option/></select>";
|
1510 |
+
|
1511 |
+
// Support: Windows 8 Native Apps
|
1512 |
+
// The type and name attributes are restricted during .innerHTML assignment
|
1513 |
+
var input = document.createElement("input");
|
1514 |
+
input.setAttribute( "type", "hidden" );
|
1515 |
+
el.appendChild( input ).setAttribute( "name", "D" );
|
1516 |
+
|
1517 |
+
// Support: IE8
|
1518 |
+
// Enforce case-sensitivity of name attribute
|
1519 |
+
if ( el.querySelectorAll("[name=d]").length ) {
|
1520 |
+
rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
|
1521 |
+
}
|
1522 |
+
|
1523 |
+
// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
|
1524 |
+
// IE8 throws error here and will not see later tests
|
1525 |
+
if ( el.querySelectorAll(":enabled").length !== 2 ) {
|
1526 |
+
rbuggyQSA.push( ":enabled", ":disabled" );
|
1527 |
+
}
|
1528 |
+
|
1529 |
+
// Support: IE9-11+
|
1530 |
+
// IE's :disabled selector does not pick up the children of disabled fieldsets
|
1531 |
+
docElem.appendChild( el ).disabled = true;
|
1532 |
+
if ( el.querySelectorAll(":disabled").length !== 2 ) {
|
1533 |
+
rbuggyQSA.push( ":enabled", ":disabled" );
|
1534 |
+
}
|
1535 |
+
|
1536 |
+
// Opera 10-11 does not throw on post-comma invalid pseudos
|
1537 |
+
el.querySelectorAll("*,:x");
|
1538 |
+
rbuggyQSA.push(",.*:");
|
1539 |
+
});
|
1540 |
+
}
|
1541 |
+
|
1542 |
+
if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
|
1543 |
+
docElem.webkitMatchesSelector ||
|
1544 |
+
docElem.mozMatchesSelector ||
|
1545 |
+
docElem.oMatchesSelector ||
|
1546 |
+
docElem.msMatchesSelector) )) ) {
|
1547 |
+
|
1548 |
+
assert(function( el ) {
|
1549 |
+
// Check to see if it's possible to do matchesSelector
|
1550 |
+
// on a disconnected node (IE 9)
|
1551 |
+
support.disconnectedMatch = matches.call( el, "*" );
|
1552 |
+
|
1553 |
+
// This should fail with an exception
|
1554 |
+
// Gecko does not error, returns false instead
|
1555 |
+
matches.call( el, "[s!='']:x" );
|
1556 |
+
rbuggyMatches.push( "!=", pseudos );
|
1557 |
+
});
|
1558 |
+
}
|
1559 |
+
|
1560 |
+
rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
|
1561 |
+
rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
|
1562 |
+
|
1563 |
+
/* Contains
|
1564 |
+
---------------------------------------------------------------------- */
|
1565 |
+
hasCompare = rnative.test( docElem.compareDocumentPosition );
|
1566 |
+
|
1567 |
+
// Element contains another
|
1568 |
+
// Purposefully self-exclusive
|
1569 |
+
// As in, an element does not contain itself
|
1570 |
+
contains = hasCompare || rnative.test( docElem.contains ) ?
|
1571 |
+
function( a, b ) {
|
1572 |
+
var adown = a.nodeType === 9 ? a.documentElement : a,
|
1573 |
+
bup = b && b.parentNode;
|
1574 |
+
return a === bup || !!( bup && bup.nodeType === 1 && (
|
1575 |
+
adown.contains ?
|
1576 |
+
adown.contains( bup ) :
|
1577 |
+
a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
|
1578 |
+
));
|
1579 |
+
} :
|
1580 |
+
function( a, b ) {
|
1581 |
+
if ( b ) {
|
1582 |
+
while ( (b = b.parentNode) ) {
|
1583 |
+
if ( b === a ) {
|
1584 |
+
return true;
|
1585 |
+
}
|
1586 |
+
}
|
1587 |
+
}
|
1588 |
+
return false;
|
1589 |
+
};
|
1590 |
+
|
1591 |
+
/* Sorting
|
1592 |
+
---------------------------------------------------------------------- */
|
1593 |
+
|
1594 |
+
// Document order sorting
|
1595 |
+
sortOrder = hasCompare ?
|
1596 |
+
function( a, b ) {
|
1597 |
+
|
1598 |
+
// Flag for duplicate removal
|
1599 |
+
if ( a === b ) {
|
1600 |
+
hasDuplicate = true;
|
1601 |
+
return 0;
|
1602 |
+
}
|
1603 |
+
|
1604 |
+
// Sort on method existence if only one input has compareDocumentPosition
|
1605 |
+
var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
|
1606 |
+
if ( compare ) {
|
1607 |
+
return compare;
|
1608 |
+
}
|
1609 |
+
|
1610 |
+
// Calculate position if both inputs belong to the same document
|
1611 |
+
compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
|
1612 |
+
a.compareDocumentPosition( b ) :
|
1613 |
+
|
1614 |
+
// Otherwise we know they are disconnected
|
1615 |
+
1;
|
1616 |
+
|
1617 |
+
// Disconnected nodes
|
1618 |
+
if ( compare & 1 ||
|
1619 |
+
(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
|
1620 |
+
|
1621 |
+
// Choose the first element that is related to our preferred document
|
1622 |
+
if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
|
1623 |
+
return -1;
|
1624 |
+
}
|
1625 |
+
if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
|
1626 |
+
return 1;
|
1627 |
+
}
|
1628 |
+
|
1629 |
+
// Maintain original order
|
1630 |
+
return sortInput ?
|
1631 |
+
( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
|
1632 |
+
0;
|
1633 |
+
}
|
1634 |
+
|
1635 |
+
return compare & 4 ? -1 : 1;
|
1636 |
+
} :
|
1637 |
+
function( a, b ) {
|
1638 |
+
// Exit early if the nodes are identical
|
1639 |
+
if ( a === b ) {
|
1640 |
+
hasDuplicate = true;
|
1641 |
+
return 0;
|
1642 |
+
}
|
1643 |
+
|
1644 |
+
var cur,
|
1645 |
+
i = 0,
|
1646 |
+
aup = a.parentNode,
|
1647 |
+
bup = b.parentNode,
|
1648 |
+
ap = [ a ],
|
1649 |
+
bp = [ b ];
|
1650 |
+
|
1651 |
+
// Parentless nodes are either documents or disconnected
|
1652 |
+
if ( !aup || !bup ) {
|
1653 |
+
return a === document ? -1 :
|
1654 |
+
b === document ? 1 :
|
1655 |
+
aup ? -1 :
|
1656 |
+
bup ? 1 :
|
1657 |
+
sortInput ?
|
1658 |
+
( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
|
1659 |
+
0;
|
1660 |
+
|
1661 |
+
// If the nodes are siblings, we can do a quick check
|
1662 |
+
} else if ( aup === bup ) {
|
1663 |
+
return siblingCheck( a, b );
|
1664 |
+
}
|
1665 |
+
|
1666 |
+
// Otherwise we need full lists of their ancestors for comparison
|
1667 |
+
cur = a;
|
1668 |
+
while ( (cur = cur.parentNode) ) {
|
1669 |
+
ap.unshift( cur );
|
1670 |
+
}
|
1671 |
+
cur = b;
|
1672 |
+
while ( (cur = cur.parentNode) ) {
|
1673 |
+
bp.unshift( cur );
|
1674 |
+
}
|
1675 |
+
|
1676 |
+
// Walk down the tree looking for a discrepancy
|
1677 |
+
while ( ap[i] === bp[i] ) {
|
1678 |
+
i++;
|
1679 |
+
}
|
1680 |
+
|
1681 |
+
return i ?
|
1682 |
+
// Do a sibling check if the nodes have a common ancestor
|
1683 |
+
siblingCheck( ap[i], bp[i] ) :
|
1684 |
+
|
1685 |
+
// Otherwise nodes in our document sort first
|
1686 |
+
ap[i] === preferredDoc ? -1 :
|
1687 |
+
bp[i] === preferredDoc ? 1 :
|
1688 |
+
0;
|
1689 |
+
};
|
1690 |
+
|
1691 |
+
return document;
|
1692 |
+
};
|
1693 |
+
|
1694 |
+
Sizzle.matches = function( expr, elements ) {
|
1695 |
+
return Sizzle( expr, null, null, elements );
|
1696 |
+
};
|
1697 |
+
|
1698 |
+
Sizzle.matchesSelector = function( elem, expr ) {
|
1699 |
+
// Set document vars if needed
|
1700 |
+
if ( ( elem.ownerDocument || elem ) !== document ) {
|
1701 |
+
setDocument( elem );
|
1702 |
+
}
|
1703 |
+
|
1704 |
+
// Make sure that attribute selectors are quoted
|
1705 |
+
expr = expr.replace( rattributeQuotes, "='$1']" );
|
1706 |
+
|
1707 |
+
if ( support.matchesSelector && documentIsHTML &&
|
1708 |
+
!compilerCache[ expr + " " ] &&
|
1709 |
+
( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
|
1710 |
+
( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
|
1711 |
+
|
1712 |
+
try {
|
1713 |
+
var ret = matches.call( elem, expr );
|
1714 |
+
|
1715 |
+
// IE 9's matchesSelector returns false on disconnected nodes
|
1716 |
+
if ( ret || support.disconnectedMatch ||
|
1717 |
+
// As well, disconnected nodes are said to be in a document
|
1718 |
+
// fragment in IE 9
|
1719 |
+
elem.document && elem.document.nodeType !== 11 ) {
|
1720 |
+
return ret;
|
1721 |
+
}
|
1722 |
+
} catch (e) {}
|
1723 |
+
}
|
1724 |
+
|
1725 |
+
return Sizzle( expr, document, null, [ elem ] ).length > 0;
|
1726 |
+
};
|
1727 |
+
|
1728 |
+
Sizzle.contains = function( context, elem ) {
|
1729 |
+
// Set document vars if needed
|
1730 |
+
if ( ( context.ownerDocument || context ) !== document ) {
|
1731 |
+
setDocument( context );
|
1732 |
+
}
|
1733 |
+
return contains( context, elem );
|
1734 |
+
};
|
1735 |
+
|
1736 |
+
Sizzle.attr = function( elem, name ) {
|
1737 |
+
// Set document vars if needed
|
1738 |
+
if ( ( elem.ownerDocument || elem ) !== document ) {
|
1739 |
+
setDocument( elem );
|
1740 |
+
}
|
1741 |
+
|
1742 |
+
var fn = Expr.attrHandle[ name.toLowerCase() ],
|
1743 |
+
// Don't get fooled by Object.prototype properties (jQuery #13807)
|
1744 |
+
val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
|
1745 |
+
fn( elem, name, !documentIsHTML ) :
|
1746 |
+
undefined;
|
1747 |
+
|
1748 |
+
return val !== undefined ?
|
1749 |
+
val :
|
1750 |
+
support.attributes || !documentIsHTML ?
|
1751 |
+
elem.getAttribute( name ) :
|
1752 |
+
(val = elem.getAttributeNode(name)) && val.specified ?
|
1753 |
+
val.value :
|
1754 |
+
null;
|
1755 |
+
};
|
1756 |
+
|
1757 |
+
Sizzle.escape = function( sel ) {
|
1758 |
+
return (sel + "").replace( rcssescape, fcssescape );
|
1759 |
+
};
|
1760 |
+
|
1761 |
+
Sizzle.error = function( msg ) {
|
1762 |
+
throw new Error( "Syntax error, unrecognized expression: " + msg );
|
1763 |
+
};
|
1764 |
+
|
1765 |
+
/**
|
1766 |
+
* Document sorting and removing duplicates
|
1767 |
+
* @param {ArrayLike} results
|
1768 |
+
*/
|
1769 |
+
Sizzle.uniqueSort = function( results ) {
|
1770 |
+
var elem,
|
1771 |
+
duplicates = [],
|
1772 |
+
j = 0,
|
1773 |
+
i = 0;
|
1774 |
+
|
1775 |
+
// Unless we *know* we can detect duplicates, assume their presence
|
1776 |
+
hasDuplicate = !support.detectDuplicates;
|
1777 |
+
sortInput = !support.sortStable && results.slice( 0 );
|
1778 |
+
results.sort( sortOrder );
|
1779 |
+
|
1780 |
+
if ( hasDuplicate ) {
|
1781 |
+
while ( (elem = results[i++]) ) {
|
1782 |
+
if ( elem === results[ i ] ) {
|
1783 |
+
j = duplicates.push( i );
|
1784 |
+
}
|
1785 |
+
}
|
1786 |
+
while ( j-- ) {
|
1787 |
+
results.splice( duplicates[ j ], 1 );
|
1788 |
+
}
|
1789 |
+
}
|
1790 |
+
|
1791 |
+
// Clear input after sorting to release objects
|
1792 |
+
// See https://github.com/jquery/sizzle/pull/225
|
1793 |
+
sortInput = null;
|
1794 |
+
|
1795 |
+
return results;
|
1796 |
+
};
|
1797 |
+
|
1798 |
+
/**
|
1799 |
+
* Utility function for retrieving the text value of an array of DOM nodes
|
1800 |
+
* @param {Array|Element} elem
|
1801 |
+
*/
|
1802 |
+
getText = Sizzle.getText = function( elem ) {
|
1803 |
+
var node,
|
1804 |
+
ret = "",
|
1805 |
+
i = 0,
|
1806 |
+
nodeType = elem.nodeType;
|
1807 |
+
|
1808 |
+
if ( !nodeType ) {
|
1809 |
+
// If no nodeType, this is expected to be an array
|
1810 |
+
while ( (node = elem[i++]) ) {
|
1811 |
+
// Do not traverse comment nodes
|
1812 |
+
ret += getText( node );
|
1813 |
+
}
|
1814 |
+
} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
|
1815 |
+
// Use textContent for elements
|
1816 |
+
// innerText usage removed for consistency of new lines (jQuery #11153)
|
1817 |
+
if ( typeof elem.textContent === "string" ) {
|
1818 |
+
return elem.textContent;
|
1819 |
+
} else {
|
1820 |
+
// Traverse its children
|
1821 |
+
for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
|
1822 |
+
ret += getText( elem );
|
1823 |
+
}
|
1824 |
+
}
|
1825 |
+
} else if ( nodeType === 3 || nodeType === 4 ) {
|
1826 |
+
return elem.nodeValue;
|
1827 |
+
}
|
1828 |
+
// Do not include comment or processing instruction nodes
|
1829 |
+
|
1830 |
+
return ret;
|
1831 |
+
};
|
1832 |
+
|
1833 |
+
Expr = Sizzle.selectors = {
|
1834 |
+
|
1835 |
+
// Can be adjusted by the user
|
1836 |
+
cacheLength: 50,
|
1837 |
+
|
1838 |
+
createPseudo: markFunction,
|
1839 |
+
|
1840 |
+
match: matchExpr,
|
1841 |
+
|
1842 |
+
attrHandle: {},
|
1843 |
+
|
1844 |
+
find: {},
|
1845 |
+
|
1846 |
+
relative: {
|
1847 |
+
">": { dir: "parentNode", first: true },
|
1848 |
+
" ": { dir: "parentNode" },
|
1849 |
+
"+": { dir: "previousSibling", first: true },
|
1850 |
+
"~": { dir: "previousSibling" }
|
1851 |
+
},
|
1852 |
+
|
1853 |
+
preFilter: {
|
1854 |
+
"ATTR": function( match ) {
|
1855 |
+
match[1] = match[1].replace( runescape, funescape );
|
1856 |
+
|
1857 |
+
// Move the given value to match[3] whether quoted or unquoted
|
1858 |
+
match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
|
1859 |
+
|
1860 |
+
if ( match[2] === "~=" ) {
|
1861 |
+
match[3] = " " + match[3] + " ";
|
1862 |
+
}
|
1863 |
+
|
1864 |
+
return match.slice( 0, 4 );
|
1865 |
+
},
|
1866 |
+
|
1867 |
+
"CHILD": function( match ) {
|
1868 |
+
/* matches from matchExpr["CHILD"]
|
1869 |
+
1 type (only|nth|...)
|
1870 |
+
2 what (child|of-type)
|
1871 |
+
3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
|
1872 |
+
4 xn-component of xn+y argument ([+-]?\d*n|)
|
1873 |
+
5 sign of xn-component
|
1874 |
+
6 x of xn-component
|
1875 |
+
7 sign of y-component
|
1876 |
+
8 y of y-component
|
1877 |
+
*/
|
1878 |
+
match[1] = match[1].toLowerCase();
|
1879 |
+
|
1880 |
+
if ( match[1].slice( 0, 3 ) === "nth" ) {
|
1881 |
+
// nth-* requires argument
|
1882 |
+
if ( !match[3] ) {
|
1883 |
+
Sizzle.error( match[0] );
|
1884 |
+
}
|
1885 |
+
|
1886 |
+
// numeric x and y parameters for Expr.filter.CHILD
|
1887 |
+
// remember that false/true cast respectively to 0/1
|
1888 |
+
match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
|
1889 |
+
match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
|
1890 |
+
|
1891 |
+
// other types prohibit arguments
|
1892 |
+
} else if ( match[3] ) {
|
1893 |
+
Sizzle.error( match[0] );
|
1894 |
+
}
|
1895 |
+
|
1896 |
+
return match;
|
1897 |
+
},
|
1898 |
+
|
1899 |
+
"PSEUDO": function( match ) {
|
1900 |
+
var excess,
|
1901 |
+
unquoted = !match[6] && match[2];
|
1902 |
+
|
1903 |
+
if ( matchExpr["CHILD"].test( match[0] ) ) {
|
1904 |
+
return null;
|
1905 |
+
}
|
1906 |
+
|
1907 |
+
// Accept quoted arguments as-is
|
1908 |
+
if ( match[3] ) {
|
1909 |
+
match[2] = match[4] || match[5] || "";
|
1910 |
+
|
1911 |
+
// Strip excess characters from unquoted arguments
|
1912 |
+
} else if ( unquoted && rpseudo.test( unquoted ) &&
|
1913 |
+
// Get excess from tokenize (recursively)
|
1914 |
+
(excess = tokenize( unquoted, true )) &&
|
1915 |
+
// advance to the next closing parenthesis
|
1916 |
+
(excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
|
1917 |
+
|
1918 |
+
// excess is a negative index
|
1919 |
+
match[0] = match[0].slice( 0, excess );
|
1920 |
+
match[2] = unquoted.slice( 0, excess );
|
1921 |
+
}
|
1922 |
+
|
1923 |
+
// Return only captures needed by the pseudo filter method (type and argument)
|
1924 |
+
return match.slice( 0, 3 );
|
1925 |
+
}
|
1926 |
+
},
|
1927 |
+
|
1928 |
+
filter: {
|
1929 |
+
|
1930 |
+
"TAG": function( nodeNameSelector ) {
|
1931 |
+
var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
|
1932 |
+
return nodeNameSelector === "*" ?
|
1933 |
+
function() { return true; } :
|
1934 |
+
function( elem ) {
|
1935 |
+
return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
|
1936 |
+
};
|
1937 |
+
},
|
1938 |
+
|
1939 |
+
"CLASS": function( className ) {
|
1940 |
+
var pattern = classCache[ className + " " ];
|
1941 |
+
|
1942 |
+
return pattern ||
|
1943 |
+
(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
|
1944 |
+
classCache( className, function( elem ) {
|
1945 |
+
return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" );
|
1946 |
+
});
|
1947 |
+
},
|
1948 |
+
|
1949 |
+
"ATTR": function( name, operator, check ) {
|
1950 |
+
return function( elem ) {
|
1951 |
+
var result = Sizzle.attr( elem, name );
|
1952 |
+
|
1953 |
+
if ( result == null ) {
|
1954 |
+
return operator === "!=";
|
1955 |
+
}
|
1956 |
+
if ( !operator ) {
|
1957 |
+
return true;
|
1958 |
+
}
|
1959 |
+
|
1960 |
+
result += "";
|
1961 |
+
|
1962 |
+
return operator === "=" ? result === check :
|
1963 |
+
operator === "!=" ? result !== check :
|
1964 |
+
operator === "^=" ? check && result.indexOf( check ) === 0 :
|
1965 |
+
operator === "*=" ? check && result.indexOf( check ) > -1 :
|
1966 |
+
operator === "$=" ? check && result.slice( -check.length ) === check :
|
1967 |
+
operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
|
1968 |
+
operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
|
1969 |
+
false;
|
1970 |
+
};
|
1971 |
+
},
|
1972 |
+
|
1973 |
+
"CHILD": function( type, what, argument, first, last ) {
|
1974 |
+
var simple = type.slice( 0, 3 ) !== "nth",
|
1975 |
+
forward = type.slice( -4 ) !== "last",
|
1976 |
+
ofType = what === "of-type";
|
1977 |
+
|
1978 |
+
return first === 1 && last === 0 ?
|
1979 |
+
|
1980 |
+
// Shortcut for :nth-*(n)
|
1981 |
+
function( elem ) {
|
1982 |
+
return !!elem.parentNode;
|
1983 |
+
} :
|
1984 |
+
|
1985 |
+
function( elem, context, xml ) {
|
1986 |
+
var cache, uniqueCache, outerCache, node, nodeIndex, start,
|
1987 |
+
dir = simple !== forward ? "nextSibling" : "previousSibling",
|
1988 |
+
parent = elem.parentNode,
|
1989 |
+
name = ofType && elem.nodeName.toLowerCase(),
|
1990 |
+
useCache = !xml && !ofType,
|
1991 |
+
diff = false;
|
1992 |
+
|
1993 |
+
if ( parent ) {
|
1994 |
+
|
1995 |
+
// :(first|last|only)-(child|of-type)
|
1996 |
+
if ( simple ) {
|
1997 |
+
while ( dir ) {
|
1998 |
+
node = elem;
|
1999 |
+
while ( (node = node[ dir ]) ) {
|
2000 |
+
if ( ofType ?
|
2001 |
+
node.nodeName.toLowerCase() === name :
|
2002 |
+
node.nodeType === 1 ) {
|
2003 |
+
|
2004 |
+
return false;
|
2005 |
+
}
|
2006 |
+
}
|
2007 |
+
// Reverse direction for :only-* (if we haven't yet done so)
|
2008 |
+
start = dir = type === "only" && !start && "nextSibling";
|
2009 |
+
}
|
2010 |
+
return true;
|
2011 |
+
}
|
2012 |
+
|
2013 |
+
start = [ forward ? parent.firstChild : parent.lastChild ];
|
2014 |
+
|
2015 |
+
// non-xml :nth-child(...) stores cache data on `parent`
|
2016 |
+
if ( forward && useCache ) {
|
2017 |
+
|
2018 |
+
// Seek `elem` from a previously-cached index
|
2019 |
+
|
2020 |
+
// ...in a gzip-friendly way
|
2021 |
+
node = parent;
|
2022 |
+
outerCache = node[ expando ] || (node[ expando ] = {});
|
2023 |
+
|
2024 |
+
// Support: IE <9 only
|
2025 |
+
// Defend against cloned attroperties (jQuery gh-1709)
|
2026 |
+
uniqueCache = outerCache[ node.uniqueID ] ||
|
2027 |
+
(outerCache[ node.uniqueID ] = {});
|
2028 |
+
|
2029 |
+
cache = uniqueCache[ type ] || [];
|
2030 |
+
nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
|
2031 |
+
diff = nodeIndex && cache[ 2 ];
|
2032 |
+
node = nodeIndex && parent.childNodes[ nodeIndex ];
|
2033 |
+
|
2034 |
+
while ( (node = ++nodeIndex && node && node[ dir ] ||
|
2035 |
+
|
2036 |
+
// Fallback to seeking `elem` from the start
|
2037 |
+
(diff = nodeIndex = 0) || start.pop()) ) {
|
2038 |
+
|
2039 |
+
// When found, cache indexes on `parent` and break
|
2040 |
+
if ( node.nodeType === 1 && ++diff && node === elem ) {
|
2041 |
+
uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
|
2042 |
+
break;
|
2043 |
+
}
|
2044 |
+
}
|
2045 |
+
|
2046 |
+
} else {
|
2047 |
+
// Use previously-cached element index if available
|
2048 |
+
if ( useCache ) {
|
2049 |
+
// ...in a gzip-friendly way
|
2050 |
+
node = elem;
|
2051 |
+
outerCache = node[ expando ] || (node[ expando ] = {});
|
2052 |
+
|
2053 |
+
// Support: IE <9 only
|
2054 |
+
// Defend against cloned attroperties (jQuery gh-1709)
|
2055 |
+
uniqueCache = outerCache[ node.uniqueID ] ||
|
2056 |
+
(outerCache[ node.uniqueID ] = {});
|
2057 |
+
|
2058 |
+
cache = uniqueCache[ type ] || [];
|
2059 |
+
nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
|
2060 |
+
diff = nodeIndex;
|
2061 |
+
}
|
2062 |
+
|
2063 |
+
// xml :nth-child(...)
|
2064 |
+
// or :nth-last-child(...) or :nth(-last)?-of-type(...)
|
2065 |
+
if ( diff === false ) {
|
2066 |
+
// Use the same loop as above to seek `elem` from the start
|
2067 |
+
while ( (node = ++nodeIndex && node && node[ dir ] ||
|
2068 |
+
(diff = nodeIndex = 0) || start.pop()) ) {
|
2069 |
+
|
2070 |
+
if ( ( ofType ?
|
2071 |
+
node.nodeName.toLowerCase() === name :
|
2072 |
+
node.nodeType === 1 ) &&
|
2073 |
+
++diff ) {
|
2074 |
+
|
2075 |
+
// Cache the index of each encountered element
|
2076 |
+
if ( useCache ) {
|
2077 |
+
outerCache = node[ expando ] || (node[ expando ] = {});
|
2078 |
+
|
2079 |
+
// Support: IE <9 only
|
2080 |
+
// Defend against cloned attroperties (jQuery gh-1709)
|
2081 |
+
uniqueCache = outerCache[ node.uniqueID ] ||
|
2082 |
+
(outerCache[ node.uniqueID ] = {});
|
2083 |
+
|
2084 |
+
uniqueCache[ type ] = [ dirruns, diff ];
|
2085 |
+
}
|
2086 |
+
|
2087 |
+
if ( node === elem ) {
|
2088 |
+
break;
|
2089 |
+
}
|
2090 |
+
}
|
2091 |
+
}
|
2092 |
+
}
|
2093 |
+
}
|
2094 |
+
|
2095 |
+
// Incorporate the offset, then check against cycle size
|
2096 |
+
diff -= last;
|
2097 |
+
return diff === first || ( diff % first === 0 && diff / first >= 0 );
|
2098 |
+
}
|
2099 |
+
};
|
2100 |
+
},
|
2101 |
+
|
2102 |
+
"PSEUDO": function( pseudo, argument ) {
|
2103 |
+
// pseudo-class names are case-insensitive
|
2104 |
+
// http://www.w3.org/TR/selectors/#pseudo-classes
|
2105 |
+
// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
|
2106 |
+
// Remember that setFilters inherits from pseudos
|
2107 |
+
var args,
|
2108 |
+
fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
|
2109 |
+
Sizzle.error( "unsupported pseudo: " + pseudo );
|
2110 |
+
|
2111 |
+
// The user may use createPseudo to indicate that
|
2112 |
+
// arguments are needed to create the filter function
|
2113 |
+
// just as Sizzle does
|
2114 |
+
if ( fn[ expando ] ) {
|
2115 |
+
return fn( argument );
|
2116 |
+
}
|
2117 |
+
|
2118 |
+
// But maintain support for old signatures
|
2119 |
+
if ( fn.length > 1 ) {
|
2120 |
+
args = [ pseudo, pseudo, "", argument ];
|
2121 |
+
return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
|
2122 |
+
markFunction(function( seed, matches ) {
|
2123 |
+
var idx,
|
2124 |
+
matched = fn( seed, argument ),
|
2125 |
+
i = matched.length;
|
2126 |
+
while ( i-- ) {
|
2127 |
+
idx = indexOf( seed, matched[i] );
|
2128 |
+
seed[ idx ] = !( matches[ idx ] = matched[i] );
|
2129 |
+
}
|
2130 |
+
}) :
|
2131 |
+
function( elem ) {
|
2132 |
+
return fn( elem, 0, args );
|
2133 |
+
};
|
2134 |
+
}
|
2135 |
+
|
2136 |
+
return fn;
|
2137 |
+
}
|
2138 |
+
},
|
2139 |
+
|
2140 |
+
pseudos: {
|
2141 |
+
// Potentially complex pseudos
|
2142 |
+
"not": markFunction(function( selector ) {
|
2143 |
+
// Trim the selector passed to compile
|
2144 |
+
// to avoid treating leading and trailing
|
2145 |
+
// spaces as combinators
|
2146 |
+
var input = [],
|
2147 |
+
results = [],
|
2148 |
+
matcher = compile( selector.replace( rtrim, "$1" ) );
|
2149 |
+
|
2150 |
+
return matcher[ expando ] ?
|
2151 |
+
markFunction(function( seed, matches, context, xml ) {
|
2152 |
+
var elem,
|
2153 |
+
unmatched = matcher( seed, null, xml, [] ),
|
2154 |
+
i = seed.length;
|
2155 |
+
|
2156 |
+
// Match elements unmatched by `matcher`
|
2157 |
+
while ( i-- ) {
|
2158 |
+
if ( (elem = unmatched[i]) ) {
|
2159 |
+
seed[i] = !(matches[i] = elem);
|
2160 |
+
}
|
2161 |
+
}
|
2162 |
+
}) :
|
2163 |
+
function( elem, context, xml ) {
|
2164 |
+
input[0] = elem;
|
2165 |
+
matcher( input, null, xml, results );
|
2166 |
+
// Don't keep the element (issue #299)
|
2167 |
+
input[0] = null;
|
2168 |
+
return !results.pop();
|
2169 |
+
};
|
2170 |
+
}),
|
2171 |
+
|
2172 |
+
"has": markFunction(function( selector ) {
|
2173 |
+
return function( elem ) {
|
2174 |
+
return Sizzle( selector, elem ).length > 0;
|
2175 |
+
};
|
2176 |
+
}),
|
2177 |
+
|
2178 |
+
"contains": markFunction(function( text ) {
|
2179 |
+
text = text.replace( runescape, funescape );
|
2180 |
+
return function( elem ) {
|
2181 |
+
return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
|
2182 |
+
};
|
2183 |
+
}),
|
2184 |
+
|
2185 |
+
// "Whether an element is represented by a :lang() selector
|
2186 |
+
// is based solely on the element's language value
|
2187 |
+
// being equal to the identifier C,
|
2188 |
+
// or beginning with the identifier C immediately followed by "-".
|
2189 |
+
// The matching of C against the element's language value is performed case-insensitively.
|
2190 |
+
// The identifier C does not have to be a valid language name."
|
2191 |
+
// http://www.w3.org/TR/selectors/#lang-pseudo
|
2192 |
+
"lang": markFunction( function( lang ) {
|
2193 |
+
// lang value must be a valid identifier
|
2194 |
+
if ( !ridentifier.test(lang || "") ) {
|
2195 |
+
Sizzle.error( "unsupported lang: " + lang );
|
2196 |
+
}
|
2197 |
+
lang = lang.replace( runescape, funescape ).toLowerCase();
|
2198 |
+
return function( elem ) {
|
2199 |
+
var elemLang;
|
2200 |
+
do {
|
2201 |
+
if ( (elemLang = documentIsHTML ?
|
2202 |
+
elem.lang :
|
2203 |
+
elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
|
2204 |
+
|
2205 |
+
elemLang = elemLang.toLowerCase();
|
2206 |
+
return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
|
2207 |
+
}
|
2208 |
+
} while ( (elem = elem.parentNode) && elem.nodeType === 1 );
|
2209 |
+
return false;
|
2210 |
+
};
|
2211 |
+
}),
|
2212 |
+
|
2213 |
+
// Miscellaneous
|
2214 |
+
"target": function( elem ) {
|
2215 |
+
var hash = window.location && window.location.hash;
|
2216 |
+
return hash && hash.slice( 1 ) === elem.id;
|
2217 |
+
},
|
2218 |
+
|
2219 |
+
"root": function( elem ) {
|
2220 |
+
return elem === docElem;
|
2221 |
+
},
|
2222 |
+
|
2223 |
+
"focus": function( elem ) {
|
2224 |
+
return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
|
2225 |
+
},
|
2226 |
+
|
2227 |
+
// Boolean properties
|
2228 |
+
"enabled": createDisabledPseudo( false ),
|
2229 |
+
"disabled": createDisabledPseudo( true ),
|
2230 |
+
|
2231 |
+
"checked": function( elem ) {
|
2232 |
+
// In CSS3, :checked should return both checked and selected elements
|
2233 |
+
// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
|
2234 |
+
var nodeName = elem.nodeName.toLowerCase();
|
2235 |
+
return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
|
2236 |
+
},
|
2237 |
+
|
2238 |
+
"selected": function( elem ) {
|
2239 |
+
// Accessing this property makes selected-by-default
|
2240 |
+
// options in Safari work properly
|
2241 |
+
if ( elem.parentNode ) {
|
2242 |
+
elem.parentNode.selectedIndex;
|
2243 |
+
}
|
2244 |
+
|
2245 |
+
return elem.selected === true;
|
2246 |
+
},
|
2247 |
+
|
2248 |
+
// Contents
|
2249 |
+
"empty": function( elem ) {
|
2250 |
+
// http://www.w3.org/TR/selectors/#empty-pseudo
|
2251 |
+
// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
|
2252 |
+
// but not by others (comment: 8; processing instruction: 7; etc.)
|
2253 |
+
// nodeType < 6 works because attributes (2) do not appear as children
|
2254 |
+
for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
|
2255 |
+
if ( elem.nodeType < 6 ) {
|
2256 |
+
return false;
|
2257 |
+
}
|
2258 |
+
}
|
2259 |
+
return true;
|
2260 |
+
},
|
2261 |
+
|
2262 |
+
"parent": function( elem ) {
|
2263 |
+
return !Expr.pseudos["empty"]( elem );
|
2264 |
+
},
|
2265 |
+
|
2266 |
+
// Element/input types
|
2267 |
+
"header": function( elem ) {
|
2268 |
+
return rheader.test( elem.nodeName );
|
2269 |
+
},
|
2270 |
+
|
2271 |
+
"input": function( elem ) {
|
2272 |
+
return rinputs.test( elem.nodeName );
|
2273 |
+
},
|
2274 |
+
|
2275 |
+
"button": function( elem ) {
|
2276 |
+
var name = elem.nodeName.toLowerCase();
|
2277 |
+
return name === "input" && elem.type === "button" || name === "button";
|
2278 |
+
},
|
2279 |
+
|
2280 |
+
"text": function( elem ) {
|
2281 |
+
var attr;
|
2282 |
+
return elem.nodeName.toLowerCase() === "input" &&
|
2283 |
+
elem.type === "text" &&
|
2284 |
+
|
2285 |
+
// Support: IE<8
|
2286 |
+
// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
|
2287 |
+
( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
|
2288 |
+
},
|
2289 |
+
|
2290 |
+
// Position-in-collection
|
2291 |
+
"first": createPositionalPseudo(function() {
|
2292 |
+
return [ 0 ];
|
2293 |
+
}),
|
2294 |
+
|
2295 |
+
"last": createPositionalPseudo(function( matchIndexes, length ) {
|
2296 |
+
return [ length - 1 ];
|
2297 |
+
}),
|
2298 |
+
|
2299 |
+
"eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
|
2300 |
+
return [ argument < 0 ? argument + length : argument ];
|
2301 |
+
}),
|
2302 |
+
|
2303 |
+
"even": createPositionalPseudo(function( matchIndexes, length ) {
|
2304 |
+
var i = 0;
|
2305 |
+
for ( ; i < length; i += 2 ) {
|
2306 |
+
matchIndexes.push( i );
|
2307 |
+
}
|
2308 |
+
return matchIndexes;
|
2309 |
+
}),
|
2310 |
+
|
2311 |
+
"odd": createPositionalPseudo(function( matchIndexes, length ) {
|
2312 |
+
var i = 1;
|
2313 |
+
for ( ; i < length; i += 2 ) {
|
2314 |
+
matchIndexes.push( i );
|
2315 |
+
}
|
2316 |
+
return matchIndexes;
|
2317 |
+
}),
|
2318 |
+
|
2319 |
+
"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
|
2320 |
+
var i = argument < 0 ? argument + length : argument;
|
2321 |
+
for ( ; --i >= 0; ) {
|
2322 |
+
matchIndexes.push( i );
|
2323 |
+
}
|
2324 |
+
return matchIndexes;
|
2325 |
+
}),
|
2326 |
+
|
2327 |
+
"gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
|
2328 |
+
var i = argument < 0 ? argument + length : argument;
|
2329 |
+
for ( ; ++i < length; ) {
|
2330 |
+
matchIndexes.push( i );
|
2331 |
+
}
|
2332 |
+
return matchIndexes;
|
2333 |
+
})
|
2334 |
+
}
|
2335 |
+
};
|
2336 |
+
|
2337 |
+
Expr.pseudos["nth"] = Expr.pseudos["eq"];
|
2338 |
+
|
2339 |
+
// Add button/input type pseudos
|
2340 |
+
for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
|
2341 |
+
Expr.pseudos[ i ] = createInputPseudo( i );
|
2342 |
+
}
|
2343 |
+
for ( i in { submit: true, reset: true } ) {
|
2344 |
+
Expr.pseudos[ i ] = createButtonPseudo( i );
|
2345 |
+
}
|
2346 |
+
|
2347 |
+
// Easy API for creating new setFilters
|
2348 |
+
function setFilters() {}
|
2349 |
+
setFilters.prototype = Expr.filters = Expr.pseudos;
|
2350 |
+
Expr.setFilters = new setFilters();
|
2351 |
+
|
2352 |
+
tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
|
2353 |
+
var matched, match, tokens, type,
|
2354 |
+
soFar, groups, preFilters,
|
2355 |
+
cached = tokenCache[ selector + " " ];
|
2356 |
+
|
2357 |
+
if ( cached ) {
|
2358 |
+
return parseOnly ? 0 : cached.slice( 0 );
|
2359 |
+
}
|
2360 |
+
|
2361 |
+
soFar = selector;
|
2362 |
+
groups = [];
|
2363 |
+
preFilters = Expr.preFilter;
|
2364 |
+
|
2365 |
+
while ( soFar ) {
|
2366 |
+
|
2367 |
+
// Comma and first run
|
2368 |
+
if ( !matched || (match = rcomma.exec( soFar )) ) {
|
2369 |
+
if ( match ) {
|
2370 |
+
// Don't consume trailing commas as valid
|
2371 |
+
soFar = soFar.slice( match[0].length ) || soFar;
|
2372 |
+
}
|
2373 |
+
groups.push( (tokens = []) );
|
2374 |
+
}
|
2375 |
+
|
2376 |
+
matched = false;
|
2377 |
+
|
2378 |
+
// Combinators
|
2379 |
+
if ( (match = rcombinators.exec( soFar )) ) {
|
2380 |
+
matched = match.shift();
|
2381 |
+
tokens.push({
|
2382 |
+
value: matched,
|
2383 |
+
// Cast descendant combinators to space
|
2384 |
+
type: match[0].replace( rtrim, " " )
|
2385 |
+
});
|
2386 |
+
soFar = soFar.slice( matched.length );
|
2387 |
+
}
|
2388 |
+
|
2389 |
+
// Filters
|
2390 |
+
for ( type in Expr.filter ) {
|
2391 |
+
if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
|
2392 |
+
(match = preFilters[ type ]( match ))) ) {
|
2393 |
+
matched = match.shift();
|
2394 |
+
tokens.push({
|
2395 |
+
value: matched,
|
2396 |
+
type: type,
|
2397 |
+
matches: match
|
2398 |
+
});
|
2399 |
+
soFar = soFar.slice( matched.length );
|
2400 |
+
}
|
2401 |
+
}
|
2402 |
+
|
2403 |
+
if ( !matched ) {
|
2404 |
+
break;
|
2405 |
+
}
|
2406 |
+
}
|
2407 |
+
|
2408 |
+
// Return the length of the invalid excess
|
2409 |
+
// if we're just parsing
|
2410 |
+
// Otherwise, throw an error or return tokens
|
2411 |
+
return parseOnly ?
|
2412 |
+
soFar.length :
|
2413 |
+
soFar ?
|
2414 |
+
Sizzle.error( selector ) :
|
2415 |
+
// Cache the tokens
|
2416 |
+
tokenCache( selector, groups ).slice( 0 );
|
2417 |
+
};
|
2418 |
+
|
2419 |
+
function toSelector( tokens ) {
|
2420 |
+
var i = 0,
|
2421 |
+
len = tokens.length,
|
2422 |
+
selector = "";
|
2423 |
+
for ( ; i < len; i++ ) {
|
2424 |
+
selector += tokens[i].value;
|
2425 |
+
}
|
2426 |
+
return selector;
|
2427 |
+
}
|
2428 |
+
|
2429 |
+
function addCombinator( matcher, combinator, base ) {
|
2430 |
+
var dir = combinator.dir,
|
2431 |
+
skip = combinator.next,
|
2432 |
+
key = skip || dir,
|
2433 |
+
checkNonElements = base && key === "parentNode",
|
2434 |
+
doneName = done++;
|
2435 |
+
|
2436 |
+
return combinator.first ?
|
2437 |
+
// Check against closest ancestor/preceding element
|
2438 |
+
function( elem, context, xml ) {
|
2439 |
+
while ( (elem = elem[ dir ]) ) {
|
2440 |
+
if ( elem.nodeType === 1 || checkNonElements ) {
|
2441 |
+
return matcher( elem, context, xml );
|
2442 |
+
}
|
2443 |
+
}
|
2444 |
+
return false;
|
2445 |
+
} :
|
2446 |
+
|
2447 |
+
// Check against all ancestor/preceding elements
|
2448 |
+
function( elem, context, xml ) {
|
2449 |
+
var oldCache, uniqueCache, outerCache,
|
2450 |
+
newCache = [ dirruns, doneName ];
|
2451 |
+
|
2452 |
+
// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
|
2453 |
+
if ( xml ) {
|
2454 |
+
while ( (elem = elem[ dir ]) ) {
|
2455 |
+
if ( elem.nodeType === 1 || checkNonElements ) {
|
2456 |
+
if ( matcher( elem, context, xml ) ) {
|
2457 |
+
return true;
|
2458 |
+
}
|
2459 |
+
}
|
2460 |
+
}
|
2461 |
+
} else {
|
2462 |
+
while ( (elem = elem[ dir ]) ) {
|
2463 |
+
if ( elem.nodeType === 1 || checkNonElements ) {
|
2464 |
+
outerCache = elem[ expando ] || (elem[ expando ] = {});
|
2465 |
+
|
2466 |
+
// Support: IE <9 only
|
2467 |
+
// Defend against cloned attroperties (jQuery gh-1709)
|
2468 |
+
uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});
|
2469 |
+
|
2470 |
+
if ( skip && skip === elem.nodeName.toLowerCase() ) {
|
2471 |
+
elem = elem[ dir ] || elem;
|
2472 |
+
} else if ( (oldCache = uniqueCache[ key ]) &&
|
2473 |
+
oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
|
2474 |
+
|
2475 |
+
// Assign to newCache so results back-propagate to previous elements
|
2476 |
+
return (newCache[ 2 ] = oldCache[ 2 ]);
|
2477 |
+
} else {
|
2478 |
+
// Reuse newcache so results back-propagate to previous elements
|
2479 |
+
uniqueCache[ key ] = newCache;
|
2480 |
+
|
2481 |
+
// A match means we're done; a fail means we have to keep checking
|
2482 |
+
if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
|
2483 |
+
return true;
|
2484 |
+
}
|
2485 |
+
}
|
2486 |
+
}
|
2487 |
+
}
|
2488 |
+
}
|
2489 |
+
return false;
|
2490 |
+
};
|
2491 |
+
}
|
2492 |
+
|
2493 |
+
function elementMatcher( matchers ) {
|
2494 |
+
return matchers.length > 1 ?
|
2495 |
+
function( elem, context, xml ) {
|
2496 |
+
var i = matchers.length;
|
2497 |
+
while ( i-- ) {
|
2498 |
+
if ( !matchers[i]( elem, context, xml ) ) {
|
2499 |
+
return false;
|
2500 |
+
}
|
2501 |
+
}
|
2502 |
+
return true;
|
2503 |
+
} :
|
2504 |
+
matchers[0];
|
2505 |
+
}
|
2506 |
+
|
2507 |
+
function multipleContexts( selector, contexts, results ) {
|
2508 |
+
var i = 0,
|
2509 |
+
len = contexts.length;
|
2510 |
+
for ( ; i < len; i++ ) {
|
2511 |
+
Sizzle( selector, contexts[i], results );
|
2512 |
+
}
|
2513 |
+
return results;
|
2514 |
+
}
|
2515 |
+
|
2516 |
+
function condense( unmatched, map, filter, context, xml ) {
|
2517 |
+
var elem,
|
2518 |
+
newUnmatched = [],
|
2519 |
+
i = 0,
|
2520 |
+
len = unmatched.length,
|
2521 |
+
mapped = map != null;
|
2522 |
+
|
2523 |
+
for ( ; i < len; i++ ) {
|
2524 |
+
if ( (elem = unmatched[i]) ) {
|
2525 |
+
if ( !filter || filter( elem, context, xml ) ) {
|
2526 |
+
newUnmatched.push( elem );
|
2527 |
+
if ( mapped ) {
|
2528 |
+
map.push( i );
|
2529 |
+
}
|
2530 |
+
}
|
2531 |
+
}
|
2532 |
+
}
|
2533 |
+
|
2534 |
+
return newUnmatched;
|
2535 |
+
}
|
2536 |
+
|
2537 |
+
function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
|
2538 |
+
if ( postFilter && !postFilter[ expando ] ) {
|
2539 |
+
postFilter = setMatcher( postFilter );
|
2540 |
+
}
|
2541 |
+
if ( postFinder && !postFinder[ expando ] ) {
|
2542 |
+
postFinder = setMatcher( postFinder, postSelector );
|
2543 |
+
}
|
2544 |
+
return markFunction(function( seed, results, context, xml ) {
|
2545 |
+
var temp, i, elem,
|
2546 |
+
preMap = [],
|
2547 |
+
postMap = [],
|
2548 |
+
preexisting = results.length,
|
2549 |
+
|
2550 |
+
// Get initial elements from seed or context
|
2551 |
+
elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
|
2552 |
+
|
2553 |
+
// Prefilter to get matcher input, preserving a map for seed-results synchronization
|
2554 |
+
matcherIn = preFilter && ( seed || !selector ) ?
|
2555 |
+
condense( elems, preMap, preFilter, context, xml ) :
|
2556 |
+
elems,
|
2557 |
+
|
2558 |
+
matcherOut = matcher ?
|
2559 |
+
// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
|
2560 |
+
postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
|
2561 |
+
|
2562 |
+
// ...intermediate processing is necessary
|
2563 |
+
[] :
|
2564 |
+
|
2565 |
+
// ...otherwise use results directly
|
2566 |
+
results :
|
2567 |
+
matcherIn;
|
2568 |
+
|
2569 |
+
// Find primary matches
|
2570 |
+
if ( matcher ) {
|
2571 |
+
matcher( matcherIn, matcherOut, context, xml );
|
2572 |
+
}
|
2573 |
+
|
2574 |
+
// Apply postFilter
|
2575 |
+
if ( postFilter ) {
|
2576 |
+
temp = condense( matcherOut, postMap );
|
2577 |
+
postFilter( temp, [], context, xml );
|
2578 |
+
|
2579 |
+
// Un-match failing elements by moving them back to matcherIn
|
2580 |
+
i = temp.length;
|
2581 |
+
while ( i-- ) {
|
2582 |
+
if ( (elem = temp[i]) ) {
|
2583 |
+
matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
|
2584 |
+
}
|
2585 |
+
}
|
2586 |
+
}
|
2587 |
+
|
2588 |
+
if ( seed ) {
|
2589 |
+
if ( postFinder || preFilter ) {
|
2590 |
+
if ( postFinder ) {
|
2591 |
+
// Get the final matcherOut by condensing this intermediate into postFinder contexts
|
2592 |
+
temp = [];
|
2593 |
+
i = matcherOut.length;
|
2594 |
+
while ( i-- ) {
|
2595 |
+
if ( (elem = matcherOut[i]) ) {
|
2596 |
+
// Restore matcherIn since elem is not yet a final match
|
2597 |
+
temp.push( (matcherIn[i] = elem) );
|
2598 |
+
}
|
2599 |
+
}
|
2600 |
+
postFinder( null, (matcherOut = []), temp, xml );
|
2601 |
+
}
|
2602 |
+
|
2603 |
+
// Move matched elements from seed to results to keep them synchronized
|
2604 |
+
i = matcherOut.length;
|
2605 |
+
while ( i-- ) {
|
2606 |
+
if ( (elem = matcherOut[i]) &&
|
2607 |
+
(temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {
|
2608 |
+
|
2609 |
+
seed[temp] = !(results[temp] = elem);
|
2610 |
+
}
|
2611 |
+
}
|
2612 |
+
}
|
2613 |
+
|
2614 |
+
// Add elements to results, through postFinder if defined
|
2615 |
+
} else {
|
2616 |
+
matcherOut = condense(
|
2617 |
+
matcherOut === results ?
|
2618 |
+
matcherOut.splice( preexisting, matcherOut.length ) :
|
2619 |
+
matcherOut
|
2620 |
+
);
|
2621 |
+
if ( postFinder ) {
|
2622 |
+
postFinder( null, results, matcherOut, xml );
|
2623 |
+
} else {
|
2624 |
+
push.apply( results, matcherOut );
|
2625 |
+
}
|
2626 |
+
}
|
2627 |
+
});
|
2628 |
+
}
|
2629 |
+
|
2630 |
+
function matcherFromTokens( tokens ) {
|
2631 |
+
var checkContext, matcher, j,
|
2632 |
+
len = tokens.length,
|
2633 |
+
leadingRelative = Expr.relative[ tokens[0].type ],
|
2634 |
+
implicitRelative = leadingRelative || Expr.relative[" "],
|
2635 |
+
i = leadingRelative ? 1 : 0,
|
2636 |
+
|
2637 |
+
// The foundational matcher ensures that elements are reachable from top-level context(s)
|
2638 |
+
matchContext = addCombinator( function( elem ) {
|
2639 |
+
return elem === checkContext;
|
2640 |
+
}, implicitRelative, true ),
|
2641 |
+
matchAnyContext = addCombinator( function( elem ) {
|
2642 |
+
return indexOf( checkContext, elem ) > -1;
|
2643 |
+
}, implicitRelative, true ),
|
2644 |
+
matchers = [ function( elem, context, xml ) {
|
2645 |
+
var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
|
2646 |
+
(checkContext = context).nodeType ?
|
2647 |
+
matchContext( elem, context, xml ) :
|
2648 |
+
matchAnyContext( elem, context, xml ) );
|
2649 |
+
// Avoid hanging onto element (issue #299)
|
2650 |
+
checkContext = null;
|
2651 |
+
return ret;
|
2652 |
+
} ];
|
2653 |
+
|
2654 |
+
for ( ; i < len; i++ ) {
|
2655 |
+
if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
|
2656 |
+
matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
|
2657 |
+
} else {
|
2658 |
+
matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
|
2659 |
+
|
2660 |
+
// Return special upon seeing a positional matcher
|
2661 |
+
if ( matcher[ expando ] ) {
|
2662 |
+
// Find the next relative operator (if any) for proper handling
|
2663 |
+
j = ++i;
|
2664 |
+
for ( ; j < len; j++ ) {
|
2665 |
+
if ( Expr.relative[ tokens[j].type ] ) {
|
2666 |
+
break;
|
2667 |
+
}
|
2668 |
+
}
|
2669 |
+
return setMatcher(
|
2670 |
+
i > 1 && elementMatcher( matchers ),
|
2671 |
+
i > 1 && toSelector(
|
2672 |
+
// If the preceding token was a descendant combinator, insert an implicit any-element `*`
|
2673 |
+
tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
|
2674 |
+
).replace( rtrim, "$1" ),
|
2675 |
+
matcher,
|
2676 |
+
i < j && matcherFromTokens( tokens.slice( i, j ) ),
|
2677 |
+
j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
|
2678 |
+
j < len && toSelector( tokens )
|
2679 |
+
);
|
2680 |
+
}
|
2681 |
+
matchers.push( matcher );
|
2682 |
+
}
|
2683 |
+
}
|
2684 |
+
|
2685 |
+
return elementMatcher( matchers );
|
2686 |
+
}
|
2687 |
+
|
2688 |
+
function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
|
2689 |
+
var bySet = setMatchers.length > 0,
|
2690 |
+
byElement = elementMatchers.length > 0,
|
2691 |
+
superMatcher = function( seed, context, xml, results, outermost ) {
|
2692 |
+
var elem, j, matcher,
|
2693 |
+
matchedCount = 0,
|
2694 |
+
i = "0",
|
2695 |
+
unmatched = seed && [],
|
2696 |
+
setMatched = [],
|
2697 |
+
contextBackup = outermostContext,
|
2698 |
+
// We must always have either seed elements or outermost context
|
2699 |
+
elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
|
2700 |
+
// Use integer dirruns iff this is the outermost matcher
|
2701 |
+
dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
|
2702 |
+
len = elems.length;
|
2703 |
+
|
2704 |
+
if ( outermost ) {
|
2705 |
+
outermostContext = context === document || context || outermost;
|
2706 |
+
}
|
2707 |
+
|
2708 |
+
// Add elements passing elementMatchers directly to results
|
2709 |
+
// Support: IE<9, Safari
|
2710 |
+
// Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
|
2711 |
+
for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
|
2712 |
+
if ( byElement && elem ) {
|
2713 |
+
j = 0;
|
2714 |
+
if ( !context && elem.ownerDocument !== document ) {
|
2715 |
+
setDocument( elem );
|
2716 |
+
xml = !documentIsHTML;
|
2717 |
+
}
|
2718 |
+
while ( (matcher = elementMatchers[j++]) ) {
|
2719 |
+
if ( matcher( elem, context || document, xml) ) {
|
2720 |
+
results.push( elem );
|
2721 |
+
break;
|
2722 |
+
}
|
2723 |
+
}
|
2724 |
+
if ( outermost ) {
|
2725 |
+
dirruns = dirrunsUnique;
|
2726 |
+
}
|
2727 |
+
}
|
2728 |
+
|
2729 |
+
// Track unmatched elements for set filters
|
2730 |
+
if ( bySet ) {
|
2731 |
+
// They will have gone through all possible matchers
|
2732 |
+
if ( (elem = !matcher && elem) ) {
|
2733 |
+
matchedCount--;
|
2734 |
+
}
|
2735 |
+
|
2736 |
+
// Lengthen the array for every element, matched or not
|
2737 |
+
if ( seed ) {
|
2738 |
+
unmatched.push( elem );
|
2739 |
+
}
|
2740 |
+
}
|
2741 |
+
}
|
2742 |
+
|
2743 |
+
// `i` is now the count of elements visited above, and adding it to `matchedCount`
|
2744 |
+
// makes the latter nonnegative.
|
2745 |
+
matchedCount += i;
|
2746 |
+
|
2747 |
+
// Apply set filters to unmatched elements
|
2748 |
+
// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
|
2749 |
+
// equals `i`), unless we didn't visit _any_ elements in the above loop because we have
|
2750 |
+
// no element matchers and no seed.
|
2751 |
+
// Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
|
2752 |
+
// case, which will result in a "00" `matchedCount` that differs from `i` but is also
|
2753 |
+
// numerically zero.
|
2754 |
+
if ( bySet && i !== matchedCount ) {
|
2755 |
+
j = 0;
|
2756 |
+
while ( (matcher = setMatchers[j++]) ) {
|
2757 |
+
matcher( unmatched, setMatched, context, xml );
|
2758 |
+
}
|
2759 |
+
|
2760 |
+
if ( seed ) {
|
2761 |
+
// Reintegrate element matches to eliminate the need for sorting
|
2762 |
+
if ( matchedCount > 0 ) {
|
2763 |
+
while ( i-- ) {
|
2764 |
+
if ( !(unmatched[i] || setMatched[i]) ) {
|
2765 |
+
setMatched[i] = pop.call( results );
|
2766 |
+
}
|
2767 |
+
}
|
2768 |
+
}
|
2769 |
+
|
2770 |
+
// Discard index placeholder values to get only actual matches
|
2771 |
+
setMatched = condense( setMatched );
|
2772 |
+
}
|
2773 |
+
|
2774 |
+
// Add matches to results
|
2775 |
+
push.apply( results, setMatched );
|
2776 |
+
|
2777 |
+
// Seedless set matches succeeding multiple successful matchers stipulate sorting
|
2778 |
+
if ( outermost && !seed && setMatched.length > 0 &&
|
2779 |
+
( matchedCount + setMatchers.length ) > 1 ) {
|
2780 |
+
|
2781 |
+
Sizzle.uniqueSort( results );
|
2782 |
+
}
|
2783 |
+
}
|
2784 |
+
|
2785 |
+
// Override manipulation of globals by nested matchers
|
2786 |
+
if ( outermost ) {
|
2787 |
+
dirruns = dirrunsUnique;
|
2788 |
+
outermostContext = contextBackup;
|
2789 |
+
}
|
2790 |
+
|
2791 |
+
return unmatched;
|
2792 |
+
};
|
2793 |
+
|
2794 |
+
return bySet ?
|
2795 |
+
markFunction( superMatcher ) :
|
2796 |
+
superMatcher;
|
2797 |
+
}
|
2798 |
+
|
2799 |
+
compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
|
2800 |
+
var i,
|
2801 |
+
setMatchers = [],
|
2802 |
+
elementMatchers = [],
|
2803 |
+
cached = compilerCache[ selector + " " ];
|
2804 |
+
|
2805 |
+
if ( !cached ) {
|
2806 |
+
// Generate a function of recursive functions that can be used to check each element
|
2807 |
+
if ( !match ) {
|
2808 |
+
match = tokenize( selector );
|
2809 |
+
}
|
2810 |
+
i = match.length;
|
2811 |
+
while ( i-- ) {
|
2812 |
+
cached = matcherFromTokens( match[i] );
|
2813 |
+
if ( cached[ expando ] ) {
|
2814 |
+
setMatchers.push( cached );
|
2815 |
+
} else {
|
2816 |
+
elementMatchers.push( cached );
|
2817 |
+
}
|
2818 |
+
}
|
2819 |
+
|
2820 |
+
// Cache the compiled function
|
2821 |
+
cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
|
2822 |
+
|
2823 |
+
// Save selector and tokenization
|
2824 |
+
cached.selector = selector;
|
2825 |
+
}
|
2826 |
+
return cached;
|
2827 |
+
};
|
2828 |
+
|
2829 |
+
/**
|
2830 |
+
* A low-level selection function that works with Sizzle's compiled
|
2831 |
+
* selector functions
|
2832 |
+
* @param {String|Function} selector A selector or a pre-compiled
|
2833 |
+
* selector function built with Sizzle.compile
|
2834 |
+
* @param {Element} context
|
2835 |
+
* @param {Array} [results]
|
2836 |
+
* @param {Array} [seed] A set of elements to match against
|
2837 |
+
*/
|
2838 |
+
select = Sizzle.select = function( selector, context, results, seed ) {
|
2839 |
+
var i, tokens, token, type, find,
|
2840 |
+
compiled = typeof selector === "function" && selector,
|
2841 |
+
match = !seed && tokenize( (selector = compiled.selector || selector) );
|
2842 |
+
|
2843 |
+
results = results || [];
|
2844 |
+
|
2845 |
+
// Try to minimize operations if there is only one selector in the list and no seed
|
2846 |
+
// (the latter of which guarantees us context)
|
2847 |
+
if ( match.length === 1 ) {
|
2848 |
+
|
2849 |
+
// Reduce context if the leading compound selector is an ID
|
2850 |
+
tokens = match[0] = match[0].slice( 0 );
|
2851 |
+
if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
|
2852 |
+
context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) {
|
2853 |
+
|
2854 |
+
context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
|
2855 |
+
if ( !context ) {
|
2856 |
+
return results;
|
2857 |
+
|
2858 |
+
// Precompiled matchers will still verify ancestry, so step up a level
|
2859 |
+
} else if ( compiled ) {
|
2860 |
+
context = context.parentNode;
|
2861 |
+
}
|
2862 |
+
|
2863 |
+
selector = selector.slice( tokens.shift().value.length );
|
2864 |
+
}
|
2865 |
+
|
2866 |
+
// Fetch a seed set for right-to-left matching
|
2867 |
+
i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
|
2868 |
+
while ( i-- ) {
|
2869 |
+
token = tokens[i];
|
2870 |
+
|
2871 |
+
// Abort if we hit a combinator
|
2872 |
+
if ( Expr.relative[ (type = token.type) ] ) {
|
2873 |
+
break;
|
2874 |
+
}
|
2875 |
+
if ( (find = Expr.find[ type ]) ) {
|
2876 |
+
// Search, expanding context for leading sibling combinators
|
2877 |
+
if ( (seed = find(
|
2878 |
+
token.matches[0].replace( runescape, funescape ),
|
2879 |
+
rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
|
2880 |
+
)) ) {
|
2881 |
+
|
2882 |
+
// If seed is empty or no tokens remain, we can return early
|
2883 |
+
tokens.splice( i, 1 );
|
2884 |
+
selector = seed.length && toSelector( tokens );
|
2885 |
+
if ( !selector ) {
|
2886 |
+
push.apply( results, seed );
|
2887 |
+
return results;
|
2888 |
+
}
|
2889 |
+
|
2890 |
+
break;
|
2891 |
+
}
|
2892 |
+
}
|
2893 |
+
}
|
2894 |
+
}
|
2895 |
+
|
2896 |
+
// Compile and execute a filtering function if one is not provided
|
2897 |
+
// Provide `match` to avoid retokenization if we modified the selector above
|
2898 |
+
( compiled || compile( selector, match ) )(
|
2899 |
+
seed,
|
2900 |
+
context,
|
2901 |
+
!documentIsHTML,
|
2902 |
+
results,
|
2903 |
+
!context || rsibling.test( selector ) && testContext( context.parentNode ) || context
|
2904 |
+
);
|
2905 |
+
return results;
|
2906 |
+
};
|
2907 |
+
|
2908 |
+
// One-time assignments
|
2909 |
+
|
2910 |
+
// Sort stability
|
2911 |
+
support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
|
2912 |
+
|
2913 |
+
// Support: Chrome 14-35+
|
2914 |
+
// Always assume duplicates if they aren't passed to the comparison function
|
2915 |
+
support.detectDuplicates = !!hasDuplicate;
|
2916 |
+
|
2917 |
+
// Initialize against the default document
|
2918 |
+
setDocument();
|
2919 |
+
|
2920 |
+
// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
|
2921 |
+
// Detached nodes confoundingly follow *each other*
|
2922 |
+
support.sortDetached = assert(function( el ) {
|
2923 |
+
// Should return 1, but returns 4 (following)
|
2924 |
+
return el.compareDocumentPosition( document.createElement("fieldset") ) & 1;
|
2925 |
+
});
|
2926 |
+
|
2927 |
+
// Support: IE<8
|
2928 |
+
// Prevent attribute/property "interpolation"
|
2929 |
+
// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
|
2930 |
+
if ( !assert(function( el ) {
|
2931 |
+
el.innerHTML = "<a href='#'></a>";
|
2932 |
+
return el.firstChild.getAttribute("href") === "#" ;
|
2933 |
+
}) ) {
|
2934 |
+
addHandle( "type|href|height|width", function( elem, name, isXML ) {
|
2935 |
+
if ( !isXML ) {
|
2936 |
+
return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
|
2937 |
+
}
|
2938 |
+
});
|
2939 |
+
}
|
2940 |
+
|
2941 |
+
// Support: IE<9
|
2942 |
+
// Use defaultValue in place of getAttribute("value")
|
2943 |
+
if ( !support.attributes || !assert(function( el ) {
|
2944 |
+
el.innerHTML = "<input/>";
|
2945 |
+
el.firstChild.setAttribute( "value", "" );
|
2946 |
+
return el.firstChild.getAttribute( "value" ) === "";
|
2947 |
+
}) ) {
|
2948 |
+
addHandle( "value", function( elem, name, isXML ) {
|
2949 |
+
if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
|
2950 |
+
return elem.defaultValue;
|
2951 |
+
}
|
2952 |
+
});
|
2953 |
+
}
|
2954 |
+
|
2955 |
+
// Support: IE<9
|
2956 |
+
// Use getAttributeNode to fetch booleans when getAttribute lies
|
2957 |
+
if ( !assert(function( el ) {
|
2958 |
+
return el.getAttribute("disabled") == null;
|
2959 |
+
}) ) {
|
2960 |
+
addHandle( booleans, function( elem, name, isXML ) {
|
2961 |
+
var val;
|
2962 |
+
if ( !isXML ) {
|
2963 |
+
return elem[ name ] === true ? name.toLowerCase() :
|
2964 |
+
(val = elem.getAttributeNode( name )) && val.specified ?
|
2965 |
+
val.value :
|
2966 |
+
null;
|
2967 |
+
}
|
2968 |
+
});
|
2969 |
+
}
|
2970 |
+
|
2971 |
+
return Sizzle;
|
2972 |
+
|
2973 |
+
})( window );
|
2974 |
+
|
2975 |
+
|
2976 |
+
|
2977 |
+
jQuery.find = Sizzle;
|
2978 |
+
jQuery.expr = Sizzle.selectors;
|
2979 |
+
|
2980 |
+
// Deprecated
|
2981 |
+
jQuery.expr[ ":" ] = jQuery.expr.pseudos;
|
2982 |
+
jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;
|
2983 |
+
jQuery.text = Sizzle.getText;
|
2984 |
+
jQuery.isXMLDoc = Sizzle.isXML;
|
2985 |
+
jQuery.contains = Sizzle.contains;
|
2986 |
+
jQuery.escapeSelector = Sizzle.escape;
|
2987 |
+
|
2988 |
+
|
2989 |
+
|
2990 |
+
|
2991 |
+
var dir = function( elem, dir, until ) {
|
2992 |
+
var matched = [],
|
2993 |
+
truncate = until !== undefined;
|
2994 |
+
|
2995 |
+
while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {
|
2996 |
+
if ( elem.nodeType === 1 ) {
|
2997 |
+
if ( truncate && jQuery( elem ).is( until ) ) {
|
2998 |
+
break;
|
2999 |
+
}
|
3000 |
+
matched.push( elem );
|
3001 |
+
}
|
3002 |
+
}
|
3003 |
+
return matched;
|
3004 |
+
};
|
3005 |
+
|
3006 |
+
|
3007 |
+
var siblings = function( n, elem ) {
|
3008 |
+
var matched = [];
|
3009 |
+
|
3010 |
+
for ( ; n; n = n.nextSibling ) {
|
3011 |
+
if ( n.nodeType === 1 && n !== elem ) {
|
3012 |
+
matched.push( n );
|
3013 |
+
}
|
3014 |
+
}
|
3015 |
+
|
3016 |
+
return matched;
|
3017 |
+
};
|
3018 |
+
|
3019 |
+
|
3020 |
+
var rneedsContext = jQuery.expr.match.needsContext;
|
3021 |
+
|
3022 |
+
|
3023 |
+
|
3024 |
+
function nodeName( elem, name ) {
|
3025 |
+
|
3026 |
+
return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
|
3027 |
+
|
3028 |
+
};
|
3029 |
+
var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i );
|
3030 |
+
|
3031 |
+
|
3032 |
+
|
3033 |
+
// Implement the identical functionality for filter and not
|
3034 |
+
function winnow( elements, qualifier, not ) {
|
3035 |
+
if ( isFunction( qualifier ) ) {
|
3036 |
+
return jQuery.grep( elements, function( elem, i ) {
|
3037 |
+
return !!qualifier.call( elem, i, elem ) !== not;
|
3038 |
+
} );
|
3039 |
+
}
|
3040 |
+
|
3041 |
+
// Single element
|
3042 |
+
if ( qualifier.nodeType ) {
|
3043 |
+
return jQuery.grep( elements, function( elem ) {
|
3044 |
+
return ( elem === qualifier ) !== not;
|
3045 |
+
} );
|
3046 |
+
}
|
3047 |
+
|
3048 |
+
// Arraylike of elements (jQuery, arguments, Array)
|
3049 |
+
if ( typeof qualifier !== "string" ) {
|
3050 |
+
return jQuery.grep( elements, function( elem ) {
|
3051 |
+
return ( indexOf.call( qualifier, elem ) > -1 ) !== not;
|
3052 |
+
} );
|
3053 |
+
}
|
3054 |
+
|
3055 |
+
// Filtered directly for both simple and complex selectors
|
3056 |
+
return jQuery.filter( qualifier, elements, not );
|
3057 |
+
}
|
3058 |
+
|
3059 |
+
jQuery.filter = function( expr, elems, not ) {
|
3060 |
+
var elem = elems[ 0 ];
|
3061 |
+
|
3062 |
+
if ( not ) {
|
3063 |
+
expr = ":not(" + expr + ")";
|
3064 |
+
}
|
3065 |
+
|
3066 |
+
if ( elems.length === 1 && elem.nodeType === 1 ) {
|
3067 |
+
return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];
|
3068 |
+
}
|
3069 |
+
|
3070 |
+
return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
|
3071 |
+
return elem.nodeType === 1;
|
3072 |
+
} ) );
|
3073 |
+
};
|
3074 |
+
|
3075 |
+
jQuery.fn.extend( {
|
3076 |
+
find: function( selector ) {
|
3077 |
+
var i, ret,
|
3078 |
+
len = this.length,
|
3079 |
+
self = this;
|
3080 |
+
|
3081 |
+
if ( typeof selector !== "string" ) {
|
3082 |
+
return this.pushStack( jQuery( selector ).filter( function() {
|
3083 |
+
for ( i = 0; i < len; i++ ) {
|
3084 |
+
if ( jQuery.contains( self[ i ], this ) ) {
|
3085 |
+
return true;
|
3086 |
+
}
|
3087 |
+
}
|
3088 |
+
} ) );
|
3089 |
+
}
|
3090 |
+
|
3091 |
+
ret = this.pushStack( [] );
|
3092 |
+
|
3093 |
+
for ( i = 0; i < len; i++ ) {
|
3094 |
+
jQuery.find( selector, self[ i ], ret );
|
3095 |
+
}
|
3096 |
+
|
3097 |
+
return len > 1 ? jQuery.uniqueSort( ret ) : ret;
|
3098 |
+
},
|
3099 |
+
filter: function( selector ) {
|
3100 |
+
return this.pushStack( winnow( this, selector || [], false ) );
|
3101 |
+
},
|
3102 |
+
not: function( selector ) {
|
3103 |
+
return this.pushStack( winnow( this, selector || [], true ) );
|
3104 |
+
},
|
3105 |
+
is: function( selector ) {
|
3106 |
+
return !!winnow(
|
3107 |
+
this,
|
3108 |
+
|
3109 |
+
// If this is a positional/relative selector, check membership in the returned set
|
3110 |
+
// so $("p:first").is("p:last") won't return true for a doc with two "p".
|
3111 |
+
typeof selector === "string" && rneedsContext.test( selector ) ?
|
3112 |
+
jQuery( selector ) :
|
3113 |
+
selector || [],
|
3114 |
+
false
|
3115 |
+
).length;
|
3116 |
+
}
|
3117 |
+
} );
|
3118 |
+
|
3119 |
+
|
3120 |
+
// Initialize a jQuery object
|
3121 |
+
|
3122 |
+
|
3123 |
+
// A central reference to the root jQuery(document)
|
3124 |
+
var rootjQuery,
|
3125 |
+
|
3126 |
+
// A simple way to check for HTML strings
|
3127 |
+
// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
|
3128 |
+
// Strict HTML recognition (#11290: must start with <)
|
3129 |
+
// Shortcut simple #id case for speed
|
3130 |
+
rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,
|
3131 |
+
|
3132 |
+
init = jQuery.fn.init = function( selector, context, root ) {
|
3133 |
+
var match, elem;
|
3134 |
+
|
3135 |
+
// HANDLE: $(""), $(null), $(undefined), $(false)
|
3136 |
+
if ( !selector ) {
|
3137 |
+
return this;
|
3138 |
+
}
|
3139 |
+
|
3140 |
+
// Method init() accepts an alternate rootjQuery
|
3141 |
+
// so migrate can support jQuery.sub (gh-2101)
|
3142 |
+
root = root || rootjQuery;
|
3143 |
+
|
3144 |
+
// Handle HTML strings
|
3145 |
+
if ( typeof selector === "string" ) {
|
3146 |
+
if ( selector[ 0 ] === "<" &&
|
3147 |
+
selector[ selector.length - 1 ] === ">" &&
|
3148 |
+
selector.length >= 3 ) {
|
3149 |
+
|
3150 |
+
// Assume that strings that start and end with <> are HTML and skip the regex check
|
3151 |
+
match = [ null, selector, null ];
|
3152 |
+
|
3153 |
+
} else {
|
3154 |
+
match = rquickExpr.exec( selector );
|
3155 |
+
}
|
3156 |
+
|
3157 |
+
// Match html or make sure no context is specified for #id
|
3158 |
+
if ( match && ( match[ 1 ] || !context ) ) {
|
3159 |
+
|
3160 |
+
// HANDLE: $(html) -> $(array)
|
3161 |
+
if ( match[ 1 ] ) {
|
3162 |
+
context = context instanceof jQuery ? context[ 0 ] : context;
|
3163 |
+
|
3164 |
+
// Option to run scripts is true for back-compat
|
3165 |
+
// Intentionally let the error be thrown if parseHTML is not present
|
3166 |
+
jQuery.merge( this, jQuery.parseHTML(
|
3167 |
+
match[ 1 ],
|
3168 |
+
context && context.nodeType ? context.ownerDocument || context : document,
|
3169 |
+
true
|
3170 |
+
) );
|
3171 |
+
|
3172 |
+
// HANDLE: $(html, props)
|
3173 |
+
if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {
|
3174 |
+
for ( match in context ) {
|
3175 |
+
|
3176 |
+
// Properties of context are called as methods if possible
|
3177 |
+
if ( isFunction( this[ match ] ) ) {
|
3178 |
+
this[ match ]( context[ match ] );
|
3179 |
+
|
3180 |
+
// ...and otherwise set as attributes
|
3181 |
+
} else {
|
3182 |
+
this.attr( match, context[ match ] );
|
3183 |
+
}
|
3184 |
+
}
|
3185 |
+
}
|
3186 |
+
|
3187 |
+
return this;
|
3188 |
+
|
3189 |
+
// HANDLE: $(#id)
|
3190 |
+
} else {
|
3191 |
+
elem = document.getElementById( match[ 2 ] );
|
3192 |
+
|
3193 |
+
if ( elem ) {
|
3194 |
+
|
3195 |
+
// Inject the element directly into the jQuery object
|
3196 |
+
this[ 0 ] = elem;
|
3197 |
+
this.length = 1;
|
3198 |
+
}
|
3199 |
+
return this;
|
3200 |
+
}
|
3201 |
+
|
3202 |
+
// HANDLE: $(expr, $(...))
|
3203 |
+
} else if ( !context || context.jquery ) {
|
3204 |
+
return ( context || root ).find( selector );
|
3205 |
+
|
3206 |
+
// HANDLE: $(expr, context)
|
3207 |
+
// (which is just equivalent to: $(context).find(expr)
|
3208 |
+
} else {
|
3209 |
+
return this.constructor( context ).find( selector );
|
3210 |
+
}
|
3211 |
+
|
3212 |
+
// HANDLE: $(DOMElement)
|
3213 |
+
} else if ( selector.nodeType ) {
|
3214 |
+
this[ 0 ] = selector;
|
3215 |
+
this.length = 1;
|
3216 |
+
return this;
|
3217 |
+
|
3218 |
+
// HANDLE: $(function)
|
3219 |
+
// Shortcut for document ready
|
3220 |
+
} else if ( isFunction( selector ) ) {
|
3221 |
+
return root.ready !== undefined ?
|
3222 |
+
root.ready( selector ) :
|
3223 |
+
|
3224 |
+
// Execute immediately if ready is not present
|
3225 |
+
selector( jQuery );
|
3226 |
+
}
|
3227 |
+
|
3228 |
+
return jQuery.makeArray( selector, this );
|
3229 |
+
};
|
3230 |
+
|
3231 |
+
// Give the init function the jQuery prototype for later instantiation
|
3232 |
+
init.prototype = jQuery.fn;
|
3233 |
+
|
3234 |
+
// Initialize central reference
|
3235 |
+
rootjQuery = jQuery( document );
|
3236 |
+
|
3237 |
+
|
3238 |
+
var rparentsprev = /^(?:parents|prev(?:Until|All))/,
|
3239 |
+
|
3240 |
+
// Methods guaranteed to produce a unique set when starting from a unique set
|
3241 |
+
guaranteedUnique = {
|
3242 |
+
children: true,
|
3243 |
+
contents: true,
|
3244 |
+
next: true,
|
3245 |
+
prev: true
|
3246 |
+
};
|
3247 |
+
|
3248 |
+
jQuery.fn.extend( {
|
3249 |
+
has: function( target ) {
|
3250 |
+
var targets = jQuery( target, this ),
|
3251 |
+
l = targets.length;
|
3252 |
+
|
3253 |
+
return this.filter( function() {
|
3254 |
+
var i = 0;
|
3255 |
+
for ( ; i < l; i++ ) {
|
3256 |
+
if ( jQuery.contains( this, targets[ i ] ) ) {
|
3257 |
+
return true;
|
3258 |
+
}
|
3259 |
+
}
|
3260 |
+
} );
|
3261 |
+
},
|
3262 |
+
|
3263 |
+
closest: function( selectors, context ) {
|
3264 |
+
var cur,
|
3265 |
+
i = 0,
|
3266 |
+
l = this.length,
|
3267 |
+
matched = [],
|
3268 |
+
targets = typeof selectors !== "string" && jQuery( selectors );
|
3269 |
+
|
3270 |
+
// Positional selectors never match, since there's no _selection_ context
|
3271 |
+
if ( !rneedsContext.test( selectors ) ) {
|
3272 |
+
for ( ; i < l; i++ ) {
|
3273 |
+
for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {
|
3274 |
+
|
3275 |
+
// Always skip document fragments
|
3276 |
+
if ( cur.nodeType < 11 && ( targets ?
|
3277 |
+
targets.index( cur ) > -1 :
|
3278 |
+
|
3279 |
+
// Don't pass non-elements to Sizzle
|
3280 |
+
cur.nodeType === 1 &&
|
3281 |
+
jQuery.find.matchesSelector( cur, selectors ) ) ) {
|
3282 |
+
|
3283 |
+
matched.push( cur );
|
3284 |
+
break;
|
3285 |
+
}
|
3286 |
+
}
|
3287 |
+
}
|
3288 |
+
}
|
3289 |
+
|
3290 |
+
return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );
|
3291 |
+
},
|
3292 |
+
|
3293 |
+
// Determine the position of an element within the set
|
3294 |
+
index: function( elem ) {
|
3295 |
+
|
3296 |
+
// No argument, return index in parent
|
3297 |
+
if ( !elem ) {
|
3298 |
+
return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
|
3299 |
+
}
|
3300 |
+
|
3301 |
+
// Index in selector
|
3302 |
+
if ( typeof elem === "string" ) {
|
3303 |
+
return indexOf.call( jQuery( elem ), this[ 0 ] );
|
3304 |
+
}
|
3305 |
+
|
3306 |
+
// Locate the position of the desired element
|
3307 |
+
return indexOf.call( this,
|
3308 |
+
|
3309 |
+
// If it receives a jQuery object, the first element is used
|
3310 |
+
elem.jquery ? elem[ 0 ] : elem
|
3311 |
+
);
|
3312 |
+
},
|
3313 |
+
|
3314 |
+
add: function( selector, context ) {
|
3315 |
+
return this.pushStack(
|
3316 |
+
jQuery.uniqueSort(
|
3317 |
+
jQuery.merge( this.get(), jQuery( selector, context ) )
|
3318 |
+
)
|
3319 |
+
);
|
3320 |
+
},
|
3321 |
+
|
3322 |
+
addBack: function( selector ) {
|
3323 |
+
return this.add( selector == null ?
|
3324 |
+
this.prevObject : this.prevObject.filter( selector )
|
3325 |
+
);
|
3326 |
+
}
|
3327 |
+
} );
|
3328 |
+
|
3329 |
+
function sibling( cur, dir ) {
|
3330 |
+
while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}
|
3331 |
+
return cur;
|
3332 |
+
}
|
3333 |
+
|
3334 |
+
jQuery.each( {
|
3335 |
+
parent: function( elem ) {
|
3336 |
+
var parent = elem.parentNode;
|
3337 |
+
return parent && parent.nodeType !== 11 ? parent : null;
|
3338 |
+
},
|
3339 |
+
parents: function( elem ) {
|
3340 |
+
return dir( elem, "parentNode" );
|
3341 |
+
},
|
3342 |
+
parentsUntil: function( elem, i, until ) {
|
3343 |
+
return dir( elem, "parentNode", until );
|
3344 |
+
},
|
3345 |
+
next: function( elem ) {
|
3346 |
+
return sibling( elem, "nextSibling" );
|
3347 |
+
},
|
3348 |
+
prev: function( elem ) {
|
3349 |
+
return sibling( elem, "previousSibling" );
|
3350 |
+
},
|
3351 |
+
nextAll: function( elem ) {
|
3352 |
+
return dir( elem, "nextSibling" );
|
3353 |
+
},
|
3354 |
+
prevAll: function( elem ) {
|
3355 |
+
return dir( elem, "previousSibling" );
|
3356 |
+
},
|
3357 |
+
nextUntil: function( elem, i, until ) {
|
3358 |
+
return dir( elem, "nextSibling", until );
|
3359 |
+
},
|
3360 |
+
prevUntil: function( elem, i, until ) {
|
3361 |
+
return dir( elem, "previousSibling", until );
|
3362 |
+
},
|
3363 |
+
siblings: function( elem ) {
|
3364 |
+
return siblings( ( elem.parentNode || {} ).firstChild, elem );
|
3365 |
+
},
|
3366 |
+
children: function( elem ) {
|
3367 |
+
return siblings( elem.firstChild );
|
3368 |
+
},
|
3369 |
+
contents: function( elem ) {
|
3370 |
+
if ( nodeName( elem, "iframe" ) ) {
|
3371 |
+
return elem.contentDocument;
|
3372 |
+
}
|
3373 |
+
|
3374 |
+
// Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only
|
3375 |
+
// Treat the template element as a regular one in browsers that
|
3376 |
+
// don't support it.
|
3377 |
+
if ( nodeName( elem, "template" ) ) {
|
3378 |
+
elem = elem.content || elem;
|
3379 |
+
}
|
3380 |
+
|
3381 |
+
return jQuery.merge( [], elem.childNodes );
|
3382 |
+
}
|
3383 |
+
}, function( name, fn ) {
|
3384 |
+
jQuery.fn[ name ] = function( until, selector ) {
|
3385 |
+
var matched = jQuery.map( this, fn, until );
|
3386 |
+
|
3387 |
+
if ( name.slice( -5 ) !== "Until" ) {
|
3388 |
+
selector = until;
|
3389 |
+
}
|
3390 |
+
|
3391 |
+
if ( selector && typeof selector === "string" ) {
|
3392 |
+
matched = jQuery.filter( selector, matched );
|
3393 |
+
}
|
3394 |
+
|
3395 |
+
if ( this.length > 1 ) {
|
3396 |
+
|
3397 |
+
// Remove duplicates
|
3398 |
+
if ( !guaranteedUnique[ name ] ) {
|
3399 |
+
jQuery.uniqueSort( matched );
|
3400 |
+
}
|
3401 |
+
|
3402 |
+
// Reverse order for parents* and prev-derivatives
|
3403 |
+
if ( rparentsprev.test( name ) ) {
|
3404 |
+
matched.reverse();
|
3405 |
+
}
|
3406 |
+
}
|
3407 |
+
|
3408 |
+
return this.pushStack( matched );
|
3409 |
+
};
|
3410 |
+
} );
|
3411 |
+
var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g );
|
3412 |
+
|
3413 |
+
|
3414 |
+
|
3415 |
+
// Convert String-formatted options into Object-formatted ones
|
3416 |
+
function createOptions( options ) {
|
3417 |
+
var object = {};
|
3418 |
+
jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {
|
3419 |
+
object[ flag ] = true;
|
3420 |
+
} );
|
3421 |
+
return object;
|
3422 |
+
}
|
3423 |
+
|
3424 |
+
/*
|
3425 |
+
* Create a callback list using the following parameters:
|
3426 |
+
*
|
3427 |
+
* options: an optional list of space-separated options that will change how
|
3428 |
+
* the callback list behaves or a more traditional option object
|
3429 |
+
*
|
3430 |
+
* By default a callback list will act like an event callback list and can be
|
3431 |
+
* "fired" multiple times.
|
3432 |
+
*
|
3433 |
+
* Possible options:
|
3434 |
+
*
|
3435 |
+
* once: will ensure the callback list can only be fired once (like a Deferred)
|
3436 |
+
*
|
3437 |
+
* memory: will keep track of previous values and will call any callback added
|
3438 |
+
* after the list has been fired right away with the latest "memorized"
|
3439 |
+
* values (like a Deferred)
|
3440 |
+
*
|
3441 |
+
* unique: will ensure a callback can only be added once (no duplicate in the list)
|
3442 |
+
*
|
3443 |
+
* stopOnFalse: interrupt callings when a callback returns false
|
3444 |
+
*
|
3445 |
+
*/
|
3446 |
+
jQuery.Callbacks = function( options ) {
|
3447 |
+
|
3448 |
+
// Convert options from String-formatted to Object-formatted if needed
|
3449 |
+
// (we check in cache first)
|
3450 |
+
options = typeof options === "string" ?
|
3451 |
+
createOptions( options ) :
|
3452 |
+
jQuery.extend( {}, options );
|
3453 |
+
|
3454 |
+
var // Flag to know if list is currently firing
|
3455 |
+
firing,
|
3456 |
+
|
3457 |
+
// Last fire value for non-forgettable lists
|
3458 |
+
memory,
|
3459 |
+
|
3460 |
+
// Flag to know if list was already fired
|
3461 |
+
fired,
|
3462 |
+
|
3463 |
+
// Flag to prevent firing
|
3464 |
+
locked,
|
3465 |
+
|
3466 |
+
// Actual callback list
|
3467 |
+
list = [],
|
3468 |
+
|
3469 |
+
// Queue of execution data for repeatable lists
|
3470 |
+
queue = [],
|
3471 |
+
|
3472 |
+
// Index of currently firing callback (modified by add/remove as needed)
|
3473 |
+
firingIndex = -1,
|
3474 |
+
|
3475 |
+
// Fire callbacks
|
3476 |
+
fire = function() {
|
3477 |
+
|
3478 |
+
// Enforce single-firing
|
3479 |
+
locked = locked || options.once;
|
3480 |
+
|
3481 |
+
// Execute callbacks for all pending executions,
|
3482 |
+
// respecting firingIndex overrides and runtime changes
|
3483 |
+
fired = firing = true;
|
3484 |
+
for ( ; queue.length; firingIndex = -1 ) {
|
3485 |
+
memory = queue.shift();
|
3486 |
+
while ( ++firingIndex < list.length ) {
|
3487 |
+
|
3488 |
+
// Run callback and check for early termination
|
3489 |
+
if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
|
3490 |
+
options.stopOnFalse ) {
|
3491 |
+
|
3492 |
+
// Jump to end and forget the data so .add doesn't re-fire
|
3493 |
+
firingIndex = list.length;
|
3494 |
+
memory = false;
|
3495 |
+
}
|
3496 |
+
}
|
3497 |
+
}
|
3498 |
+
|
3499 |
+
// Forget the data if we're done with it
|
3500 |
+
if ( !options.memory ) {
|
3501 |
+
memory = false;
|
3502 |
+
}
|
3503 |
+
|
3504 |
+
firing = false;
|
3505 |
+
|
3506 |
+
// Clean up if we're done firing for good
|
3507 |
+
if ( locked ) {
|
3508 |
+
|
3509 |
+
// Keep an empty list if we have data for future add calls
|
3510 |
+
if ( memory ) {
|
3511 |
+
list = [];
|
3512 |
+
|
3513 |
+
// Otherwise, this object is spent
|
3514 |
+
} else {
|
3515 |
+
list = "";
|
3516 |
+
}
|
3517 |
+
}
|
3518 |
+
},
|
3519 |
+
|
3520 |
+
// Actual Callbacks object
|
3521 |
+
self = {
|
3522 |
+
|
3523 |
+
// Add a callback or a collection of callbacks to the list
|
3524 |
+
add: function() {
|
3525 |
+
if ( list ) {
|
3526 |
+
|
3527 |
+
// If we have memory from a past run, we should fire after adding
|
3528 |
+
if ( memory && !firing ) {
|
3529 |
+
firingIndex = list.length - 1;
|
3530 |
+
queue.push( memory );
|
3531 |
+
}
|
3532 |
+
|
3533 |
+
( function add( args ) {
|
3534 |
+
jQuery.each( args, function( _, arg ) {
|
3535 |
+
if ( isFunction( arg ) ) {
|
3536 |
+
if ( !options.unique || !self.has( arg ) ) {
|
3537 |
+
list.push( arg );
|
3538 |
+
}
|
3539 |
+
} else if ( arg && arg.length && toType( arg ) !== "string" ) {
|
3540 |
+
|
3541 |
+
// Inspect recursively
|
3542 |
+
add( arg );
|
3543 |
+
}
|
3544 |
+
} );
|
3545 |
+
} )( arguments );
|
3546 |
+
|
3547 |
+
if ( memory && !firing ) {
|
3548 |
+
fire();
|
3549 |
+
}
|
3550 |
+
}
|
3551 |
+
return this;
|
3552 |
+
},
|
3553 |
+
|
3554 |
+
// Remove a callback from the list
|
3555 |
+
remove: function() {
|
3556 |
+
jQuery.each( arguments, function( _, arg ) {
|
3557 |
+
var index;
|
3558 |
+
while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
|
3559 |
+
list.splice( index, 1 );
|
3560 |
+
|
3561 |
+
// Handle firing indexes
|
3562 |
+
if ( index <= firingIndex ) {
|
3563 |
+
firingIndex--;
|
3564 |
+
}
|
3565 |
+
}
|
3566 |
+
} );
|
3567 |
+
return this;
|
3568 |
+
},
|
3569 |
+
|
3570 |
+
// Check if a given callback is in the list.
|
3571 |
+
// If no argument is given, return whether or not list has callbacks attached.
|
3572 |
+
has: function( fn ) {
|
3573 |
+
return fn ?
|
3574 |
+
jQuery.inArray( fn, list ) > -1 :
|
3575 |
+
list.length > 0;
|
3576 |
+
},
|
3577 |
+
|
3578 |
+
// Remove all callbacks from the list
|
3579 |
+
empty: function() {
|
3580 |
+
if ( list ) {
|
3581 |
+
list = [];
|
3582 |
+
}
|
3583 |
+
return this;
|
3584 |
+
},
|
3585 |
+
|
3586 |
+
// Disable .fire and .add
|
3587 |
+
// Abort any current/pending executions
|
3588 |
+
// Clear all callbacks and values
|
3589 |
+
disable: function() {
|
3590 |
+
locked = queue = [];
|
3591 |
+
list = memory = "";
|
3592 |
+
return this;
|
3593 |
+
},
|
3594 |
+
disabled: function() {
|
3595 |
+
return !list;
|
3596 |
+
},
|
3597 |
+
|
3598 |
+
// Disable .fire
|
3599 |
+
// Also disable .add unless we have memory (since it would have no effect)
|
3600 |
+
// Abort any pending executions
|
3601 |
+
lock: function() {
|
3602 |
+
locked = queue = [];
|
3603 |
+
if ( !memory && !firing ) {
|
3604 |
+
list = memory = "";
|
3605 |
+
}
|
3606 |
+
return this;
|
3607 |
+
},
|
3608 |
+
locked: function() {
|
3609 |
+
return !!locked;
|
3610 |
+
},
|
3611 |
+
|
3612 |
+
// Call all callbacks with the given context and arguments
|
3613 |
+
fireWith: function( context, args ) {
|
3614 |
+
if ( !locked ) {
|
3615 |
+
args = args || [];
|
3616 |
+
args = [ context, args.slice ? args.slice() : args ];
|
3617 |
+
queue.push( args );
|
3618 |
+
if ( !firing ) {
|
3619 |
+
fire();
|
3620 |
+
}
|
3621 |
+
}
|
3622 |
+
return this;
|
3623 |
+
},
|
3624 |
+
|
3625 |
+
// Call all the callbacks with the given arguments
|
3626 |
+
fire: function() {
|
3627 |
+
self.fireWith( this, arguments );
|
3628 |
+
return this;
|
3629 |
+
},
|
3630 |
+
|
3631 |
+
// To know if the callbacks have already been called at least once
|
3632 |
+
fired: function() {
|
3633 |
+
return !!fired;
|
3634 |
+
}
|
3635 |
+
};
|
3636 |
+
|
3637 |
+
return self;
|
3638 |
+
};
|
3639 |
+
|
3640 |
+
|
3641 |
+
function Identity( v ) {
|
3642 |
+
return v;
|
3643 |
+
}
|
3644 |
+
function Thrower( ex ) {
|
3645 |
+
throw ex;
|
3646 |
+
}
|
3647 |
+
|
3648 |
+
function adoptValue( value, resolve, reject, noValue ) {
|
3649 |
+
var method;
|
3650 |
+
|
3651 |
+
try {
|
3652 |
+
|
3653 |
+
// Check for promise aspect first to privilege synchronous behavior
|
3654 |
+
if ( value && isFunction( ( method = value.promise ) ) ) {
|
3655 |
+
method.call( value ).done( resolve ).fail( reject );
|
3656 |
+
|
3657 |
+
// Other thenables
|
3658 |
+
} else if ( value && isFunction( ( method = value.then ) ) ) {
|
3659 |
+
method.call( value, resolve, reject );
|
3660 |
+
|
3661 |
+
// Other non-thenables
|
3662 |
+
} else {
|
3663 |
+
|
3664 |
+
// Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:
|
3665 |
+
// * false: [ value ].slice( 0 ) => resolve( value )
|
3666 |
+
// * true: [ value ].slice( 1 ) => resolve()
|
3667 |
+
resolve.apply( undefined, [ value ].slice( noValue ) );
|
3668 |
+
}
|
3669 |
+
|
3670 |
+
// For Promises/A+, convert exceptions into rejections
|
3671 |
+
// Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in
|
3672 |
+
// Deferred#then to conditionally suppress rejection.
|
3673 |
+
} catch ( value ) {
|
3674 |
+
|
3675 |
+
// Support: Android 4.0 only
|
3676 |
+
// Strict mode functions invoked without .call/.apply get global-object context
|
3677 |
+
reject.apply( undefined, [ value ] );
|
3678 |
+
}
|
3679 |
+
}
|
3680 |
+
|
3681 |
+
jQuery.extend( {
|
3682 |
+
|
3683 |
+
Deferred: function( func ) {
|
3684 |
+
var tuples = [
|
3685 |
+
|
3686 |
+
// action, add listener, callbacks,
|
3687 |
+
// ... .then handlers, argument index, [final state]
|
3688 |
+
[ "notify", "progress", jQuery.Callbacks( "memory" ),
|
3689 |
+
jQuery.Callbacks( "memory" ), 2 ],
|
3690 |
+
[ "resolve", "done", jQuery.Callbacks( "once memory" ),
|
3691 |
+
jQuery.Callbacks( "once memory" ), 0, "resolved" ],
|
3692 |
+
[ "reject", "fail", jQuery.Callbacks( "once memory" ),
|
3693 |
+
jQuery.Callbacks( "once memory" ), 1, "rejected" ]
|
3694 |
+
],
|
3695 |
+
state = "pending",
|
3696 |
+
promise = {
|
3697 |
+
state: function() {
|
3698 |
+
return state;
|
3699 |
+
},
|
3700 |
+
always: function() {
|
3701 |
+
deferred.done( arguments ).fail( arguments );
|
3702 |
+
return this;
|
3703 |
+
},
|
3704 |
+
"catch": function( fn ) {
|
3705 |
+
return promise.then( null, fn );
|
3706 |
+
},
|
3707 |
+
|
3708 |
+
// Keep pipe for back-compat
|
3709 |
+
pipe: function( /* fnDone, fnFail, fnProgress */ ) {
|
3710 |
+
var fns = arguments;
|
3711 |
+
|
3712 |
+
return jQuery.Deferred( function( newDefer ) {
|
3713 |
+
jQuery.each( tuples, function( i, tuple ) {
|
3714 |
+
|
3715 |
+
// Map tuples (progress, done, fail) to arguments (done, fail, progress)
|
3716 |
+
var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];
|
3717 |
+
|
3718 |
+
// deferred.progress(function() { bind to newDefer or newDefer.notify })
|
3719 |
+
// deferred.done(function() { bind to newDefer or newDefer.resolve })
|
3720 |
+
// deferred.fail(function() { bind to newDefer or newDefer.reject })
|
3721 |
+
deferred[ tuple[ 1 ] ]( function() {
|
3722 |
+
var returned = fn && fn.apply( this, arguments );
|
3723 |
+
if ( returned && isFunction( returned.promise ) ) {
|
3724 |
+
returned.promise()
|
3725 |
+
.progress( newDefer.notify )
|
3726 |
+
.done( newDefer.resolve )
|
3727 |
+
.fail( newDefer.reject );
|
3728 |
+
} else {
|
3729 |
+
newDefer[ tuple[ 0 ] + "With" ](
|
3730 |
+
this,
|
3731 |
+
fn ? [ returned ] : arguments
|
3732 |
+
);
|
3733 |
+
}
|
3734 |
+
} );
|
3735 |
+
} );
|
3736 |
+
fns = null;
|
3737 |
+
} ).promise();
|
3738 |
+
},
|
3739 |
+
then: function( onFulfilled, onRejected, onProgress ) {
|
3740 |
+
var maxDepth = 0;
|
3741 |
+
function resolve( depth, deferred, handler, special ) {
|
3742 |
+
return function() {
|
3743 |
+
var that = this,
|
3744 |
+
args = arguments,
|
3745 |
+
mightThrow = function() {
|
3746 |
+
var returned, then;
|
3747 |
+
|
3748 |
+
// Support: Promises/A+ section 2.3.3.3.3
|
3749 |
+
// https://promisesaplus.com/#point-59
|
3750 |
+
// Ignore double-resolution attempts
|
3751 |
+
if ( depth < maxDepth ) {
|
3752 |
+
return;
|
3753 |
+
}
|
3754 |
+
|
3755 |
+
returned = handler.apply( that, args );
|
3756 |
+
|
3757 |
+
// Support: Promises/A+ section 2.3.1
|
3758 |
+
// https://promisesaplus.com/#point-48
|
3759 |
+
if ( returned === deferred.promise() ) {
|
3760 |
+
throw new TypeError( "Thenable self-resolution" );
|
3761 |
+
}
|
3762 |
+
|
3763 |
+
// Support: Promises/A+ sections 2.3.3.1, 3.5
|
3764 |
+
// https://promisesaplus.com/#point-54
|
3765 |
+
// https://promisesaplus.com/#point-75
|
3766 |
+
// Retrieve `then` only once
|
3767 |
+
then = returned &&
|
3768 |
+
|
3769 |
+
// Support: Promises/A+ section 2.3.4
|
3770 |
+
// https://promisesaplus.com/#point-64
|
3771 |
+
// Only check objects and functions for thenability
|
3772 |
+
( typeof returned === "object" ||
|
3773 |
+
typeof returned === "function" ) &&
|
3774 |
+
returned.then;
|
3775 |
+
|
3776 |
+
// Handle a returned thenable
|
3777 |
+
if ( isFunction( then ) ) {
|
3778 |
+
|
3779 |
+
// Special processors (notify) just wait for resolution
|
3780 |
+
if ( special ) {
|
3781 |
+
then.call(
|
3782 |
+
returned,
|
3783 |
+
resolve( maxDepth, deferred, Identity, special ),
|
3784 |
+
resolve( maxDepth, deferred, Thrower, special )
|
3785 |
+
);
|
3786 |
+
|
3787 |
+
// Normal processors (resolve) also hook into progress
|
3788 |
+
} else {
|
3789 |
+
|
3790 |
+
// ...and disregard older resolution values
|
3791 |
+
maxDepth++;
|
3792 |
+
|
3793 |
+
then.call(
|
3794 |
+
returned,
|
3795 |
+
resolve( maxDepth, deferred, Identity, special ),
|
3796 |
+
resolve( maxDepth, deferred, Thrower, special ),
|
3797 |
+
resolve( maxDepth, deferred, Identity,
|
3798 |
+
deferred.notifyWith )
|
3799 |
+
);
|
3800 |
+
}
|
3801 |
+
|
3802 |
+
// Handle all other returned values
|
3803 |
+
} else {
|
3804 |
+
|
3805 |
+
// Only substitute handlers pass on context
|
3806 |
+
// and multiple values (non-spec behavior)
|
3807 |
+
if ( handler !== Identity ) {
|
3808 |
+
that = undefined;
|
3809 |
+
args = [ returned ];
|
3810 |
+
}
|
3811 |
+
|
3812 |
+
// Process the value(s)
|
3813 |
+
// Default process is resolve
|
3814 |
+
( special || deferred.resolveWith )( that, args );
|
3815 |
+
}
|
3816 |
+
},
|
3817 |
+
|
3818 |
+
// Only normal processors (resolve) catch and reject exceptions
|
3819 |
+
process = special ?
|
3820 |
+
mightThrow :
|
3821 |
+
function() {
|
3822 |
+
try {
|
3823 |
+
mightThrow();
|
3824 |
+
} catch ( e ) {
|
3825 |
+
|
3826 |
+
if ( jQuery.Deferred.exceptionHook ) {
|
3827 |
+
jQuery.Deferred.exceptionHook( e,
|
3828 |
+
process.stackTrace );
|
3829 |
+
}
|
3830 |
+
|
3831 |
+
// Support: Promises/A+ section 2.3.3.3.4.1
|
3832 |
+
// https://promisesaplus.com/#point-61
|
3833 |
+
// Ignore post-resolution exceptions
|
3834 |
+
if ( depth + 1 >= maxDepth ) {
|
3835 |
+
|
3836 |
+
// Only substitute handlers pass on context
|
3837 |
+
// and multiple values (non-spec behavior)
|
3838 |
+
if ( handler !== Thrower ) {
|
3839 |
+
that = undefined;
|
3840 |
+
args = [ e ];
|
3841 |
+
}
|
3842 |
+
|
3843 |
+
deferred.rejectWith( that, args );
|
3844 |
+
}
|
3845 |
+
}
|
3846 |
+
};
|
3847 |
+
|
3848 |
+
// Support: Promises/A+ section 2.3.3.3.1
|
3849 |
+
// https://promisesaplus.com/#point-57
|
3850 |
+
// Re-resolve promises immediately to dodge false rejection from
|
3851 |
+
// subsequent errors
|
3852 |
+
if ( depth ) {
|
3853 |
+
process();
|
3854 |
+
} else {
|
3855 |
+
|
3856 |
+
// Call an optional hook to record the stack, in case of exception
|
3857 |
+
// since it's otherwise lost when execution goes async
|
3858 |
+
if ( jQuery.Deferred.getStackHook ) {
|
3859 |
+
process.stackTrace = jQuery.Deferred.getStackHook();
|
3860 |
+
}
|
3861 |
+
window.setTimeout( process );
|
3862 |
+
}
|
3863 |
+
};
|
3864 |
+
}
|
3865 |
+
|
3866 |
+
return jQuery.Deferred( function( newDefer ) {
|
3867 |
+
|
3868 |
+
// progress_handlers.add( ... )
|
3869 |
+
tuples[ 0 ][ 3 ].add(
|
3870 |
+
resolve(
|
3871 |
+
0,
|
3872 |
+
newDefer,
|
3873 |
+
isFunction( onProgress ) ?
|
3874 |
+
onProgress :
|
3875 |
+
Identity,
|
3876 |
+
newDefer.notifyWith
|
3877 |
+
)
|
3878 |
+
);
|
3879 |
+
|
3880 |
+
// fulfilled_handlers.add( ... )
|
3881 |
+
tuples[ 1 ][ 3 ].add(
|
3882 |
+
resolve(
|
3883 |
+
0,
|
3884 |
+
newDefer,
|
3885 |
+
isFunction( onFulfilled ) ?
|
3886 |
+
onFulfilled :
|
3887 |
+
Identity
|
3888 |
+
)
|
3889 |
+
);
|
3890 |
+
|
3891 |
+
// rejected_handlers.add( ... )
|
3892 |
+
tuples[ 2 ][ 3 ].add(
|
3893 |
+
resolve(
|
3894 |
+
0,
|
3895 |
+
newDefer,
|
3896 |
+
isFunction( onRejected ) ?
|
3897 |
+
onRejected :
|
3898 |
+
Thrower
|
3899 |
+
)
|
3900 |
+
);
|
3901 |
+
} ).promise();
|
3902 |
+
},
|
3903 |
+
|
3904 |
+
// Get a promise for this deferred
|
3905 |
+
// If obj is provided, the promise aspect is added to the object
|
3906 |
+
promise: function( obj ) {
|
3907 |
+
return obj != null ? jQuery.extend( obj, promise ) : promise;
|
3908 |
+
}
|
3909 |
+
},
|
3910 |
+
deferred = {};
|
3911 |
+
|
3912 |
+
// Add list-specific methods
|
3913 |
+
jQuery.each( tuples, function( i, tuple ) {
|
3914 |
+
var list = tuple[ 2 ],
|
3915 |
+
stateString = tuple[ 5 ];
|
3916 |
+
|
3917 |
+
// promise.progress = list.add
|
3918 |
+
// promise.done = list.add
|
3919 |
+
// promise.fail = list.add
|
3920 |
+
promise[ tuple[ 1 ] ] = list.add;
|
3921 |
+
|
3922 |
+
// Handle state
|
3923 |
+
if ( stateString ) {
|
3924 |
+
list.add(
|
3925 |
+
function() {
|
3926 |
+
|
3927 |
+
// state = "resolved" (i.e., fulfilled)
|
3928 |
+
// state = "rejected"
|
3929 |
+
state = stateString;
|
3930 |
+
},
|
3931 |
+
|
3932 |
+
// rejected_callbacks.disable
|
3933 |
+
// fulfilled_callbacks.disable
|
3934 |
+
tuples[ 3 - i ][ 2 ].disable,
|
3935 |
+
|
3936 |
+
// rejected_handlers.disable
|
3937 |
+
// fulfilled_handlers.disable
|
3938 |
+
tuples[ 3 - i ][ 3 ].disable,
|
3939 |
+
|
3940 |
+
// progress_callbacks.lock
|
3941 |
+
tuples[ 0 ][ 2 ].lock,
|
3942 |
+
|
3943 |
+
// progress_handlers.lock
|
3944 |
+
tuples[ 0 ][ 3 ].lock
|
3945 |
+
);
|
3946 |
+
}
|
3947 |
+
|
3948 |
+
// progress_handlers.fire
|
3949 |
+
// fulfilled_handlers.fire
|
3950 |
+
// rejected_handlers.fire
|
3951 |
+
list.add( tuple[ 3 ].fire );
|
3952 |
+
|
3953 |
+
// deferred.notify = function() { deferred.notifyWith(...) }
|
3954 |
+
// deferred.resolve = function() { deferred.resolveWith(...) }
|
3955 |
+
// deferred.reject = function() { deferred.rejectWith(...) }
|
3956 |
+
deferred[ tuple[ 0 ] ] = function() {
|
3957 |
+
deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments );
|
3958 |
+
return this;
|
3959 |
+
};
|
3960 |
+
|
3961 |
+
// deferred.notifyWith = list.fireWith
|
3962 |
+
// deferred.resolveWith = list.fireWith
|
3963 |
+
// deferred.rejectWith = list.fireWith
|
3964 |
+
deferred[ tuple[ 0 ] + "With" ] = list.fireWith;
|
3965 |
+
} );
|
3966 |
+
|
3967 |
+
// Make the deferred a promise
|
3968 |
+
promise.promise( deferred );
|
3969 |
+
|
3970 |
+
// Call given func if any
|
3971 |
+
if ( func ) {
|
3972 |
+
func.call( deferred, deferred );
|
3973 |
+
}
|
3974 |
+
|
3975 |
+
// All done!
|
3976 |
+
return deferred;
|
3977 |
+
},
|
3978 |
+
|
3979 |
+
// Deferred helper
|
3980 |
+
when: function( singleValue ) {
|
3981 |
+
var
|
3982 |
+
|
3983 |
+
// count of uncompleted subordinates
|
3984 |
+
remaining = arguments.length,
|
3985 |
+
|
3986 |
+
// count of unprocessed arguments
|
3987 |
+
i = remaining,
|
3988 |
+
|
3989 |
+
// subordinate fulfillment data
|
3990 |
+
resolveContexts = Array( i ),
|
3991 |
+
resolveValues = slice.call( arguments ),
|
3992 |
+
|
3993 |
+
// the master Deferred
|
3994 |
+
master = jQuery.Deferred(),
|
3995 |
+
|
3996 |
+
// subordinate callback factory
|
3997 |
+
updateFunc = function( i ) {
|
3998 |
+
return function( value ) {
|
3999 |
+
resolveContexts[ i ] = this;
|
4000 |
+
resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
|
4001 |
+
if ( !( --remaining ) ) {
|
4002 |
+
master.resolveWith( resolveContexts, resolveValues );
|
4003 |
+
}
|
4004 |
+
};
|
4005 |
+
};
|
4006 |
+
|
4007 |
+
// Single- and empty arguments are adopted like Promise.resolve
|
4008 |
+
if ( remaining <= 1 ) {
|
4009 |
+
adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject,
|
4010 |
+
!remaining );
|
4011 |
+
|
4012 |
+
// Use .then() to unwrap secondary thenables (cf. gh-3000)
|
4013 |
+
if ( master.state() === "pending" ||
|
4014 |
+
isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {
|
4015 |
+
|
4016 |
+
return master.then();
|
4017 |
+
}
|
4018 |
+
}
|
4019 |
+
|
4020 |
+
// Multiple arguments are aggregated like Promise.all array elements
|
4021 |
+
while ( i-- ) {
|
4022 |
+
adoptValue( resolveValues[ i ], updateFunc( i ), master.reject );
|
4023 |
+
}
|
4024 |
+
|
4025 |
+
return master.promise();
|
4026 |
+
}
|
4027 |
+
} );
|
4028 |
+
|
4029 |
+
|
4030 |
+
// These usually indicate a programmer mistake during development,
|
4031 |
+
// warn about them ASAP rather than swallowing them by default.
|
4032 |
+
var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;
|
4033 |
+
|
4034 |
+
jQuery.Deferred.exceptionHook = function( error, stack ) {
|
4035 |
+
|
4036 |
+
// Support: IE 8 - 9 only
|
4037 |
+
// Console exists when dev tools are open, which can happen at any time
|
4038 |
+
if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {
|
4039 |
+
window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack );
|
4040 |
+
}
|
4041 |
+
};
|
4042 |
+
|
4043 |
+
|
4044 |
+
|
4045 |
+
|
4046 |
+
jQuery.readyException = function( error ) {
|
4047 |
+
window.setTimeout( function() {
|
4048 |
+
throw error;
|
4049 |
+
} );
|
4050 |
+
};
|
4051 |
+
|
4052 |
+
|
4053 |
+
|
4054 |
+
|
4055 |
+
// The deferred used on DOM ready
|
4056 |
+
var readyList = jQuery.Deferred();
|
4057 |
+
|
4058 |
+
jQuery.fn.ready = function( fn ) {
|
4059 |
+
|
4060 |
+
readyList
|
4061 |
+
.then( fn )
|
4062 |
+
|
4063 |
+
// Wrap jQuery.readyException in a function so that the lookup
|
4064 |
+
// happens at the time of error handling instead of callback
|
4065 |
+
// registration.
|
4066 |
+
.catch( function( error ) {
|
4067 |
+
jQuery.readyException( error );
|
4068 |
+
} );
|
4069 |
+
|
4070 |
+
return this;
|
4071 |
+
};
|
4072 |
+
|
4073 |
+
jQuery.extend( {
|
4074 |
+
|
4075 |
+
// Is the DOM ready to be used? Set to true once it occurs.
|
4076 |
+
isReady: false,
|
4077 |
+
|
4078 |
+
// A counter to track how many items to wait for before
|
4079 |
+
// the ready event fires. See #6781
|
4080 |
+
readyWait: 1,
|
4081 |
+
|
4082 |
+
// Handle when the DOM is ready
|
4083 |
+
ready: function( wait ) {
|
4084 |
+
|
4085 |
+
// Abort if there are pending holds or we're already ready
|
4086 |
+
if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
|
4087 |
+
return;
|
4088 |
+
}
|
4089 |
+
|
4090 |
+
// Remember that the DOM is ready
|
4091 |
+
jQuery.isReady = true;
|
4092 |
+
|
4093 |
+
// If a normal DOM Ready event fired, decrement, and wait if need be
|
4094 |
+
if ( wait !== true && --jQuery.readyWait > 0 ) {
|
4095 |
+
return;
|
4096 |
+
}
|
4097 |
+
|
4098 |
+
// If there are functions bound, to execute
|
4099 |
+
readyList.resolveWith( document, [ jQuery ] );
|
4100 |
+
}
|
4101 |
+
} );
|
4102 |
+
|
4103 |
+
jQuery.ready.then = readyList.then;
|
4104 |
+
|
4105 |
+
// The ready event handler and self cleanup method
|
4106 |
+
function completed() {
|
4107 |
+
document.removeEventListener( "DOMContentLoaded", completed );
|
4108 |
+
window.removeEventListener( "load", completed );
|
4109 |
+
jQuery.ready();
|
4110 |
+
}
|
4111 |
+
|
4112 |
+
// Catch cases where $(document).ready() is called
|
4113 |
+
// after the browser event has already occurred.
|
4114 |
+
// Support: IE <=9 - 10 only
|
4115 |
+
// Older IE sometimes signals "interactive" too soon
|
4116 |
+
if ( document.readyState === "complete" ||
|
4117 |
+
( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {
|
4118 |
+
|
4119 |
+
// Handle it asynchronously to allow scripts the opportunity to delay ready
|
4120 |
+
window.setTimeout( jQuery.ready );
|
4121 |
+
|
4122 |
+
} else {
|
4123 |
+
|
4124 |
+
// Use the handy event callback
|
4125 |
+
document.addEventListener( "DOMContentLoaded", completed );
|
4126 |
+
|
4127 |
+
// A fallback to window.onload, that will always work
|
4128 |
+
window.addEventListener( "load", completed );
|
4129 |
+
}
|
4130 |
+
|
4131 |
+
|
4132 |
+
|
4133 |
+
|
4134 |
+
// Multifunctional method to get and set values of a collection
|
4135 |
+
// The value/s can optionally be executed if it's a function
|
4136 |
+
var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
|
4137 |
+
var i = 0,
|
4138 |
+
len = elems.length,
|
4139 |
+
bulk = key == null;
|
4140 |
+
|
4141 |
+
// Sets many values
|
4142 |
+
if ( toType( key ) === "object" ) {
|
4143 |
+
chainable = true;
|
4144 |
+
for ( i in key ) {
|
4145 |
+
access( elems, fn, i, key[ i ], true, emptyGet, raw );
|
4146 |
+
}
|
4147 |
+
|
4148 |
+
// Sets one value
|
4149 |
+
} else if ( value !== undefined ) {
|
4150 |
+
chainable = true;
|
4151 |
+
|
4152 |
+
if ( !isFunction( value ) ) {
|
4153 |
+
raw = true;
|
4154 |
+
}
|
4155 |
+
|
4156 |
+
if ( bulk ) {
|
4157 |
+
|
4158 |
+
// Bulk operations run against the entire set
|
4159 |
+
if ( raw ) {
|
4160 |
+
fn.call( elems, value );
|
4161 |
+
fn = null;
|
4162 |
+
|
4163 |
+
// ...except when executing function values
|
4164 |
+
} else {
|
4165 |
+
bulk = fn;
|
4166 |
+
fn = function( elem, key, value ) {
|
4167 |
+
return bulk.call( jQuery( elem ), value );
|
4168 |
+
};
|
4169 |
+
}
|
4170 |
+
}
|
4171 |
+
|
4172 |
+
if ( fn ) {
|
4173 |
+
for ( ; i < len; i++ ) {
|
4174 |
+
fn(
|
4175 |
+
elems[ i ], key, raw ?
|
4176 |
+
value :
|
4177 |
+
value.call( elems[ i ], i, fn( elems[ i ], key ) )
|
4178 |
+
);
|
4179 |
+
}
|
4180 |
+
}
|
4181 |
+
}
|
4182 |
+
|
4183 |
+
if ( chainable ) {
|
4184 |
+
return elems;
|
4185 |
+
}
|
4186 |
+
|
4187 |
+
// Gets
|
4188 |
+
if ( bulk ) {
|
4189 |
+
return fn.call( elems );
|
4190 |
+
}
|
4191 |
+
|
4192 |
+
return len ? fn( elems[ 0 ], key ) : emptyGet;
|
4193 |
+
};
|
4194 |
+
|
4195 |
+
|
4196 |
+
// Matches dashed string for camelizing
|
4197 |
+
var rmsPrefix = /^-ms-/,
|
4198 |
+
rdashAlpha = /-([a-z])/g;
|
4199 |
+
|
4200 |
+
// Used by camelCase as callback to replace()
|
4201 |
+
function fcamelCase( all, letter ) {
|
4202 |
+
return letter.toUpperCase();
|
4203 |
+
}
|
4204 |
+
|
4205 |
+
// Convert dashed to camelCase; used by the css and data modules
|
4206 |
+
// Support: IE <=9 - 11, Edge 12 - 15
|
4207 |
+
// Microsoft forgot to hump their vendor prefix (#9572)
|
4208 |
+
function camelCase( string ) {
|
4209 |
+
return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
|
4210 |
+
}
|
4211 |
+
var acceptData = function( owner ) {
|
4212 |
+
|
4213 |
+
// Accepts only:
|
4214 |
+
// - Node
|
4215 |
+
// - Node.ELEMENT_NODE
|
4216 |
+
// - Node.DOCUMENT_NODE
|
4217 |
+
// - Object
|
4218 |
+
// - Any
|
4219 |
+
return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
|
4220 |
+
};
|
4221 |
+
|
4222 |
+
|
4223 |
+
|
4224 |
+
|
4225 |
+
function Data() {
|
4226 |
+
this.expando = jQuery.expando + Data.uid++;
|
4227 |
+
}
|
4228 |
+
|
4229 |
+
Data.uid = 1;
|
4230 |
+
|
4231 |
+
Data.prototype = {
|
4232 |
+
|
4233 |
+
cache: function( owner ) {
|
4234 |
+
|
4235 |
+
// Check if the owner object already has a cache
|
4236 |
+
var value = owner[ this.expando ];
|
4237 |
+
|
4238 |
+
// If not, create one
|
4239 |
+
if ( !value ) {
|
4240 |
+
value = {};
|
4241 |
+
|
4242 |
+
// We can accept data for non-element nodes in modern browsers,
|
4243 |
+
// but we should not, see #8335.
|
4244 |
+
// Always return an empty object.
|
4245 |
+
if ( acceptData( owner ) ) {
|
4246 |
+
|
4247 |
+
// If it is a node unlikely to be stringify-ed or looped over
|
4248 |
+
// use plain assignment
|
4249 |
+
if ( owner.nodeType ) {
|
4250 |
+
owner[ this.expando ] = value;
|
4251 |
+
|
4252 |
+
// Otherwise secure it in a non-enumerable property
|
4253 |
+
// configurable must be true to allow the property to be
|
4254 |
+
// deleted when data is removed
|
4255 |
+
} else {
|
4256 |
+
Object.defineProperty( owner, this.expando, {
|
4257 |
+
value: value,
|
4258 |
+
configurable: true
|
4259 |
+
} );
|
4260 |
+
}
|
4261 |
+
}
|
4262 |
+
}
|
4263 |
+
|
4264 |
+
return value;
|
4265 |
+
},
|
4266 |
+
set: function( owner, data, value ) {
|
4267 |
+
var prop,
|
4268 |
+
cache = this.cache( owner );
|
4269 |
+
|
4270 |
+
// Handle: [ owner, key, value ] args
|
4271 |
+
// Always use camelCase key (gh-2257)
|
4272 |
+
if ( typeof data === "string" ) {
|
4273 |
+
cache[ camelCase( data ) ] = value;
|
4274 |
+
|
4275 |
+
// Handle: [ owner, { properties } ] args
|
4276 |
+
} else {
|
4277 |
+
|
4278 |
+
// Copy the properties one-by-one to the cache object
|
4279 |
+
for ( prop in data ) {
|
4280 |
+
cache[ camelCase( prop ) ] = data[ prop ];
|
4281 |
+
}
|
4282 |
+
}
|
4283 |
+
return cache;
|
4284 |
+
},
|
4285 |
+
get: function( owner, key ) {
|
4286 |
+
return key === undefined ?
|
4287 |
+
this.cache( owner ) :
|
4288 |
+
|
4289 |
+
// Always use camelCase key (gh-2257)
|
4290 |
+
owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ];
|
4291 |
+
},
|
4292 |
+
access: function( owner, key, value ) {
|
4293 |
+
|
4294 |
+
// In cases where either:
|
4295 |
+
//
|
4296 |
+
// 1. No key was specified
|
4297 |
+
// 2. A string key was specified, but no value provided
|
4298 |
+
//
|
4299 |
+
// Take the "read" path and allow the get method to determine
|
4300 |
+
// which value to return, respectively either:
|
4301 |
+
//
|
4302 |
+
// 1. The entire cache object
|
4303 |
+
// 2. The data stored at the key
|
4304 |
+
//
|
4305 |
+
if ( key === undefined ||
|
4306 |
+
( ( key && typeof key === "string" ) && value === undefined ) ) {
|
4307 |
+
|
4308 |
+
return this.get( owner, key );
|
4309 |
+
}
|
4310 |
+
|
4311 |
+
// When the key is not a string, or both a key and value
|
4312 |
+
// are specified, set or extend (existing objects) with either:
|
4313 |
+
//
|
4314 |
+
// 1. An object of properties
|
4315 |
+
// 2. A key and value
|
4316 |
+
//
|
4317 |
+
this.set( owner, key, value );
|
4318 |
+
|
4319 |
+
// Since the "set" path can have two possible entry points
|
4320 |
+
// return the expected data based on which path was taken[*]
|
4321 |
+
return value !== undefined ? value : key;
|
4322 |
+
},
|
4323 |
+
remove: function( owner, key ) {
|
4324 |
+
var i,
|
4325 |
+
cache = owner[ this.expando ];
|
4326 |
+
|
4327 |
+
if ( cache === undefined ) {
|
4328 |
+
return;
|
4329 |
+
}
|
4330 |
+
|
4331 |
+
if ( key !== undefined ) {
|
4332 |
+
|
4333 |
+
// Support array or space separated string of keys
|
4334 |
+
if ( Array.isArray( key ) ) {
|
4335 |
+
|
4336 |
+
// If key is an array of keys...
|
4337 |
+
// We always set camelCase keys, so remove that.
|
4338 |
+
key = key.map( camelCase );
|
4339 |
+
} else {
|
4340 |
+
key = camelCase( key );
|
4341 |
+
|
4342 |
+
// If a key with the spaces exists, use it.
|
4343 |
+
// Otherwise, create an array by matching non-whitespace
|
4344 |
+
key = key in cache ?
|
4345 |
+
[ key ] :
|
4346 |
+
( key.match( rnothtmlwhite ) || [] );
|
4347 |
+
}
|
4348 |
+
|
4349 |
+
i = key.length;
|
4350 |
+
|
4351 |
+
while ( i-- ) {
|
4352 |
+
delete cache[ key[ i ] ];
|
4353 |
+
}
|
4354 |
+
}
|
4355 |
+
|
4356 |
+
// Remove the expando if there's no more data
|
4357 |
+
if ( key === undefined || jQuery.isEmptyObject( cache ) ) {
|
4358 |
+
|
4359 |
+
// Support: Chrome <=35 - 45
|
4360 |
+
// Webkit & Blink performance suffers when deleting properties
|
4361 |
+
// from DOM nodes, so set to undefined instead
|
4362 |
+
// https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)
|
4363 |
+
if ( owner.nodeType ) {
|
4364 |
+
owner[ this.expando ] = undefined;
|
4365 |
+
} else {
|
4366 |
+
delete owner[ this.expando ];
|
4367 |
+
}
|
4368 |
+
}
|
4369 |
+
},
|
4370 |
+
hasData: function( owner ) {
|
4371 |
+
var cache = owner[ this.expando ];
|
4372 |
+
return cache !== undefined && !jQuery.isEmptyObject( cache );
|
4373 |
+
}
|
4374 |
+
};
|
4375 |
+
var dataPriv = new Data();
|
4376 |
+
|
4377 |
+
var dataUser = new Data();
|
4378 |
+
|
4379 |
+
|
4380 |
+
|
4381 |
+
// Implementation Summary
|
4382 |
+
//
|
4383 |
+
// 1. Enforce API surface and semantic compatibility with 1.9.x branch
|
4384 |
+
// 2. Improve the module's maintainability by reducing the storage
|
4385 |
+
// paths to a single mechanism.
|
4386 |
+
// 3. Use the same single mechanism to support "private" and "user" data.
|
4387 |
+
// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
|
4388 |
+
// 5. Avoid exposing implementation details on user objects (eg. expando properties)
|
4389 |
+
// 6. Provide a clear path for implementation upgrade to WeakMap in 2014
|
4390 |
+
|
4391 |
+
var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
|
4392 |
+
rmultiDash = /[A-Z]/g;
|
4393 |
+
|
4394 |
+
function getData( data ) {
|
4395 |
+
if ( data === "true" ) {
|
4396 |
+
return true;
|
4397 |
+
}
|
4398 |
+
|
4399 |
+
if ( data === "false" ) {
|
4400 |
+
return false;
|
4401 |
+
}
|
4402 |
+
|
4403 |
+
if ( data === "null" ) {
|
4404 |
+
return null;
|
4405 |
+
}
|
4406 |
+
|
4407 |
+
// Only convert to a number if it doesn't change the string
|
4408 |
+
if ( data === +data + "" ) {
|
4409 |
+
return +data;
|
4410 |
+
}
|
4411 |
+
|
4412 |
+
if ( rbrace.test( data ) ) {
|
4413 |
+
return JSON.parse( data );
|
4414 |
+
}
|
4415 |
+
|
4416 |
+
return data;
|
4417 |
+
}
|
4418 |
+
|
4419 |
+
function dataAttr( elem, key, data ) {
|
4420 |
+
var name;
|
4421 |
+
|
4422 |
+
// If nothing was found internally, try to fetch any
|
4423 |
+
// data from the HTML5 data-* attribute
|
4424 |
+
if ( data === undefined && elem.nodeType === 1 ) {
|
4425 |
+
name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase();
|
4426 |
+
data = elem.getAttribute( name );
|
4427 |
+
|
4428 |
+
if ( typeof data === "string" ) {
|
4429 |
+
try {
|
4430 |
+
data = getData( data );
|
4431 |
+
} catch ( e ) {}
|
4432 |
+
|
4433 |
+
// Make sure we set the data so it isn't changed later
|
4434 |
+
dataUser.set( elem, key, data );
|
4435 |
+
} else {
|
4436 |
+
data = undefined;
|
4437 |
+
}
|
4438 |
+
}
|
4439 |
+
return data;
|
4440 |
+
}
|
4441 |
+
|
4442 |
+
jQuery.extend( {
|
4443 |
+
hasData: function( elem ) {
|
4444 |
+
return dataUser.hasData( elem ) || dataPriv.hasData( elem );
|
4445 |
+
},
|
4446 |
+
|
4447 |
+
data: function( elem, name, data ) {
|
4448 |
+
return dataUser.access( elem, name, data );
|
4449 |
+
},
|
4450 |
+
|
4451 |
+
removeData: function( elem, name ) {
|
4452 |
+
dataUser.remove( elem, name );
|
4453 |
+
},
|
4454 |
+
|
4455 |
+
// TODO: Now that all calls to _data and _removeData have been replaced
|
4456 |
+
// with direct calls to dataPriv methods, these can be deprecated.
|
4457 |
+
_data: function( elem, name, data ) {
|
4458 |
+
return dataPriv.access( elem, name, data );
|
4459 |
+
},
|
4460 |
+
|
4461 |
+
_removeData: function( elem, name ) {
|
4462 |
+
dataPriv.remove( elem, name );
|
4463 |
+
}
|
4464 |
+
} );
|
4465 |
+
|
4466 |
+
jQuery.fn.extend( {
|
4467 |
+
data: function( key, value ) {
|
4468 |
+
var i, name, data,
|
4469 |
+
elem = this[ 0 ],
|
4470 |
+
attrs = elem && elem.attributes;
|
4471 |
+
|
4472 |
+
// Gets all values
|
4473 |
+
if ( key === undefined ) {
|
4474 |
+
if ( this.length ) {
|
4475 |
+
data = dataUser.get( elem );
|
4476 |
+
|
4477 |
+
if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) {
|
4478 |
+
i = attrs.length;
|
4479 |
+
while ( i-- ) {
|
4480 |
+
|
4481 |
+
// Support: IE 11 only
|
4482 |
+
// The attrs elements can be null (#14894)
|
4483 |
+
if ( attrs[ i ] ) {
|
4484 |
+
name = attrs[ i ].name;
|
4485 |
+
if ( name.indexOf( "data-" ) === 0 ) {
|
4486 |
+
name = camelCase( name.slice( 5 ) );
|
4487 |
+
dataAttr( elem, name, data[ name ] );
|
4488 |
+
}
|
4489 |
+
}
|
4490 |
+
}
|
4491 |
+
dataPriv.set( elem, "hasDataAttrs", true );
|
4492 |
+
}
|
4493 |
+
}
|
4494 |
+
|
4495 |
+
return data;
|
4496 |
+
}
|
4497 |
+
|
4498 |
+
// Sets multiple values
|
4499 |
+
if ( typeof key === "object" ) {
|
4500 |
+
return this.each( function() {
|
4501 |
+
dataUser.set( this, key );
|
4502 |
+
} );
|
4503 |
+
}
|
4504 |
+
|
4505 |
+
return access( this, function( value ) {
|
4506 |
+
var data;
|
4507 |
+
|
4508 |
+
// The calling jQuery object (element matches) is not empty
|
4509 |
+
// (and therefore has an element appears at this[ 0 ]) and the
|
4510 |
+
// `value` parameter was not undefined. An empty jQuery object
|
4511 |
+
// will result in `undefined` for elem = this[ 0 ] which will
|
4512 |
+
// throw an exception if an attempt to read a data cache is made.
|
4513 |
+
if ( elem && value === undefined ) {
|
4514 |
+
|
4515 |
+
// Attempt to get data from the cache
|
4516 |
+
// The key will always be camelCased in Data
|
4517 |
+
data = dataUser.get( elem, key );
|
4518 |
+
if ( data !== undefined ) {
|
4519 |
+
return data;
|
4520 |
+
}
|
4521 |
+
|
4522 |
+
// Attempt to "discover" the data in
|
4523 |
+
// HTML5 custom data-* attrs
|
4524 |
+
data = dataAttr( elem, key );
|
4525 |
+
if ( data !== undefined ) {
|
4526 |
+
return data;
|
4527 |
+
}
|
4528 |
+
|
4529 |
+
// We tried really hard, but the data doesn't exist.
|
4530 |
+
return;
|
4531 |
+
}
|
4532 |
+
|
4533 |
+
// Set the data...
|
4534 |
+
this.each( function() {
|
4535 |
+
|
4536 |
+
// We always store the camelCased key
|
4537 |
+
dataUser.set( this, key, value );
|
4538 |
+
} );
|
4539 |
+
}, null, value, arguments.length > 1, null, true );
|
4540 |
+
},
|
4541 |
+
|
4542 |
+
removeData: function( key ) {
|
4543 |
+
return this.each( function() {
|
4544 |
+
dataUser.remove( this, key );
|
4545 |
+
} );
|
4546 |
+
}
|
4547 |
+
} );
|
4548 |
+
|
4549 |
+
|
4550 |
+
jQuery.extend( {
|
4551 |
+
queue: function( elem, type, data ) {
|
4552 |
+
var queue;
|
4553 |
+
|
4554 |
+
if ( elem ) {
|
4555 |
+
type = ( type || "fx" ) + "queue";
|
4556 |
+
queue = dataPriv.get( elem, type );
|
4557 |
+
|
4558 |
+
// Speed up dequeue by getting out quickly if this is just a lookup
|
4559 |
+
if ( data ) {
|
4560 |
+
if ( !queue || Array.isArray( data ) ) {
|
4561 |
+
queue = dataPriv.access( elem, type, jQuery.makeArray( data ) );
|
4562 |
+
} else {
|
4563 |
+
queue.push( data );
|
4564 |
+
}
|
4565 |
+
}
|
4566 |
+
return queue || [];
|
4567 |
+
}
|
4568 |
+
},
|
4569 |
+
|
4570 |
+
dequeue: function( elem, type ) {
|
4571 |
+
type = type || "fx";
|
4572 |
+
|
4573 |
+
var queue = jQuery.queue( elem, type ),
|
4574 |
+
startLength = queue.length,
|
4575 |
+
fn = queue.shift(),
|
4576 |
+
hooks = jQuery._queueHooks( elem, type ),
|
4577 |
+
next = function() {
|
4578 |
+
jQuery.dequeue( elem, type );
|
4579 |
+
};
|
4580 |
+
|
4581 |
+
// If the fx queue is dequeued, always remove the progress sentinel
|
4582 |
+
if ( fn === "inprogress" ) {
|
4583 |
+
fn = queue.shift();
|
4584 |
+
startLength--;
|
4585 |
+
}
|
4586 |
+
|
4587 |
+
if ( fn ) {
|
4588 |
+
|
4589 |
+
// Add a progress sentinel to prevent the fx queue from being
|
4590 |
+
// automatically dequeued
|
4591 |
+
if ( type === "fx" ) {
|
4592 |
+
queue.unshift( "inprogress" );
|
4593 |
+
}
|
4594 |
+
|
4595 |
+
// Clear up the last queue stop function
|
4596 |
+
delete hooks.stop;
|
4597 |
+
fn.call( elem, next, hooks );
|
4598 |
+
}
|
4599 |
+
|
4600 |
+
if ( !startLength && hooks ) {
|
4601 |
+
hooks.empty.fire();
|
4602 |
+
}
|
4603 |
+
},
|
4604 |
+
|
4605 |
+
// Not public - generate a queueHooks object, or return the current one
|
4606 |
+
_queueHooks: function( elem, type ) {
|
4607 |
+
var key = type + "queueHooks";
|
4608 |
+
return dataPriv.get( elem, key ) || dataPriv.access( elem, key, {
|
4609 |
+
empty: jQuery.Callbacks( "once memory" ).add( function() {
|
4610 |
+
dataPriv.remove( elem, [ type + "queue", key ] );
|
4611 |
+
} )
|
4612 |
+
} );
|
4613 |
+
}
|
4614 |
+
} );
|
4615 |
+
|
4616 |
+
jQuery.fn.extend( {
|
4617 |
+
queue: function( type, data ) {
|
4618 |
+
var setter = 2;
|
4619 |
+
|
4620 |
+
if ( typeof type !== "string" ) {
|
4621 |
+
data = type;
|
4622 |
+
type = "fx";
|
4623 |
+
setter--;
|
4624 |
+
}
|
4625 |
+
|
4626 |
+
if ( arguments.length < setter ) {
|
4627 |
+
return jQuery.queue( this[ 0 ], type );
|
4628 |
+
}
|
4629 |
+
|
4630 |
+
return data === undefined ?
|
4631 |
+
this :
|
4632 |
+
this.each( function() {
|
4633 |
+
var queue = jQuery.queue( this, type, data );
|
4634 |
+
|
4635 |
+
// Ensure a hooks for this queue
|
4636 |
+
jQuery._queueHooks( this, type );
|
4637 |
+
|
4638 |
+
if ( type === "fx" && queue[ 0 ] !== "inprogress" ) {
|
4639 |
+
jQuery.dequeue( this, type );
|
4640 |
+
}
|
4641 |
+
} );
|
4642 |
+
},
|
4643 |
+
dequeue: function( type ) {
|
4644 |
+
return this.each( function() {
|
4645 |
+
jQuery.dequeue( this, type );
|
4646 |
+
} );
|
4647 |
+
},
|
4648 |
+
clearQueue: function( type ) {
|
4649 |
+
return this.queue( type || "fx", [] );
|
4650 |
+
},
|
4651 |
+
|
4652 |
+
// Get a promise resolved when queues of a certain type
|
4653 |
+
// are emptied (fx is the type by default)
|
4654 |
+
promise: function( type, obj ) {
|
4655 |
+
var tmp,
|
4656 |
+
count = 1,
|
4657 |
+
defer = jQuery.Deferred(),
|
4658 |
+
elements = this,
|
4659 |
+
i = this.length,
|
4660 |
+
resolve = function() {
|
4661 |
+
if ( !( --count ) ) {
|
4662 |
+
defer.resolveWith( elements, [ elements ] );
|
4663 |
+
}
|
4664 |
+
};
|
4665 |
+
|
4666 |
+
if ( typeof type !== "string" ) {
|
4667 |
+
obj = type;
|
4668 |
+
type = undefined;
|
4669 |
+
}
|
4670 |
+
type = type || "fx";
|
4671 |
+
|
4672 |
+
while ( i-- ) {
|
4673 |
+
tmp = dataPriv.get( elements[ i ], type + "queueHooks" );
|
4674 |
+
if ( tmp && tmp.empty ) {
|
4675 |
+
count++;
|
4676 |
+
tmp.empty.add( resolve );
|
4677 |
+
}
|
4678 |
+
}
|
4679 |
+
resolve();
|
4680 |
+
return defer.promise( obj );
|
4681 |
+
}
|
4682 |
+
} );
|
4683 |
+
var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source;
|
4684 |
+
|
4685 |
+
var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" );
|
4686 |
+
|
4687 |
+
|
4688 |
+
var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
|
4689 |
+
|
4690 |
+
var isHiddenWithinTree = function( elem, el ) {
|
4691 |
+
|
4692 |
+
// isHiddenWithinTree might be called from jQuery#filter function;
|
4693 |
+
// in that case, element will be second argument
|
4694 |
+
elem = el || elem;
|
4695 |
+
|
4696 |
+
// Inline style trumps all
|
4697 |
+
return elem.style.display === "none" ||
|
4698 |
+
elem.style.display === "" &&
|
4699 |
+
|
4700 |
+
// Otherwise, check computed style
|
4701 |
+
// Support: Firefox <=43 - 45
|
4702 |
+
// Disconnected elements can have computed display: none, so first confirm that elem is
|
4703 |
+
// in the document.
|
4704 |
+
jQuery.contains( elem.ownerDocument, elem ) &&
|
4705 |
+
|
4706 |
+
jQuery.css( elem, "display" ) === "none";
|
4707 |
+
};
|
4708 |
+
|
4709 |
+
var swap = function( elem, options, callback, args ) {
|
4710 |
+
var ret, name,
|
4711 |
+
old = {};
|
4712 |
+
|
4713 |
+
// Remember the old values, and insert the new ones
|
4714 |
+
for ( name in options ) {
|
4715 |
+
old[ name ] = elem.style[ name ];
|
4716 |
+
elem.style[ name ] = options[ name ];
|
4717 |
+
}
|
4718 |
+
|
4719 |
+
ret = callback.apply( elem, args || [] );
|
4720 |
+
|
4721 |
+
// Revert the old values
|
4722 |
+
for ( name in options ) {
|
4723 |
+
elem.style[ name ] = old[ name ];
|
4724 |
+
}
|
4725 |
+
|
4726 |
+
return ret;
|
4727 |
+
};
|
4728 |
+
|
4729 |
+
|
4730 |
+
|
4731 |
+
|
4732 |
+
function adjustCSS( elem, prop, valueParts, tween ) {
|
4733 |
+
var adjusted, scale,
|
4734 |
+
maxIterations = 20,
|
4735 |
+
currentValue = tween ?
|
4736 |
+
function() {
|
4737 |
+
return tween.cur();
|
4738 |
+
} :
|
4739 |
+
function() {
|
4740 |
+
return jQuery.css( elem, prop, "" );
|
4741 |
+
},
|
4742 |
+
initial = currentValue(),
|
4743 |
+
unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
|
4744 |
+
|
4745 |
+
// Starting value computation is required for potential unit mismatches
|
4746 |
+
initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) &&
|
4747 |
+
rcssNum.exec( jQuery.css( elem, prop ) );
|
4748 |
+
|
4749 |
+
if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {
|
4750 |
+
|
4751 |
+
// Support: Firefox <=54
|
4752 |
+
// Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144)
|
4753 |
+
initial = initial / 2;
|
4754 |
+
|
4755 |
+
// Trust units reported by jQuery.css
|
4756 |
+
unit = unit || initialInUnit[ 3 ];
|
4757 |
+
|
4758 |
+
// Iteratively approximate from a nonzero starting point
|
4759 |
+
initialInUnit = +initial || 1;
|
4760 |
+
|
4761 |
+
while ( maxIterations-- ) {
|
4762 |
+
|
4763 |
+
// Evaluate and update our best guess (doubling guesses that zero out).
|
4764 |
+
// Finish if the scale equals or crosses 1 (making the old*new product non-positive).
|
4765 |
+
jQuery.style( elem, prop, initialInUnit + unit );
|
4766 |
+
if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) {
|
4767 |
+
maxIterations = 0;
|
4768 |
+
}
|
4769 |
+
initialInUnit = initialInUnit / scale;
|
4770 |
+
|
4771 |
+
}
|
4772 |
+
|
4773 |
+
initialInUnit = initialInUnit * 2;
|
4774 |
+
jQuery.style( elem, prop, initialInUnit + unit );
|
4775 |
+
|
4776 |
+
// Make sure we update the tween properties later on
|
4777 |
+
valueParts = valueParts || [];
|
4778 |
+
}
|
4779 |
+
|
4780 |
+
if ( valueParts ) {
|
4781 |
+
initialInUnit = +initialInUnit || +initial || 0;
|
4782 |
+
|
4783 |
+
// Apply relative offset (+=/-=) if specified
|
4784 |
+
adjusted = valueParts[ 1 ] ?
|
4785 |
+
initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :
|
4786 |
+
+valueParts[ 2 ];
|
4787 |
+
if ( tween ) {
|
4788 |
+
tween.unit = unit;
|
4789 |
+
tween.start = initialInUnit;
|
4790 |
+
tween.end = adjusted;
|
4791 |
+
}
|
4792 |
+
}
|
4793 |
+
return adjusted;
|
4794 |
+
}
|
4795 |
+
|
4796 |
+
|
4797 |
+
var defaultDisplayMap = {};
|
4798 |
+
|
4799 |
+
function getDefaultDisplay( elem ) {
|
4800 |
+
var temp,
|
4801 |
+
doc = elem.ownerDocument,
|
4802 |
+
nodeName = elem.nodeName,
|
4803 |
+
display = defaultDisplayMap[ nodeName ];
|
4804 |
+
|
4805 |
+
if ( display ) {
|
4806 |
+
return display;
|
4807 |
+
}
|
4808 |
+
|
4809 |
+
temp = doc.body.appendChild( doc.createElement( nodeName ) );
|
4810 |
+
display = jQuery.css( temp, "display" );
|
4811 |
+
|
4812 |
+
temp.parentNode.removeChild( temp );
|
4813 |
+
|
4814 |
+
if ( display === "none" ) {
|
4815 |
+
display = "block";
|
4816 |
+
}
|
4817 |
+
defaultDisplayMap[ nodeName ] = display;
|
4818 |
+
|
4819 |
+
return display;
|
4820 |
+
}
|
4821 |
+
|
4822 |
+
function showHide( elements, show ) {
|
4823 |
+
var display, elem,
|
4824 |
+
values = [],
|
4825 |
+
index = 0,
|
4826 |
+
length = elements.length;
|
4827 |
+
|
4828 |
+
// Determine new display value for elements that need to change
|
4829 |
+
for ( ; index < length; index++ ) {
|
4830 |
+
elem = elements[ index ];
|
4831 |
+
if ( !elem.style ) {
|
4832 |
+
continue;
|
4833 |
+
}
|
4834 |
+
|
4835 |
+
display = elem.style.display;
|
4836 |
+
if ( show ) {
|
4837 |
+
|
4838 |
+
// Since we force visibility upon cascade-hidden elements, an immediate (and slow)
|
4839 |
+
// check is required in this first loop unless we have a nonempty display value (either
|
4840 |
+
// inline or about-to-be-restored)
|
4841 |
+
if ( display === "none" ) {
|
4842 |
+
values[ index ] = dataPriv.get( elem, "display" ) || null;
|
4843 |
+
if ( !values[ index ] ) {
|
4844 |
+
elem.style.display = "";
|
4845 |
+
}
|
4846 |
+
}
|
4847 |
+
if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) {
|
4848 |
+
values[ index ] = getDefaultDisplay( elem );
|
4849 |
+
}
|
4850 |
+
} else {
|
4851 |
+
if ( display !== "none" ) {
|
4852 |
+
values[ index ] = "none";
|
4853 |
+
|
4854 |
+
// Remember what we're overwriting
|
4855 |
+
dataPriv.set( elem, "display", display );
|
4856 |
+
}
|
4857 |
+
}
|
4858 |
+
}
|
4859 |
+
|
4860 |
+
// Set the display of the elements in a second loop to avoid constant reflow
|
4861 |
+
for ( index = 0; index < length; index++ ) {
|
4862 |
+
if ( values[ index ] != null ) {
|
4863 |
+
elements[ index ].style.display = values[ index ];
|
4864 |
+
}
|
4865 |
+
}
|
4866 |
+
|
4867 |
+
return elements;
|
4868 |
+
}
|
4869 |
+
|
4870 |
+
jQuery.fn.extend( {
|
4871 |
+
show: function() {
|
4872 |
+
return showHide( this, true );
|
4873 |
+
},
|
4874 |
+
hide: function() {
|
4875 |
+
return showHide( this );
|
4876 |
+
},
|
4877 |
+
toggle: function( state ) {
|
4878 |
+
if ( typeof state === "boolean" ) {
|
4879 |
+
return state ? this.show() : this.hide();
|
4880 |
+
}
|
4881 |
+
|
4882 |
+
return this.each( function() {
|
4883 |
+
if ( isHiddenWithinTree( this ) ) {
|
4884 |
+
jQuery( this ).show();
|
4885 |
+
} else {
|
4886 |
+
jQuery( this ).hide();
|
4887 |
+
}
|
4888 |
+
} );
|
4889 |
+
}
|
4890 |
+
} );
|
4891 |
+
var rcheckableType = ( /^(?:checkbox|radio)$/i );
|
4892 |
+
|
4893 |
+
var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i );
|
4894 |
+
|
4895 |
+
var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i );
|
4896 |
+
|
4897 |
+
|
4898 |
+
|
4899 |
+
// We have to close these tags to support XHTML (#13200)
|
4900 |
+
var wrapMap = {
|
4901 |
+
|
4902 |
+
// Support: IE <=9 only
|
4903 |
+
option: [ 1, "<select multiple='multiple'>", "</select>" ],
|
4904 |
+
|
4905 |
+
// XHTML parsers do not magically insert elements in the
|
4906 |
+
// same way that tag soup parsers do. So we cannot shorten
|
4907 |
+
// this by omitting <tbody> or other required elements.
|
4908 |
+
thead: [ 1, "<table>", "</table>" ],
|
4909 |
+
col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
|
4910 |
+
tr: [ 2, "<table><tbody>", "</tbody></table>" ],
|
4911 |
+
td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
|
4912 |
+
|
4913 |
+
_default: [ 0, "", "" ]
|
4914 |
+
};
|
4915 |
+
|
4916 |
+
// Support: IE <=9 only
|
4917 |
+
wrapMap.optgroup = wrapMap.option;
|
4918 |
+
|
4919 |
+
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
|
4920 |
+
wrapMap.th = wrapMap.td;
|
4921 |
+
|
4922 |
+
|
4923 |
+
function getAll( context, tag ) {
|
4924 |
+
|
4925 |
+
// Support: IE <=9 - 11 only
|
4926 |
+
// Use typeof to avoid zero-argument method invocation on host objects (#15151)
|
4927 |
+
var ret;
|
4928 |
+
|
4929 |
+
if ( typeof context.getElementsByTagName !== "undefined" ) {
|
4930 |
+
ret = context.getElementsByTagName( tag || "*" );
|
4931 |
+
|
4932 |
+
} else if ( typeof context.querySelectorAll !== "undefined" ) {
|
4933 |
+
ret = context.querySelectorAll( tag || "*" );
|
4934 |
+
|
4935 |
+
} else {
|
4936 |
+
ret = [];
|
4937 |
+
}
|
4938 |
+
|
4939 |
+
if ( tag === undefined || tag && nodeName( context, tag ) ) {
|
4940 |
+
return jQuery.merge( [ context ], ret );
|
4941 |
+
}
|
4942 |
+
|
4943 |
+
return ret;
|
4944 |
+
}
|
4945 |
+
|
4946 |
+
|
4947 |
+
// Mark scripts as having already been evaluated
|
4948 |
+
function setGlobalEval( elems, refElements ) {
|
4949 |
+
var i = 0,
|
4950 |
+
l = elems.length;
|
4951 |
+
|
4952 |
+
for ( ; i < l; i++ ) {
|
4953 |
+
dataPriv.set(
|
4954 |
+
elems[ i ],
|
4955 |
+
"globalEval",
|
4956 |
+
!refElements || dataPriv.get( refElements[ i ], "globalEval" )
|
4957 |
+
);
|
4958 |
+
}
|
4959 |
+
}
|
4960 |
+
|
4961 |
+
|
4962 |
+
var rhtml = /<|&#?\w+;/;
|
4963 |
+
|
4964 |
+
function buildFragment( elems, context, scripts, selection, ignored ) {
|
4965 |
+
var elem, tmp, tag, wrap, contains, j,
|
4966 |
+
fragment = context.createDocumentFragment(),
|
4967 |
+
nodes = [],
|
4968 |
+
i = 0,
|
4969 |
+
l = elems.length;
|
4970 |
+
|
4971 |
+
for ( ; i < l; i++ ) {
|
4972 |
+
elem = elems[ i ];
|
4973 |
+
|
4974 |
+
if ( elem || elem === 0 ) {
|
4975 |
+
|
4976 |
+
// Add nodes directly
|
4977 |
+
if ( toType( elem ) === "object" ) {
|
4978 |
+
|
4979 |
+
// Support: Android <=4.0 only, PhantomJS 1 only
|
4980 |
+
// push.apply(_, arraylike) throws on ancient WebKit
|
4981 |
+
jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
|
4982 |
+
|
4983 |
+
// Convert non-html into a text node
|
4984 |
+
} else if ( !rhtml.test( elem ) ) {
|
4985 |
+
nodes.push( context.createTextNode( elem ) );
|
4986 |
+
|
4987 |
+
// Convert html into DOM nodes
|
4988 |
+
} else {
|
4989 |
+
tmp = tmp || fragment.appendChild( context.createElement( "div" ) );
|
4990 |
+
|
4991 |
+
// Deserialize a standard representation
|
4992 |
+
tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
|
4993 |
+
wrap = wrapMap[ tag ] || wrapMap._default;
|
4994 |
+
tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];
|
4995 |
+
|
4996 |
+
// Descend through wrappers to the right content
|
4997 |
+
j = wrap[ 0 ];
|
4998 |
+
while ( j-- ) {
|
4999 |
+
tmp = tmp.lastChild;
|
5000 |
+
}
|
5001 |
+
|
5002 |
+
// Support: Android <=4.0 only, PhantomJS 1 only
|
5003 |
+
// push.apply(_, arraylike) throws on ancient WebKit
|
5004 |
+
jQuery.merge( nodes, tmp.childNodes );
|
5005 |
+
|
5006 |
+
// Remember the top-level container
|
5007 |
+
tmp = fragment.firstChild;
|
5008 |
+
|
5009 |
+
// Ensure the created nodes are orphaned (#12392)
|
5010 |
+
tmp.textContent = "";
|
5011 |
+
}
|
5012 |
+
}
|
5013 |
+
}
|
5014 |
+
|
5015 |
+
// Remove wrapper from fragment
|
5016 |
+
fragment.textContent = "";
|
5017 |
+
|
5018 |
+
i = 0;
|
5019 |
+
while ( ( elem = nodes[ i++ ] ) ) {
|
5020 |
+
|
5021 |
+
// Skip elements already in the context collection (trac-4087)
|
5022 |
+
if ( selection && jQuery.inArray( elem, selection ) > -1 ) {
|
5023 |
+
if ( ignored ) {
|
5024 |
+
ignored.push( elem );
|
5025 |
+
}
|
5026 |
+
continue;
|
5027 |
+
}
|
5028 |
+
|
5029 |
+
contains = jQuery.contains( elem.ownerDocument, elem );
|
5030 |
+
|
5031 |
+
// Append to fragment
|
5032 |
+
tmp = getAll( fragment.appendChild( elem ), "script" );
|
5033 |
+
|
5034 |
+
// Preserve script evaluation history
|
5035 |
+
if ( contains ) {
|
5036 |
+
setGlobalEval( tmp );
|
5037 |
+
}
|
5038 |
+
|
5039 |
+
// Capture executables
|
5040 |
+
if ( scripts ) {
|
5041 |
+
j = 0;
|
5042 |
+
while ( ( elem = tmp[ j++ ] ) ) {
|
5043 |
+
if ( rscriptType.test( elem.type || "" ) ) {
|
5044 |
+
scripts.push( elem );
|
5045 |
+
}
|
5046 |
+
}
|
5047 |
+
}
|
5048 |
+
}
|
5049 |
+
|
5050 |
+
return fragment;
|
5051 |
+
}
|
5052 |
+
|
5053 |
+
|
5054 |
+
( function() {
|
5055 |
+
var fragment = document.createDocumentFragment(),
|
5056 |
+
div = fragment.appendChild( document.createElement( "div" ) ),
|
5057 |
+
input = document.createElement( "input" );
|
5058 |
+
|
5059 |
+
// Support: Android 4.0 - 4.3 only
|
5060 |
+
// Check state lost if the name is set (#11217)
|
5061 |
+
// Support: Windows Web Apps (WWA)
|
5062 |
+
// `name` and `type` must use .setAttribute for WWA (#14901)
|
5063 |
+
input.setAttribute( "type", "radio" );
|
5064 |
+
input.setAttribute( "checked", "checked" );
|
5065 |
+
input.setAttribute( "name", "t" );
|
5066 |
+
|
5067 |
+
div.appendChild( input );
|
5068 |
+
|
5069 |
+
// Support: Android <=4.1 only
|
5070 |
+
// Older WebKit doesn't clone checked state correctly in fragments
|
5071 |
+
support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
|
5072 |
+
|
5073 |
+
// Support: IE <=11 only
|
5074 |
+
// Make sure textarea (and checkbox) defaultValue is properly cloned
|
5075 |
+
div.innerHTML = "<textarea>x</textarea>";
|
5076 |
+
support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
|
5077 |
+
} )();
|
5078 |
+
var documentElement = document.documentElement;
|
5079 |
+
|
5080 |
+
|
5081 |
+
|
5082 |
+
var
|
5083 |
+
rkeyEvent = /^key/,
|
5084 |
+
rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
|
5085 |
+
rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
|
5086 |
+
|
5087 |
+
function returnTrue() {
|
5088 |
+
return true;
|
5089 |
+
}
|
5090 |
+
|
5091 |
+
function returnFalse() {
|
5092 |
+
return false;
|
5093 |
+
}
|
5094 |
+
|
5095 |
+
// Support: IE <=9 only
|
5096 |
+
// See #13393 for more info
|
5097 |
+
function safeActiveElement() {
|
5098 |
+
try {
|
5099 |
+
return document.activeElement;
|
5100 |
+
} catch ( err ) { }
|
5101 |
+
}
|
5102 |
+
|
5103 |
+
function on( elem, types, selector, data, fn, one ) {
|
5104 |
+
var origFn, type;
|
5105 |
+
|
5106 |
+
// Types can be a map of types/handlers
|
5107 |
+
if ( typeof types === "object" ) {
|
5108 |
+
|
5109 |
+
// ( types-Object, selector, data )
|
5110 |
+
if ( typeof selector !== "string" ) {
|
5111 |
+
|
5112 |
+
// ( types-Object, data )
|
5113 |
+
data = data || selector;
|
5114 |
+
selector = undefined;
|
5115 |
+
}
|
5116 |
+
for ( type in types ) {
|
5117 |
+
on( elem, type, selector, data, types[ type ], one );
|
5118 |
+
}
|
5119 |
+
return elem;
|
5120 |
+
}
|
5121 |
+
|
5122 |
+
if ( data == null && fn == null ) {
|
5123 |
+
|
5124 |
+
// ( types, fn )
|
5125 |
+
fn = selector;
|
5126 |
+
data = selector = undefined;
|
5127 |
+
} else if ( fn == null ) {
|
5128 |
+
if ( typeof selector === "string" ) {
|
5129 |
+
|
5130 |
+
// ( types, selector, fn )
|
5131 |
+
fn = data;
|
5132 |
+
data = undefined;
|
5133 |
+
} else {
|
5134 |
+
|
5135 |
+
// ( types, data, fn )
|
5136 |
+
fn = data;
|
5137 |
+
data = selector;
|
5138 |
+
selector = undefined;
|
5139 |
+
}
|
5140 |
+
}
|
5141 |
+
if ( fn === false ) {
|
5142 |
+
fn = returnFalse;
|
5143 |
+
} else if ( !fn ) {
|
5144 |
+
return elem;
|
5145 |
+
}
|
5146 |
+
|
5147 |
+
if ( one === 1 ) {
|
5148 |
+
origFn = fn;
|
5149 |
+
fn = function( event ) {
|
5150 |
+
|
5151 |
+
// Can use an empty set, since event contains the info
|
5152 |
+
jQuery().off( event );
|
5153 |
+
return origFn.apply( this, arguments );
|
5154 |
+
};
|
5155 |
+
|
5156 |
+
// Use same guid so caller can remove using origFn
|
5157 |
+
fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
|
5158 |
+
}
|
5159 |
+
return elem.each( function() {
|
5160 |
+
jQuery.event.add( this, types, fn, data, selector );
|
5161 |
+
} );
|
5162 |
+
}
|
5163 |
+
|
5164 |
+
/*
|
5165 |
+
* Helper functions for managing events -- not part of the public interface.
|
5166 |
+
* Props to Dean Edwards' addEvent library for many of the ideas.
|
5167 |
+
*/
|
5168 |
+
jQuery.event = {
|
5169 |
+
|
5170 |
+
global: {},
|
5171 |
+
|
5172 |
+
add: function( elem, types, handler, data, selector ) {
|
5173 |
+
|
5174 |
+
var handleObjIn, eventHandle, tmp,
|
5175 |
+
events, t, handleObj,
|
5176 |
+
special, handlers, type, namespaces, origType,
|
5177 |
+
elemData = dataPriv.get( elem );
|
5178 |
+
|
5179 |
+
// Don't attach events to noData or text/comment nodes (but allow plain objects)
|
5180 |
+
if ( !elemData ) {
|
5181 |
+
return;
|
5182 |
+
}
|
5183 |
+
|
5184 |
+
// Caller can pass in an object of custom data in lieu of the handler
|
5185 |
+
if ( handler.handler ) {
|
5186 |
+
handleObjIn = handler;
|
5187 |
+
handler = handleObjIn.handler;
|
5188 |
+
selector = handleObjIn.selector;
|
5189 |
+
}
|
5190 |
+
|
5191 |
+
// Ensure that invalid selectors throw exceptions at attach time
|
5192 |
+
// Evaluate against documentElement in case elem is a non-element node (e.g., document)
|
5193 |
+
if ( selector ) {
|
5194 |
+
jQuery.find.matchesSelector( documentElement, selector );
|
5195 |
+
}
|
5196 |
+
|
5197 |
+
// Make sure that the handler has a unique ID, used to find/remove it later
|
5198 |
+
if ( !handler.guid ) {
|
5199 |
+
handler.guid = jQuery.guid++;
|
5200 |
+
}
|
5201 |
+
|
5202 |
+
// Init the element's event structure and main handler, if this is the first
|
5203 |
+
if ( !( events = elemData.events ) ) {
|
5204 |
+
events = elemData.events = {};
|
5205 |
+
}
|
5206 |
+
if ( !( eventHandle = elemData.handle ) ) {
|
5207 |
+
eventHandle = elemData.handle = function( e ) {
|
5208 |
+
|
5209 |
+
// Discard the second event of a jQuery.event.trigger() and
|
5210 |
+
// when an event is called after a page has unloaded
|
5211 |
+
return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
|
5212 |
+
jQuery.event.dispatch.apply( elem, arguments ) : undefined;
|
5213 |
+
};
|
5214 |
+
}
|
5215 |
+
|
5216 |
+
// Handle multiple events separated by a space
|
5217 |
+
types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
|
5218 |
+
t = types.length;
|
5219 |
+
while ( t-- ) {
|
5220 |
+
tmp = rtypenamespace.exec( types[ t ] ) || [];
|
5221 |
+
type = origType = tmp[ 1 ];
|
5222 |
+
namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
|
5223 |
+
|
5224 |
+
// There *must* be a type, no attaching namespace-only handlers
|
5225 |
+
if ( !type ) {
|
5226 |
+
continue;
|
5227 |
+
}
|
5228 |
+
|
5229 |
+
// If event changes its type, use the special event handlers for the changed type
|
5230 |
+
special = jQuery.event.special[ type ] || {};
|
5231 |
+
|
5232 |
+
// If selector defined, determine special event api type, otherwise given type
|
5233 |
+
type = ( selector ? special.delegateType : special.bindType ) || type;
|
5234 |
+
|
5235 |
+
// Update special based on newly reset type
|
5236 |
+
special = jQuery.event.special[ type ] || {};
|
5237 |
+
|
5238 |
+
// handleObj is passed to all event handlers
|
5239 |
+
handleObj = jQuery.extend( {
|
5240 |
+
type: type,
|
5241 |
+
origType: origType,
|
5242 |
+
data: data,
|
5243 |
+
handler: handler,
|
5244 |
+
guid: handler.guid,
|
5245 |
+
selector: selector,
|
5246 |
+
needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
|
5247 |
+
namespace: namespaces.join( "." )
|
5248 |
+
}, handleObjIn );
|
5249 |
+
|
5250 |
+
// Init the event handler queue if we're the first
|
5251 |
+
if ( !( handlers = events[ type ] ) ) {
|
5252 |
+
handlers = events[ type ] = [];
|
5253 |
+
handlers.delegateCount = 0;
|
5254 |
+
|
5255 |
+
// Only use addEventListener if the special events handler returns false
|
5256 |
+
if ( !special.setup ||
|
5257 |
+
special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
|
5258 |
+
|
5259 |
+
if ( elem.addEventListener ) {
|
5260 |
+
elem.addEventListener( type, eventHandle );
|
5261 |
+
}
|
5262 |
+
}
|
5263 |
+
}
|
5264 |
+
|
5265 |
+
if ( special.add ) {
|
5266 |
+
special.add.call( elem, handleObj );
|
5267 |
+
|
5268 |
+
if ( !handleObj.handler.guid ) {
|
5269 |
+
handleObj.handler.guid = handler.guid;
|
5270 |
+
}
|
5271 |
+
}
|
5272 |
+
|
5273 |
+
// Add to the element's handler list, delegates in front
|
5274 |
+
if ( selector ) {
|
5275 |
+
handlers.splice( handlers.delegateCount++, 0, handleObj );
|
5276 |
+
} else {
|
5277 |
+
handlers.push( handleObj );
|
5278 |
+
}
|
5279 |
+
|
5280 |
+
// Keep track of which events have ever been used, for event optimization
|
5281 |
+
jQuery.event.global[ type ] = true;
|
5282 |
+
}
|
5283 |
+
|
5284 |
+
},
|
5285 |
+
|
5286 |
+
// Detach an event or set of events from an element
|
5287 |
+
remove: function( elem, types, handler, selector, mappedTypes ) {
|
5288 |
+
|
5289 |
+
var j, origCount, tmp,
|
5290 |
+
events, t, handleObj,
|
5291 |
+
special, handlers, type, namespaces, origType,
|
5292 |
+
elemData = dataPriv.hasData( elem ) && dataPriv.get( elem );
|
5293 |
+
|
5294 |
+
if ( !elemData || !( events = elemData.events ) ) {
|
5295 |
+
return;
|
5296 |
+
}
|
5297 |
+
|
5298 |
+
// Once for each type.namespace in types; type may be omitted
|
5299 |
+
types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
|
5300 |
+
t = types.length;
|
5301 |
+
while ( t-- ) {
|
5302 |
+
tmp = rtypenamespace.exec( types[ t ] ) || [];
|
5303 |
+
type = origType = tmp[ 1 ];
|
5304 |
+
namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
|
5305 |
+
|
5306 |
+
// Unbind all events (on this namespace, if provided) for the element
|
5307 |
+
if ( !type ) {
|
5308 |
+
for ( type in events ) {
|
5309 |
+
jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
|
5310 |
+
}
|
5311 |
+
continue;
|
5312 |
+
}
|
5313 |
+
|
5314 |
+
special = jQuery.event.special[ type ] || {};
|
5315 |
+
type = ( selector ? special.delegateType : special.bindType ) || type;
|
5316 |
+
handlers = events[ type ] || [];
|
5317 |
+
tmp = tmp[ 2 ] &&
|
5318 |
+
new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" );
|
5319 |
+
|
5320 |
+
// Remove matching events
|
5321 |
+
origCount = j = handlers.length;
|
5322 |
+
while ( j-- ) {
|
5323 |
+
handleObj = handlers[ j ];
|
5324 |
+
|
5325 |
+
if ( ( mappedTypes || origType === handleObj.origType ) &&
|
5326 |
+
( !handler || handler.guid === handleObj.guid ) &&
|
5327 |
+
( !tmp || tmp.test( handleObj.namespace ) ) &&
|
5328 |
+
( !selector || selector === handleObj.selector ||
|
5329 |
+
selector === "**" && handleObj.selector ) ) {
|
5330 |
+
handlers.splice( j, 1 );
|
5331 |
+
|
5332 |
+
if ( handleObj.selector ) {
|
5333 |
+
handlers.delegateCount--;
|
5334 |
+
}
|
5335 |
+
if ( special.remove ) {
|
5336 |
+
special.remove.call( elem, handleObj );
|
5337 |
+
}
|
5338 |
+
}
|
5339 |
+
}
|
5340 |
+
|
5341 |
+
// Remove generic event handler if we removed something and no more handlers exist
|
5342 |
+
// (avoids potential for endless recursion during removal of special event handlers)
|
5343 |
+
if ( origCount && !handlers.length ) {
|
5344 |
+
if ( !special.teardown ||
|
5345 |
+
special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
|
5346 |
+
|
5347 |
+
jQuery.removeEvent( elem, type, elemData.handle );
|
5348 |
+
}
|
5349 |
+
|
5350 |
+
delete events[ type ];
|
5351 |
+
}
|
5352 |
+
}
|
5353 |
+
|
5354 |
+
// Remove data and the expando if it's no longer used
|
5355 |
+
if ( jQuery.isEmptyObject( events ) ) {
|
5356 |
+
dataPriv.remove( elem, "handle events" );
|
5357 |
+
}
|
5358 |
+
},
|
5359 |
+
|
5360 |
+
dispatch: function( nativeEvent ) {
|
5361 |
+
|
5362 |
+
// Make a writable jQuery.Event from the native event object
|
5363 |
+
var event = jQuery.event.fix( nativeEvent );
|
5364 |
+
|
5365 |
+
var i, j, ret, matched, handleObj, handlerQueue,
|
5366 |
+
args = new Array( arguments.length ),
|
5367 |
+
handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [],
|
5368 |
+
special = jQuery.event.special[ event.type ] || {};
|
5369 |
+
|
5370 |
+
// Use the fix-ed jQuery.Event rather than the (read-only) native event
|
5371 |
+
args[ 0 ] = event;
|
5372 |
+
|
5373 |
+
for ( i = 1; i < arguments.length; i++ ) {
|
5374 |
+
args[ i ] = arguments[ i ];
|
5375 |
+
}
|
5376 |
+
|
5377 |
+
event.delegateTarget = this;
|
5378 |
+
|
5379 |
+
// Call the preDispatch hook for the mapped type, and let it bail if desired
|
5380 |
+
if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
|
5381 |
+
return;
|
5382 |
+
}
|
5383 |
+
|
5384 |
+
// Determine handlers
|
5385 |
+
handlerQueue = jQuery.event.handlers.call( this, event, handlers );
|
5386 |
+
|
5387 |
+
// Run delegates first; they may want to stop propagation beneath us
|
5388 |
+
i = 0;
|
5389 |
+
while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
|
5390 |
+
event.currentTarget = matched.elem;
|
5391 |
+
|
5392 |
+
j = 0;
|
5393 |
+
while ( ( handleObj = matched.handlers[ j++ ] ) &&
|
5394 |
+
!event.isImmediatePropagationStopped() ) {
|
5395 |
+
|
5396 |
+
// Triggered event must either 1) have no namespace, or 2) have namespace(s)
|
5397 |
+
// a subset or equal to those in the bound event (both can have no namespace).
|
5398 |
+
if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) {
|
5399 |
+
|
5400 |
+
event.handleObj = handleObj;
|
5401 |
+
event.data = handleObj.data;
|
5402 |
+
|
5403 |
+
ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
|
5404 |
+
handleObj.handler ).apply( matched.elem, args );
|
5405 |
+
|
5406 |
+
if ( ret !== undefined ) {
|
5407 |
+
if ( ( event.result = ret ) === false ) {
|
5408 |
+
event.preventDefault();
|
5409 |
+
event.stopPropagation();
|
5410 |
+
}
|
5411 |
+
}
|
5412 |
+
}
|
5413 |
+
}
|
5414 |
+
}
|
5415 |
+
|
5416 |
+
// Call the postDispatch hook for the mapped type
|
5417 |
+
if ( special.postDispatch ) {
|
5418 |
+
special.postDispatch.call( this, event );
|
5419 |
+
}
|
5420 |
+
|
5421 |
+
return event.result;
|
5422 |
+
},
|
5423 |
+
|
5424 |
+
handlers: function( event, handlers ) {
|
5425 |
+
var i, handleObj, sel, matchedHandlers, matchedSelectors,
|
5426 |
+
handlerQueue = [],
|
5427 |
+
delegateCount = handlers.delegateCount,
|
5428 |
+
cur = event.target;
|
5429 |
+
|
5430 |
+
// Find delegate handlers
|
5431 |
+
if ( delegateCount &&
|
5432 |
+
|
5433 |
+
// Support: IE <=9
|
5434 |
+
// Black-hole SVG <use> instance trees (trac-13180)
|
5435 |
+
cur.nodeType &&
|
5436 |
+
|
5437 |
+
// Support: Firefox <=42
|
5438 |
+
// Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)
|
5439 |
+
// https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click
|
5440 |
+
// Support: IE 11 only
|
5441 |
+
// ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343)
|
5442 |
+
!( event.type === "click" && event.button >= 1 ) ) {
|
5443 |
+
|
5444 |
+
for ( ; cur !== this; cur = cur.parentNode || this ) {
|
5445 |
+
|
5446 |
+
// Don't check non-elements (#13208)
|
5447 |
+
// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
|
5448 |
+
if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) {
|
5449 |
+
matchedHandlers = [];
|
5450 |
+
matchedSelectors = {};
|
5451 |
+
for ( i = 0; i < delegateCount; i++ ) {
|
5452 |
+
handleObj = handlers[ i ];
|
5453 |
+
|
5454 |
+
// Don't conflict with Object.prototype properties (#13203)
|
5455 |
+
sel = handleObj.selector + " ";
|
5456 |
+
|
5457 |
+
if ( matchedSelectors[ sel ] === undefined ) {
|
5458 |
+
matchedSelectors[ sel ] = handleObj.needsContext ?
|
5459 |
+
jQuery( sel, this ).index( cur ) > -1 :
|
5460 |
+
jQuery.find( sel, this, null, [ cur ] ).length;
|
5461 |
+
}
|
5462 |
+
if ( matchedSelectors[ sel ] ) {
|
5463 |
+
matchedHandlers.push( handleObj );
|
5464 |
+
}
|
5465 |
+
}
|
5466 |
+
if ( matchedHandlers.length ) {
|
5467 |
+
handlerQueue.push( { elem: cur, handlers: matchedHandlers } );
|
5468 |
+
}
|
5469 |
+
}
|
5470 |
+
}
|
5471 |
+
}
|
5472 |
+
|
5473 |
+
// Add the remaining (directly-bound) handlers
|
5474 |
+
cur = this;
|
5475 |
+
if ( delegateCount < handlers.length ) {
|
5476 |
+
handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );
|
5477 |
+
}
|
5478 |
+
|
5479 |
+
return handlerQueue;
|
5480 |
+
},
|
5481 |
+
|
5482 |
+
addProp: function( name, hook ) {
|
5483 |
+
Object.defineProperty( jQuery.Event.prototype, name, {
|
5484 |
+
enumerable: true,
|
5485 |
+
configurable: true,
|
5486 |
+
|
5487 |
+
get: isFunction( hook ) ?
|
5488 |
+
function() {
|
5489 |
+
if ( this.originalEvent ) {
|
5490 |
+
return hook( this.originalEvent );
|
5491 |
+
}
|
5492 |
+
} :
|
5493 |
+
function() {
|
5494 |
+
if ( this.originalEvent ) {
|
5495 |
+
return this.originalEvent[ name ];
|
5496 |
+
}
|
5497 |
+
},
|
5498 |
+
|
5499 |
+
set: function( value ) {
|
5500 |
+
Object.defineProperty( this, name, {
|
5501 |
+
enumerable: true,
|
5502 |
+
configurable: true,
|
5503 |
+
writable: true,
|
5504 |
+
value: value
|
5505 |
+
} );
|
5506 |
+
}
|
5507 |
+
} );
|
5508 |
+
},
|
5509 |
+
|
5510 |
+
fix: function( originalEvent ) {
|
5511 |
+
return originalEvent[ jQuery.expando ] ?
|
5512 |
+
originalEvent :
|
5513 |
+
new jQuery.Event( originalEvent );
|
5514 |
+
},
|
5515 |
+
|
5516 |
+
special: {
|
5517 |
+
load: {
|
5518 |
+
|
5519 |
+
// Prevent triggered image.load events from bubbling to window.load
|
5520 |
+
noBubble: true
|
5521 |
+
},
|
5522 |
+
focus: {
|
5523 |
+
|
5524 |
+
// Fire native event if possible so blur/focus sequence is correct
|
5525 |
+
trigger: function() {
|
5526 |
+
if ( this !== safeActiveElement() && this.focus ) {
|
5527 |
+
this.focus();
|
5528 |
+
return false;
|
5529 |
+
}
|
5530 |
+
},
|
5531 |
+
delegateType: "focusin"
|
5532 |
+
},
|
5533 |
+
blur: {
|
5534 |
+
trigger: function() {
|
5535 |
+
if ( this === safeActiveElement() && this.blur ) {
|
5536 |
+
this.blur();
|
5537 |
+
return false;
|
5538 |
+
}
|
5539 |
+
},
|
5540 |
+
delegateType: "focusout"
|
5541 |
+
},
|
5542 |
+
click: {
|
5543 |
+
|
5544 |
+
// For checkbox, fire native event so checked state will be right
|
5545 |
+
trigger: function() {
|
5546 |
+
if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) {
|
5547 |
+
this.click();
|
5548 |
+
return false;
|
5549 |
+
}
|
5550 |
+
},
|
5551 |
+
|
5552 |
+
// For cross-browser consistency, don't fire native .click() on links
|
5553 |
+
_default: function( event ) {
|
5554 |
+
return nodeName( event.target, "a" );
|
5555 |
+
}
|
5556 |
+
},
|
5557 |
+
|
5558 |
+
beforeunload: {
|
5559 |
+
postDispatch: function( event ) {
|
5560 |
+
|
5561 |
+
// Support: Firefox 20+
|
5562 |
+
// Firefox doesn't alert if the returnValue field is not set.
|
5563 |
+
if ( event.result !== undefined && event.originalEvent ) {
|
5564 |
+
event.originalEvent.returnValue = event.result;
|
5565 |
+
}
|
5566 |
+
}
|
5567 |
+
}
|
5568 |
+
}
|
5569 |
+
};
|
5570 |
+
|
5571 |
+
jQuery.removeEvent = function( elem, type, handle ) {
|
5572 |
+
|
5573 |
+
// This "if" is needed for plain objects
|
5574 |
+
if ( elem.removeEventListener ) {
|
5575 |
+
elem.removeEventListener( type, handle );
|
5576 |
+
}
|
5577 |
+
};
|
5578 |
+
|
5579 |
+
jQuery.Event = function( src, props ) {
|
5580 |
+
|
5581 |
+
// Allow instantiation without the 'new' keyword
|
5582 |
+
if ( !( this instanceof jQuery.Event ) ) {
|
5583 |
+
return new jQuery.Event( src, props );
|
5584 |
+
}
|
5585 |
+
|
5586 |
+
// Event object
|
5587 |
+
if ( src && src.type ) {
|
5588 |
+
this.originalEvent = src;
|
5589 |
+
this.type = src.type;
|
5590 |
+
|
5591 |
+
// Events bubbling up the document may have been marked as prevented
|
5592 |
+
// by a handler lower down the tree; reflect the correct value.
|
5593 |
+
this.isDefaultPrevented = src.defaultPrevented ||
|
5594 |
+
src.defaultPrevented === undefined &&
|
5595 |
+
|
5596 |
+
// Support: Android <=2.3 only
|
5597 |
+
src.returnValue === false ?
|
5598 |
+
returnTrue :
|
5599 |
+
returnFalse;
|
5600 |
+
|
5601 |
+
// Create target properties
|
5602 |
+
// Support: Safari <=6 - 7 only
|
5603 |
+
// Target should not be a text node (#504, #13143)
|
5604 |
+
this.target = ( src.target && src.target.nodeType === 3 ) ?
|
5605 |
+
src.target.parentNode :
|
5606 |
+
src.target;
|
5607 |
+
|
5608 |
+
this.currentTarget = src.currentTarget;
|
5609 |
+
this.relatedTarget = src.relatedTarget;
|
5610 |
+
|
5611 |
+
// Event type
|
5612 |
+
} else {
|
5613 |
+
this.type = src;
|
5614 |
+
}
|
5615 |
+
|
5616 |
+
// Put explicitly provided properties onto the event object
|
5617 |
+
if ( props ) {
|
5618 |
+
jQuery.extend( this, props );
|
5619 |
+
}
|
5620 |
+
|
5621 |
+
// Create a timestamp if incoming event doesn't have one
|
5622 |
+
this.timeStamp = src && src.timeStamp || Date.now();
|
5623 |
+
|
5624 |
+
// Mark it as fixed
|
5625 |
+
this[ jQuery.expando ] = true;
|
5626 |
+
};
|
5627 |
+
|
5628 |
+
// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
|
5629 |
+
// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
|
5630 |
+
jQuery.Event.prototype = {
|
5631 |
+
constructor: jQuery.Event,
|
5632 |
+
isDefaultPrevented: returnFalse,
|
5633 |
+
isPropagationStopped: returnFalse,
|
5634 |
+
isImmediatePropagationStopped: returnFalse,
|
5635 |
+
isSimulated: false,
|
5636 |
+
|
5637 |
+
preventDefault: function() {
|
5638 |
+
var e = this.originalEvent;
|
5639 |
+
|
5640 |
+
this.isDefaultPrevented = returnTrue;
|
5641 |
+
|
5642 |
+
if ( e && !this.isSimulated ) {
|
5643 |
+
e.preventDefault();
|
5644 |
+
}
|
5645 |
+
},
|
5646 |
+
stopPropagation: function() {
|
5647 |
+
var e = this.originalEvent;
|
5648 |
+
|
5649 |
+
this.isPropagationStopped = returnTrue;
|
5650 |
+
|
5651 |
+
if ( e && !this.isSimulated ) {
|
5652 |
+
e.stopPropagation();
|
5653 |
+
}
|
5654 |
+
},
|
5655 |
+
stopImmediatePropagation: function() {
|
5656 |
+
var e = this.originalEvent;
|
5657 |
+
|
5658 |
+
this.isImmediatePropagationStopped = returnTrue;
|
5659 |
+
|
5660 |
+
if ( e && !this.isSimulated ) {
|
5661 |
+
e.stopImmediatePropagation();
|
5662 |
+
}
|
5663 |
+
|
5664 |
+
this.stopPropagation();
|
5665 |
+
}
|
5666 |
+
};
|
5667 |
+
|
5668 |
+
// Includes all common event props including KeyEvent and MouseEvent specific props
|
5669 |
+
jQuery.each( {
|
5670 |
+
altKey: true,
|
5671 |
+
bubbles: true,
|
5672 |
+
cancelable: true,
|
5673 |
+
changedTouches: true,
|
5674 |
+
ctrlKey: true,
|
5675 |
+
detail: true,
|
5676 |
+
eventPhase: true,
|
5677 |
+
metaKey: true,
|
5678 |
+
pageX: true,
|
5679 |
+
pageY: true,
|
5680 |
+
shiftKey: true,
|
5681 |
+
view: true,
|
5682 |
+
"char": true,
|
5683 |
+
charCode: true,
|
5684 |
+
key: true,
|
5685 |
+
keyCode: true,
|
5686 |
+
button: true,
|
5687 |
+
buttons: true,
|
5688 |
+
clientX: true,
|
5689 |
+
clientY: true,
|
5690 |
+
offsetX: true,
|
5691 |
+
offsetY: true,
|
5692 |
+
pointerId: true,
|
5693 |
+
pointerType: true,
|
5694 |
+
screenX: true,
|
5695 |
+
screenY: true,
|
5696 |
+
targetTouches: true,
|
5697 |
+
toElement: true,
|
5698 |
+
touches: true,
|
5699 |
+
|
5700 |
+
which: function( event ) {
|
5701 |
+
var button = event.button;
|
5702 |
+
|
5703 |
+
// Add which for key events
|
5704 |
+
if ( event.which == null && rkeyEvent.test( event.type ) ) {
|
5705 |
+
return event.charCode != null ? event.charCode : event.keyCode;
|
5706 |
+
}
|
5707 |
+
|
5708 |
+
// Add which for click: 1 === left; 2 === middle; 3 === right
|
5709 |
+
if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) {
|
5710 |
+
if ( button & 1 ) {
|
5711 |
+
return 1;
|
5712 |
+
}
|
5713 |
+
|
5714 |
+
if ( button & 2 ) {
|
5715 |
+
return 3;
|
5716 |
+
}
|
5717 |
+
|
5718 |
+
if ( button & 4 ) {
|
5719 |
+
return 2;
|
5720 |
+
}
|
5721 |
+
|
5722 |
+
return 0;
|
5723 |
+
}
|
5724 |
+
|
5725 |
+
return event.which;
|
5726 |
+
}
|
5727 |
+
}, jQuery.event.addProp );
|
5728 |
+
|
5729 |
+
// Create mouseenter/leave events using mouseover/out and event-time checks
|
5730 |
+
// so that event delegation works in jQuery.
|
5731 |
+
// Do the same for pointerenter/pointerleave and pointerover/pointerout
|
5732 |
+
//
|
5733 |
+
// Support: Safari 7 only
|
5734 |
+
// Safari sends mouseenter too often; see:
|
5735 |
+
// https://bugs.chromium.org/p/chromium/issues/detail?id=470258
|
5736 |
+
// for the description of the bug (it existed in older Chrome versions as well).
|
5737 |
+
jQuery.each( {
|
5738 |
+
mouseenter: "mouseover",
|
5739 |
+
mouseleave: "mouseout",
|
5740 |
+
pointerenter: "pointerover",
|
5741 |
+
pointerleave: "pointerout"
|
5742 |
+
}, function( orig, fix ) {
|
5743 |
+
jQuery.event.special[ orig ] = {
|
5744 |
+
delegateType: fix,
|
5745 |
+
bindType: fix,
|
5746 |
+
|
5747 |
+
handle: function( event ) {
|
5748 |
+
var ret,
|
5749 |
+
target = this,
|
5750 |
+
related = event.relatedTarget,
|
5751 |
+
handleObj = event.handleObj;
|
5752 |
+
|
5753 |
+
// For mouseenter/leave call the handler if related is outside the target.
|
5754 |
+
// NB: No relatedTarget if the mouse left/entered the browser window
|
5755 |
+
if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {
|
5756 |
+
event.type = handleObj.origType;
|
5757 |
+
ret = handleObj.handler.apply( this, arguments );
|
5758 |
+
event.type = fix;
|
5759 |
+
}
|
5760 |
+
return ret;
|
5761 |
+
}
|
5762 |
+
};
|
5763 |
+
} );
|
5764 |
+
|
5765 |
+
jQuery.fn.extend( {
|
5766 |
+
|
5767 |
+
on: function( types, selector, data, fn ) {
|
5768 |
+
return on( this, types, selector, data, fn );
|
5769 |
+
},
|
5770 |
+
one: function( types, selector, data, fn ) {
|
5771 |
+
return on( this, types, selector, data, fn, 1 );
|
5772 |
+
},
|
5773 |
+
off: function( types, selector, fn ) {
|
5774 |
+
var handleObj, type;
|
5775 |
+
if ( types && types.preventDefault && types.handleObj ) {
|
5776 |
+
|
5777 |
+
// ( event ) dispatched jQuery.Event
|
5778 |
+
handleObj = types.handleObj;
|
5779 |
+
jQuery( types.delegateTarget ).off(
|
5780 |
+
handleObj.namespace ?
|
5781 |
+
handleObj.origType + "." + handleObj.namespace :
|
5782 |
+
handleObj.origType,
|
5783 |
+
handleObj.selector,
|
5784 |
+
handleObj.handler
|
5785 |
+
);
|
5786 |
+
return this;
|
5787 |
+
}
|
5788 |
+
if ( typeof types === "object" ) {
|
5789 |
+
|
5790 |
+
// ( types-object [, selector] )
|
5791 |
+
for ( type in types ) {
|
5792 |
+
this.off( type, selector, types[ type ] );
|
5793 |
+
}
|
5794 |
+
return this;
|
5795 |
+
}
|
5796 |
+
if ( selector === false || typeof selector === "function" ) {
|
5797 |
+
|
5798 |
+
// ( types [, fn] )
|
5799 |
+
fn = selector;
|
5800 |
+
selector = undefined;
|
5801 |
+
}
|
5802 |
+
if ( fn === false ) {
|
5803 |
+
fn = returnFalse;
|
5804 |
+
}
|
5805 |
+
return this.each( function() {
|
5806 |
+
jQuery.event.remove( this, types, fn, selector );
|
5807 |
+
} );
|
5808 |
+
}
|
5809 |
+
} );
|
5810 |
+
|
5811 |
+
|
5812 |
+
var
|
5813 |
+
|
5814 |
+
/* eslint-disable max-len */
|
5815 |
+
|
5816 |
+
// See https://github.com/eslint/eslint/issues/3229
|
5817 |
+
rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,
|
5818 |
+
|
5819 |
+
/* eslint-enable */
|
5820 |
+
|
5821 |
+
// Support: IE <=10 - 11, Edge 12 - 13 only
|
5822 |
+
// In IE/Edge using regex groups here causes severe slowdowns.
|
5823 |
+
// See https://connect.microsoft.com/IE/feedback/details/1736512/
|
5824 |
+
rnoInnerhtml = /<script|<style|<link/i,
|
5825 |
+
|
5826 |
+
// checked="checked" or checked
|
5827 |
+
rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
|
5828 |
+
rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;
|
5829 |
+
|
5830 |
+
// Prefer a tbody over its parent table for containing new rows
|
5831 |
+
function manipulationTarget( elem, content ) {
|
5832 |
+
if ( nodeName( elem, "table" ) &&
|
5833 |
+
nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) {
|
5834 |
+
|
5835 |
+
return jQuery( elem ).children( "tbody" )[ 0 ] || elem;
|
5836 |
+
}
|
5837 |
+
|
5838 |
+
return elem;
|
5839 |
+
}
|
5840 |
+
|
5841 |
+
// Replace/restore the type attribute of script elements for safe DOM manipulation
|
5842 |
+
function disableScript( elem ) {
|
5843 |
+
elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type;
|
5844 |
+
return elem;
|
5845 |
+
}
|
5846 |
+
function restoreScript( elem ) {
|
5847 |
+
if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) {
|
5848 |
+
elem.type = elem.type.slice( 5 );
|
5849 |
+
} else {
|
5850 |
+
elem.removeAttribute( "type" );
|
5851 |
+
}
|
5852 |
+
|
5853 |
+
return elem;
|
5854 |
+
}
|
5855 |
+
|
5856 |
+
function cloneCopyEvent( src, dest ) {
|
5857 |
+
var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
|
5858 |
+
|
5859 |
+
if ( dest.nodeType !== 1 ) {
|
5860 |
+
return;
|
5861 |
+
}
|
5862 |
+
|
5863 |
+
// 1. Copy private data: events, handlers, etc.
|
5864 |
+
if ( dataPriv.hasData( src ) ) {
|
5865 |
+
pdataOld = dataPriv.access( src );
|
5866 |
+
pdataCur = dataPriv.set( dest, pdataOld );
|
5867 |
+
events = pdataOld.events;
|
5868 |
+
|
5869 |
+
if ( events ) {
|
5870 |
+
delete pdataCur.handle;
|
5871 |
+
pdataCur.events = {};
|
5872 |
+
|
5873 |
+
for ( type in events ) {
|
5874 |
+
for ( i = 0, l = events[ type ].length; i < l; i++ ) {
|
5875 |
+
jQuery.event.add( dest, type, events[ type ][ i ] );
|
5876 |
+
}
|
5877 |
+
}
|
5878 |
+
}
|
5879 |
+
}
|
5880 |
+
|
5881 |
+
// 2. Copy user data
|
5882 |
+
if ( dataUser.hasData( src ) ) {
|
5883 |
+
udataOld = dataUser.access( src );
|
5884 |
+
udataCur = jQuery.extend( {}, udataOld );
|
5885 |
+
|
5886 |
+
dataUser.set( dest, udataCur );
|
5887 |
+
}
|
5888 |
+
}
|
5889 |
+
|
5890 |
+
// Fix IE bugs, see support tests
|
5891 |
+
function fixInput( src, dest ) {
|
5892 |
+
var nodeName = dest.nodeName.toLowerCase();
|
5893 |
+
|
5894 |
+
// Fails to persist the checked state of a cloned checkbox or radio button.
|
5895 |
+
if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
|
5896 |
+
dest.checked = src.checked;
|
5897 |
+
|
5898 |
+
// Fails to return the selected option to the default selected state when cloning options
|
5899 |
+
} else if ( nodeName === "input" || nodeName === "textarea" ) {
|
5900 |
+
dest.defaultValue = src.defaultValue;
|
5901 |
+
}
|
5902 |
+
}
|
5903 |
+
|
5904 |
+
function domManip( collection, args, callback, ignored ) {
|
5905 |
+
|
5906 |
+
// Flatten any nested arrays
|
5907 |
+
args = concat.apply( [], args );
|
5908 |
+
|
5909 |
+
var fragment, first, scripts, hasScripts, node, doc,
|
5910 |
+
i = 0,
|
5911 |
+
l = collection.length,
|
5912 |
+
iNoClone = l - 1,
|
5913 |
+
value = args[ 0 ],
|
5914 |
+
valueIsFunction = isFunction( value );
|
5915 |
+
|
5916 |
+
// We can't cloneNode fragments that contain checked, in WebKit
|
5917 |
+
if ( valueIsFunction ||
|
5918 |
+
( l > 1 && typeof value === "string" &&
|
5919 |
+
!support.checkClone && rchecked.test( value ) ) ) {
|
5920 |
+
return collection.each( function( index ) {
|
5921 |
+
var self = collection.eq( index );
|
5922 |
+
if ( valueIsFunction ) {
|
5923 |
+
args[ 0 ] = value.call( this, index, self.html() );
|
5924 |
+
}
|
5925 |
+
domManip( self, args, callback, ignored );
|
5926 |
+
} );
|
5927 |
+
}
|
5928 |
+
|
5929 |
+
if ( l ) {
|
5930 |
+
fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );
|
5931 |
+
first = fragment.firstChild;
|
5932 |
+
|
5933 |
+
if ( fragment.childNodes.length === 1 ) {
|
5934 |
+
fragment = first;
|
5935 |
+
}
|
5936 |
+
|
5937 |
+
// Require either new content or an interest in ignored elements to invoke the callback
|
5938 |
+
if ( first || ignored ) {
|
5939 |
+
scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
|
5940 |
+
hasScripts = scripts.length;
|
5941 |
+
|
5942 |
+
// Use the original fragment for the last item
|
5943 |
+
// instead of the first because it can end up
|
5944 |
+
// being emptied incorrectly in certain situations (#8070).
|
5945 |
+
for ( ; i < l; i++ ) {
|
5946 |
+
node = fragment;
|
5947 |
+
|
5948 |
+
if ( i !== iNoClone ) {
|
5949 |
+
node = jQuery.clone( node, true, true );
|
5950 |
+
|
5951 |
+
// Keep references to cloned scripts for later restoration
|
5952 |
+
if ( hasScripts ) {
|
5953 |
+
|
5954 |
+
// Support: Android <=4.0 only, PhantomJS 1 only
|
5955 |
+
// push.apply(_, arraylike) throws on ancient WebKit
|
5956 |
+
jQuery.merge( scripts, getAll( node, "script" ) );
|
5957 |
+
}
|
5958 |
+
}
|
5959 |
+
|
5960 |
+
callback.call( collection[ i ], node, i );
|
5961 |
+
}
|
5962 |
+
|
5963 |
+
if ( hasScripts ) {
|
5964 |
+
doc = scripts[ scripts.length - 1 ].ownerDocument;
|
5965 |
+
|
5966 |
+
// Reenable scripts
|
5967 |
+
jQuery.map( scripts, restoreScript );
|
5968 |
+
|
5969 |
+
// Evaluate executable scripts on first document insertion
|
5970 |
+
for ( i = 0; i < hasScripts; i++ ) {
|
5971 |
+
node = scripts[ i ];
|
5972 |
+
if ( rscriptType.test( node.type || "" ) &&
|
5973 |
+
!dataPriv.access( node, "globalEval" ) &&
|
5974 |
+
jQuery.contains( doc, node ) ) {
|
5975 |
+
|
5976 |
+
if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) {
|
5977 |
+
|
5978 |
+
// Optional AJAX dependency, but won't run scripts if not present
|
5979 |
+
if ( jQuery._evalUrl ) {
|
5980 |
+
jQuery._evalUrl( node.src );
|
5981 |
+
}
|
5982 |
+
} else {
|
5983 |
+
DOMEval( node.textContent.replace( rcleanScript, "" ), doc, node );
|
5984 |
+
}
|
5985 |
+
}
|
5986 |
+
}
|
5987 |
+
}
|
5988 |
+
}
|
5989 |
+
}
|
5990 |
+
|
5991 |
+
return collection;
|
5992 |
+
}
|
5993 |
+
|
5994 |
+
function remove( elem, selector, keepData ) {
|
5995 |
+
var node,
|
5996 |
+
nodes = selector ? jQuery.filter( selector, elem ) : elem,
|
5997 |
+
i = 0;
|
5998 |
+
|
5999 |
+
for ( ; ( node = nodes[ i ] ) != null; i++ ) {
|
6000 |
+
if ( !keepData && node.nodeType === 1 ) {
|
6001 |
+
jQuery.cleanData( getAll( node ) );
|
6002 |
+
}
|
6003 |
+
|
6004 |
+
if ( node.parentNode ) {
|
6005 |
+
if ( keepData && jQuery.contains( node.ownerDocument, node ) ) {
|
6006 |
+
setGlobalEval( getAll( node, "script" ) );
|
6007 |
+
}
|
6008 |
+
node.parentNode.removeChild( node );
|
6009 |
+
}
|
6010 |
+
}
|
6011 |
+
|
6012 |
+
return elem;
|
6013 |
+
}
|
6014 |
+
|
6015 |
+
jQuery.extend( {
|
6016 |
+
htmlPrefilter: function( html ) {
|
6017 |
+
return html.replace( rxhtmlTag, "<$1></$2>" );
|
6018 |
+
},
|
6019 |
+
|
6020 |
+
clone: function( elem, dataAndEvents, deepDataAndEvents ) {
|
6021 |
+
var i, l, srcElements, destElements,
|
6022 |
+
clone = elem.cloneNode( true ),
|
6023 |
+
inPage = jQuery.contains( elem.ownerDocument, elem );
|
6024 |
+
|
6025 |
+
// Fix IE cloning issues
|
6026 |
+
if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
|
6027 |
+
!jQuery.isXMLDoc( elem ) ) {
|
6028 |
+
|
6029 |
+
// We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2
|
6030 |
+
destElements = getAll( clone );
|
6031 |
+
srcElements = getAll( elem );
|
6032 |
+
|
6033 |
+
for ( i = 0, l = srcElements.length; i < l; i++ ) {
|
6034 |
+
fixInput( srcElements[ i ], destElements[ i ] );
|
6035 |
+
}
|
6036 |
+
}
|
6037 |
+
|
6038 |
+
// Copy the events from the original to the clone
|
6039 |
+
if ( dataAndEvents ) {
|
6040 |
+
if ( deepDataAndEvents ) {
|
6041 |
+
srcElements = srcElements || getAll( elem );
|
6042 |
+
destElements = destElements || getAll( clone );
|
6043 |
+
|
6044 |
+
for ( i = 0, l = srcElements.length; i < l; i++ ) {
|
6045 |
+
cloneCopyEvent( srcElements[ i ], destElements[ i ] );
|
6046 |
+
}
|
6047 |
+
} else {
|
6048 |
+
cloneCopyEvent( elem, clone );
|
6049 |
+
}
|
6050 |
+
}
|
6051 |
+
|
6052 |
+
// Preserve script evaluation history
|
6053 |
+
destElements = getAll( clone, "script" );
|
6054 |
+
if ( destElements.length > 0 ) {
|
6055 |
+
setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
|
6056 |
+
}
|
6057 |
+
|
6058 |
+
// Return the cloned set
|
6059 |
+
return clone;
|
6060 |
+
},
|
6061 |
+
|
6062 |
+
cleanData: function( elems ) {
|
6063 |
+
var data, elem, type,
|
6064 |
+
special = jQuery.event.special,
|
6065 |
+
i = 0;
|
6066 |
+
|
6067 |
+
for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {
|
6068 |
+
if ( acceptData( elem ) ) {
|
6069 |
+
if ( ( data = elem[ dataPriv.expando ] ) ) {
|
6070 |
+
if ( data.events ) {
|
6071 |
+
for ( type in data.events ) {
|
6072 |
+
if ( special[ type ] ) {
|
6073 |
+
jQuery.event.remove( elem, type );
|
6074 |
+
|
6075 |
+
// This is a shortcut to avoid jQuery.event.remove's overhead
|
6076 |
+
} else {
|
6077 |
+
jQuery.removeEvent( elem, type, data.handle );
|
6078 |
+
}
|
6079 |
+
}
|
6080 |
+
}
|
6081 |
+
|
6082 |
+
// Support: Chrome <=35 - 45+
|
6083 |
+
// Assign undefined instead of using delete, see Data#remove
|
6084 |
+
elem[ dataPriv.expando ] = undefined;
|
6085 |
+
}
|
6086 |
+
if ( elem[ dataUser.expando ] ) {
|
6087 |
+
|
6088 |
+
// Support: Chrome <=35 - 45+
|
6089 |
+
// Assign undefined instead of using delete, see Data#remove
|
6090 |
+
elem[ dataUser.expando ] = undefined;
|
6091 |
+
}
|
6092 |
+
}
|
6093 |
+
}
|
6094 |
+
}
|
6095 |
+
} );
|
6096 |
+
|
6097 |
+
jQuery.fn.extend( {
|
6098 |
+
detach: function( selector ) {
|
6099 |
+
return remove( this, selector, true );
|
6100 |
+
},
|
6101 |
+
|
6102 |
+
remove: function( selector ) {
|
6103 |
+
return remove( this, selector );
|
6104 |
+
},
|
6105 |
+
|
6106 |
+
text: function( value ) {
|
6107 |
+
return access( this, function( value ) {
|
6108 |
+
return value === undefined ?
|
6109 |
+
jQuery.text( this ) :
|
6110 |
+
this.empty().each( function() {
|
6111 |
+
if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
|
6112 |
+
this.textContent = value;
|
6113 |
+
}
|
6114 |
+
} );
|
6115 |
+
}, null, value, arguments.length );
|
6116 |
+
},
|
6117 |
+
|
6118 |
+
append: function() {
|
6119 |
+
return domManip( this, arguments, function( elem ) {
|
6120 |
+
if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
|
6121 |
+
var target = manipulationTarget( this, elem );
|
6122 |
+
target.appendChild( elem );
|
6123 |
+
}
|
6124 |
+
} );
|
6125 |
+
},
|
6126 |
+
|
6127 |
+
prepend: function() {
|
6128 |
+
return domManip( this, arguments, function( elem ) {
|
6129 |
+
if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
|
6130 |
+
var target = manipulationTarget( this, elem );
|
6131 |
+
target.insertBefore( elem, target.firstChild );
|
6132 |
+
}
|
6133 |
+
} );
|
6134 |
+
},
|
6135 |
+
|
6136 |
+
before: function() {
|
6137 |
+
return domManip( this, arguments, function( elem ) {
|
6138 |
+
if ( this.parentNode ) {
|
6139 |
+
this.parentNode.insertBefore( elem, this );
|
6140 |
+
}
|
6141 |
+
} );
|
6142 |
+
},
|
6143 |
+
|
6144 |
+
after: function() {
|
6145 |
+
return domManip( this, arguments, function( elem ) {
|
6146 |
+
if ( this.parentNode ) {
|
6147 |
+
this.parentNode.insertBefore( elem, this.nextSibling );
|
6148 |
+
}
|
6149 |
+
} );
|
6150 |
+
},
|
6151 |
+
|
6152 |
+
empty: function() {
|
6153 |
+
var elem,
|
6154 |
+
i = 0;
|
6155 |
+
|
6156 |
+
for ( ; ( elem = this[ i ] ) != null; i++ ) {
|
6157 |
+
if ( elem.nodeType === 1 ) {
|
6158 |
+
|
6159 |
+
// Prevent memory leaks
|
6160 |
+
jQuery.cleanData( getAll( elem, false ) );
|
6161 |
+
|
6162 |
+
// Remove any remaining nodes
|
6163 |
+
elem.textContent = "";
|
6164 |
+
}
|
6165 |
+
}
|
6166 |
+
|
6167 |
+
return this;
|
6168 |
+
},
|
6169 |
+
|
6170 |
+
clone: function( dataAndEvents, deepDataAndEvents ) {
|
6171 |
+
dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
|
6172 |
+
deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
|
6173 |
+
|
6174 |
+
return this.map( function() {
|
6175 |
+
return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
|
6176 |
+
} );
|
6177 |
+
},
|
6178 |
+
|
6179 |
+
html: function( value ) {
|
6180 |
+
return access( this, function( value ) {
|
6181 |
+
var elem = this[ 0 ] || {},
|
6182 |
+
i = 0,
|
6183 |
+
l = this.length;
|
6184 |
+
|
6185 |
+
if ( value === undefined && elem.nodeType === 1 ) {
|
6186 |
+
return elem.innerHTML;
|
6187 |
+
}
|
6188 |
+
|
6189 |
+
// See if we can take a shortcut and just use innerHTML
|
6190 |
+
if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
|
6191 |
+
!wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
|
6192 |
+
|
6193 |
+
value = jQuery.htmlPrefilter( value );
|
6194 |
+
|
6195 |
+
try {
|
6196 |
+
for ( ; i < l; i++ ) {
|
6197 |
+
elem = this[ i ] || {};
|
6198 |
+
|
6199 |
+
// Remove element nodes and prevent memory leaks
|
6200 |
+
if ( elem.nodeType === 1 ) {
|
6201 |
+
jQuery.cleanData( getAll( elem, false ) );
|
6202 |
+
elem.innerHTML = value;
|
6203 |
+
}
|
6204 |
+
}
|
6205 |
+
|
6206 |
+
elem = 0;
|
6207 |
+
|
6208 |
+
// If using innerHTML throws an exception, use the fallback method
|
6209 |
+
} catch ( e ) {}
|
6210 |
+
}
|
6211 |
+
|
6212 |
+
if ( elem ) {
|
6213 |
+
this.empty().append( value );
|
6214 |
+
}
|
6215 |
+
}, null, value, arguments.length );
|
6216 |
+
},
|
6217 |
+
|
6218 |
+
replaceWith: function() {
|
6219 |
+
var ignored = [];
|
6220 |
+
|
6221 |
+
// Make the changes, replacing each non-ignored context element with the new content
|
6222 |
+
return domManip( this, arguments, function( elem ) {
|
6223 |
+
var parent = this.parentNode;
|
6224 |
+
|
6225 |
+
if ( jQuery.inArray( this, ignored ) < 0 ) {
|
6226 |
+
jQuery.cleanData( getAll( this ) );
|
6227 |
+
if ( parent ) {
|
6228 |
+
parent.replaceChild( elem, this );
|
6229 |
+
}
|
6230 |
+
}
|
6231 |
+
|
6232 |
+
// Force callback invocation
|
6233 |
+
}, ignored );
|
6234 |
+
}
|
6235 |
+
} );
|
6236 |
+
|
6237 |
+
jQuery.each( {
|
6238 |
+
appendTo: "append",
|
6239 |
+
prependTo: "prepend",
|
6240 |
+
insertBefore: "before",
|
6241 |
+
insertAfter: "after",
|
6242 |
+
replaceAll: "replaceWith"
|
6243 |
+
}, function( name, original ) {
|
6244 |
+
jQuery.fn[ name ] = function( selector ) {
|
6245 |
+
var elems,
|
6246 |
+
ret = [],
|
6247 |
+
insert = jQuery( selector ),
|
6248 |
+
last = insert.length - 1,
|
6249 |
+
i = 0;
|
6250 |
+
|
6251 |
+
for ( ; i <= last; i++ ) {
|
6252 |
+
elems = i === last ? this : this.clone( true );
|
6253 |
+
jQuery( insert[ i ] )[ original ]( elems );
|
6254 |
+
|
6255 |
+
// Support: Android <=4.0 only, PhantomJS 1 only
|
6256 |
+
// .get() because push.apply(_, arraylike) throws on ancient WebKit
|
6257 |
+
push.apply( ret, elems.get() );
|
6258 |
+
}
|
6259 |
+
|
6260 |
+
return this.pushStack( ret );
|
6261 |
+
};
|
6262 |
+
} );
|
6263 |
+
var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
|
6264 |
+
|
6265 |
+
var getStyles = function( elem ) {
|
6266 |
+
|
6267 |
+
// Support: IE <=11 only, Firefox <=30 (#15098, #14150)
|
6268 |
+
// IE throws on elements created in popups
|
6269 |
+
// FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
|
6270 |
+
var view = elem.ownerDocument.defaultView;
|
6271 |
+
|
6272 |
+
if ( !view || !view.opener ) {
|
6273 |
+
view = window;
|
6274 |
+
}
|
6275 |
+
|
6276 |
+
return view.getComputedStyle( elem );
|
6277 |
+
};
|
6278 |
+
|
6279 |
+
var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" );
|
6280 |
+
|
6281 |
+
|
6282 |
+
|
6283 |
+
( function() {
|
6284 |
+
|
6285 |
+
// Executing both pixelPosition & boxSizingReliable tests require only one layout
|
6286 |
+
// so they're executed at the same time to save the second computation.
|
6287 |
+
function computeStyleTests() {
|
6288 |
+
|
6289 |
+
// This is a singleton, we need to execute it only once
|
6290 |
+
if ( !div ) {
|
6291 |
+
return;
|
6292 |
+
}
|
6293 |
+
|
6294 |
+
container.style.cssText = "position:absolute;left:-11111px;width:60px;" +
|
6295 |
+
"margin-top:1px;padding:0;border:0";
|
6296 |
+
div.style.cssText =
|
6297 |
+
"position:relative;display:block;box-sizing:border-box;overflow:scroll;" +
|
6298 |
+
"margin:auto;border:1px;padding:1px;" +
|
6299 |
+
"width:60%;top:1%";
|
6300 |
+
documentElement.appendChild( container ).appendChild( div );
|
6301 |
+
|
6302 |
+
var divStyle = window.getComputedStyle( div );
|
6303 |
+
pixelPositionVal = divStyle.top !== "1%";
|
6304 |
+
|
6305 |
+
// Support: Android 4.0 - 4.3 only, Firefox <=3 - 44
|
6306 |
+
reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12;
|
6307 |
+
|
6308 |
+
// Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3
|
6309 |
+
// Some styles come back with percentage values, even though they shouldn't
|
6310 |
+
div.style.right = "60%";
|
6311 |
+
pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36;
|
6312 |
+
|
6313 |
+
// Support: IE 9 - 11 only
|
6314 |
+
// Detect misreporting of content dimensions for box-sizing:border-box elements
|
6315 |
+
boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36;
|
6316 |
+
|
6317 |
+
// Support: IE 9 only
|
6318 |
+
// Detect overflow:scroll screwiness (gh-3699)
|
6319 |
+
div.style.position = "absolute";
|
6320 |
+
scrollboxSizeVal = div.offsetWidth === 36 || "absolute";
|
6321 |
+
|
6322 |
+
documentElement.removeChild( container );
|
6323 |
+
|
6324 |
+
// Nullify the div so it wouldn't be stored in the memory and
|
6325 |
+
// it will also be a sign that checks already performed
|
6326 |
+
div = null;
|
6327 |
+
}
|
6328 |
+
|
6329 |
+
function roundPixelMeasures( measure ) {
|
6330 |
+
return Math.round( parseFloat( measure ) );
|
6331 |
+
}
|
6332 |
+
|
6333 |
+
var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal,
|
6334 |
+
reliableMarginLeftVal,
|
6335 |
+
container = document.createElement( "div" ),
|
6336 |
+
div = document.createElement( "div" );
|
6337 |
+
|
6338 |
+
// Finish early in limited (non-browser) environments
|
6339 |
+
if ( !div.style ) {
|
6340 |
+
return;
|
6341 |
+
}
|
6342 |
+
|
6343 |
+
// Support: IE <=9 - 11 only
|
6344 |
+
// Style of cloned element affects source element cloned (#8908)
|
6345 |
+
div.style.backgroundClip = "content-box";
|
6346 |
+
div.cloneNode( true ).style.backgroundClip = "";
|
6347 |
+
support.clearCloneStyle = div.style.backgroundClip === "content-box";
|
6348 |
+
|
6349 |
+
jQuery.extend( support, {
|
6350 |
+
boxSizingReliable: function() {
|
6351 |
+
computeStyleTests();
|
6352 |
+
return boxSizingReliableVal;
|
6353 |
+
},
|
6354 |
+
pixelBoxStyles: function() {
|
6355 |
+
computeStyleTests();
|
6356 |
+
return pixelBoxStylesVal;
|
6357 |
+
},
|
6358 |
+
pixelPosition: function() {
|
6359 |
+
computeStyleTests();
|
6360 |
+
return pixelPositionVal;
|
6361 |
+
},
|
6362 |
+
reliableMarginLeft: function() {
|
6363 |
+
computeStyleTests();
|
6364 |
+
return reliableMarginLeftVal;
|
6365 |
+
},
|
6366 |
+
scrollboxSize: function() {
|
6367 |
+
computeStyleTests();
|
6368 |
+
return scrollboxSizeVal;
|
6369 |
+
}
|
6370 |
+
} );
|
6371 |
+
} )();
|
6372 |
+
|
6373 |
+
|
6374 |
+
function curCSS( elem, name, computed ) {
|
6375 |
+
var width, minWidth, maxWidth, ret,
|
6376 |
+
|
6377 |
+
// Support: Firefox 51+
|
6378 |
+
// Retrieving style before computed somehow
|
6379 |
+
// fixes an issue with getting wrong values
|
6380 |
+
// on detached elements
|
6381 |
+
style = elem.style;
|
6382 |
+
|
6383 |
+
computed = computed || getStyles( elem );
|
6384 |
+
|
6385 |
+
// getPropertyValue is needed for:
|
6386 |
+
// .css('filter') (IE 9 only, #12537)
|
6387 |
+
// .css('--customProperty) (#3144)
|
6388 |
+
if ( computed ) {
|
6389 |
+
ret = computed.getPropertyValue( name ) || computed[ name ];
|
6390 |
+
|
6391 |
+
if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
|
6392 |
+
ret = jQuery.style( elem, name );
|
6393 |
+
}
|
6394 |
+
|
6395 |
+
// A tribute to the "awesome hack by Dean Edwards"
|
6396 |
+
// Android Browser returns percentage for some values,
|
6397 |
+
// but width seems to be reliably pixels.
|
6398 |
+
// This is against the CSSOM draft spec:
|
6399 |
+
// https://drafts.csswg.org/cssom/#resolved-values
|
6400 |
+
if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) {
|
6401 |
+
|
6402 |
+
// Remember the original values
|
6403 |
+
width = style.width;
|
6404 |
+
minWidth = style.minWidth;
|
6405 |
+
maxWidth = style.maxWidth;
|
6406 |
+
|
6407 |
+
// Put in the new values to get a computed value out
|
6408 |
+
style.minWidth = style.maxWidth = style.width = ret;
|
6409 |
+
ret = computed.width;
|
6410 |
+
|
6411 |
+
// Revert the changed values
|
6412 |
+
style.width = width;
|
6413 |
+
style.minWidth = minWidth;
|
6414 |
+
style.maxWidth = maxWidth;
|
6415 |
+
}
|
6416 |
+
}
|
6417 |
+
|
6418 |
+
return ret !== undefined ?
|
6419 |
+
|
6420 |
+
// Support: IE <=9 - 11 only
|
6421 |
+
// IE returns zIndex value as an integer.
|
6422 |
+
ret + "" :
|
6423 |
+
ret;
|
6424 |
+
}
|
6425 |
+
|
6426 |
+
|
6427 |
+
function addGetHookIf( conditionFn, hookFn ) {
|
6428 |
+
|
6429 |
+
// Define the hook, we'll check on the first run if it's really needed.
|
6430 |
+
return {
|
6431 |
+
get: function() {
|
6432 |
+
if ( conditionFn() ) {
|
6433 |
+
|
6434 |
+
// Hook not needed (or it's not possible to use it due
|
6435 |
+
// to missing dependency), remove it.
|
6436 |
+
delete this.get;
|
6437 |
+
return;
|
6438 |
+
}
|
6439 |
+
|
6440 |
+
// Hook needed; redefine it so that the support test is not executed again.
|
6441 |
+
return ( this.get = hookFn ).apply( this, arguments );
|
6442 |
+
}
|
6443 |
+
};
|
6444 |
+
}
|
6445 |
+
|
6446 |
+
|
6447 |
+
var
|
6448 |
+
|
6449 |
+
// Swappable if display is none or starts with table
|
6450 |
+
// except "table", "table-cell", or "table-caption"
|
6451 |
+
// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
|
6452 |
+
rdisplayswap = /^(none|table(?!-c[ea]).+)/,
|
6453 |
+
rcustomProp = /^--/,
|
6454 |
+
cssShow = { position: "absolute", visibility: "hidden", display: "block" },
|
6455 |
+
cssNormalTransform = {
|
6456 |
+
letterSpacing: "0",
|
6457 |
+
fontWeight: "400"
|
6458 |
+
},
|
6459 |
+
|
6460 |
+
cssPrefixes = [ "Webkit", "Moz", "ms" ],
|
6461 |
+
emptyStyle = document.createElement( "div" ).style;
|
6462 |
+
|
6463 |
+
// Return a css property mapped to a potentially vendor prefixed property
|
6464 |
+
function vendorPropName( name ) {
|
6465 |
+
|
6466 |
+
// Shortcut for names that are not vendor prefixed
|
6467 |
+
if ( name in emptyStyle ) {
|
6468 |
+
return name;
|
6469 |
+
}
|
6470 |
+
|
6471 |
+
// Check for vendor prefixed names
|
6472 |
+
var capName = name[ 0 ].toUpperCase() + name.slice( 1 ),
|
6473 |
+
i = cssPrefixes.length;
|
6474 |
+
|
6475 |
+
while ( i-- ) {
|
6476 |
+
name = cssPrefixes[ i ] + capName;
|
6477 |
+
if ( name in emptyStyle ) {
|
6478 |
+
return name;
|
6479 |
+
}
|
6480 |
+
}
|
6481 |
+
}
|
6482 |
+
|
6483 |
+
// Return a property mapped along what jQuery.cssProps suggests or to
|
6484 |
+
// a vendor prefixed property.
|
6485 |
+
function finalPropName( name ) {
|
6486 |
+
var ret = jQuery.cssProps[ name ];
|
6487 |
+
if ( !ret ) {
|
6488 |
+
ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name;
|
6489 |
+
}
|
6490 |
+
return ret;
|
6491 |
+
}
|
6492 |
+
|
6493 |
+
function setPositiveNumber( elem, value, subtract ) {
|
6494 |
+
|
6495 |
+
// Any relative (+/-) values have already been
|
6496 |
+
// normalized at this point
|
6497 |
+
var matches = rcssNum.exec( value );
|
6498 |
+
return matches ?
|
6499 |
+
|
6500 |
+
// Guard against undefined "subtract", e.g., when used as in cssHooks
|
6501 |
+
Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) :
|
6502 |
+
value;
|
6503 |
+
}
|
6504 |
+
|
6505 |
+
function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) {
|
6506 |
+
var i = dimension === "width" ? 1 : 0,
|
6507 |
+
extra = 0,
|
6508 |
+
delta = 0;
|
6509 |
+
|
6510 |
+
// Adjustment may not be necessary
|
6511 |
+
if ( box === ( isBorderBox ? "border" : "content" ) ) {
|
6512 |
+
return 0;
|
6513 |
+
}
|
6514 |
+
|
6515 |
+
for ( ; i < 4; i += 2 ) {
|
6516 |
+
|
6517 |
+
// Both box models exclude margin
|
6518 |
+
if ( box === "margin" ) {
|
6519 |
+
delta += jQuery.css( elem, box + cssExpand[ i ], true, styles );
|
6520 |
+
}
|
6521 |
+
|
6522 |
+
// If we get here with a content-box, we're seeking "padding" or "border" or "margin"
|
6523 |
+
if ( !isBorderBox ) {
|
6524 |
+
|
6525 |
+
// Add padding
|
6526 |
+
delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
|
6527 |
+
|
6528 |
+
// For "border" or "margin", add border
|
6529 |
+
if ( box !== "padding" ) {
|
6530 |
+
delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
|
6531 |
+
|
6532 |
+
// But still keep track of it otherwise
|
6533 |
+
} else {
|
6534 |
+
extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
|
6535 |
+
}
|
6536 |
+
|
6537 |
+
// If we get here with a border-box (content + padding + border), we're seeking "content" or
|
6538 |
+
// "padding" or "margin"
|
6539 |
+
} else {
|
6540 |
+
|
6541 |
+
// For "content", subtract padding
|
6542 |
+
if ( box === "content" ) {
|
6543 |
+
delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
|
6544 |
+
}
|
6545 |
+
|
6546 |
+
// For "content" or "padding", subtract border
|
6547 |
+
if ( box !== "margin" ) {
|
6548 |
+
delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
|
6549 |
+
}
|
6550 |
+
}
|
6551 |
+
}
|
6552 |
+
|
6553 |
+
// Account for positive content-box scroll gutter when requested by providing computedVal
|
6554 |
+
if ( !isBorderBox && computedVal >= 0 ) {
|
6555 |
+
|
6556 |
+
// offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border
|
6557 |
+
// Assuming integer scroll gutter, subtract the rest and round down
|
6558 |
+
delta += Math.max( 0, Math.ceil(
|
6559 |
+
elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
|
6560 |
+
computedVal -
|
6561 |
+
delta -
|
6562 |
+
extra -
|
6563 |
+
0.5
|
6564 |
+
) );
|
6565 |
+
}
|
6566 |
+
|
6567 |
+
return delta;
|
6568 |
+
}
|
6569 |
+
|
6570 |
+
function getWidthOrHeight( elem, dimension, extra ) {
|
6571 |
+
|
6572 |
+
// Start with computed style
|
6573 |
+
var styles = getStyles( elem ),
|
6574 |
+
val = curCSS( elem, dimension, styles ),
|
6575 |
+
isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
|
6576 |
+
valueIsBorderBox = isBorderBox;
|
6577 |
+
|
6578 |
+
// Support: Firefox <=54
|
6579 |
+
// Return a confounding non-pixel value or feign ignorance, as appropriate.
|
6580 |
+
if ( rnumnonpx.test( val ) ) {
|
6581 |
+
if ( !extra ) {
|
6582 |
+
return val;
|
6583 |
+
}
|
6584 |
+
val = "auto";
|
6585 |
+
}
|
6586 |
+
|
6587 |
+
// Check for style in case a browser which returns unreliable values
|
6588 |
+
// for getComputedStyle silently falls back to the reliable elem.style
|
6589 |
+
valueIsBorderBox = valueIsBorderBox &&
|
6590 |
+
( support.boxSizingReliable() || val === elem.style[ dimension ] );
|
6591 |
+
|
6592 |
+
// Fall back to offsetWidth/offsetHeight when value is "auto"
|
6593 |
+
// This happens for inline elements with no explicit setting (gh-3571)
|
6594 |
+
// Support: Android <=4.1 - 4.3 only
|
6595 |
+
// Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)
|
6596 |
+
if ( val === "auto" ||
|
6597 |
+
!parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) {
|
6598 |
+
|
6599 |
+
val = elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ];
|
6600 |
+
|
6601 |
+
// offsetWidth/offsetHeight provide border-box values
|
6602 |
+
valueIsBorderBox = true;
|
6603 |
+
}
|
6604 |
+
|
6605 |
+
// Normalize "" and auto
|
6606 |
+
val = parseFloat( val ) || 0;
|
6607 |
+
|
6608 |
+
// Adjust for the element's box model
|
6609 |
+
return ( val +
|
6610 |
+
boxModelAdjustment(
|
6611 |
+
elem,
|
6612 |
+
dimension,
|
6613 |
+
extra || ( isBorderBox ? "border" : "content" ),
|
6614 |
+
valueIsBorderBox,
|
6615 |
+
styles,
|
6616 |
+
|
6617 |
+
// Provide the current computed size to request scroll gutter calculation (gh-3589)
|
6618 |
+
val
|
6619 |
+
)
|
6620 |
+
) + "px";
|
6621 |
+
}
|
6622 |
+
|
6623 |
+
jQuery.extend( {
|
6624 |
+
|
6625 |
+
// Add in style property hooks for overriding the default
|
6626 |
+
// behavior of getting and setting a style property
|
6627 |
+
cssHooks: {
|
6628 |
+
opacity: {
|
6629 |
+
get: function( elem, computed ) {
|
6630 |
+
if ( computed ) {
|
6631 |
+
|
6632 |
+
// We should always get a number back from opacity
|
6633 |
+
var ret = curCSS( elem, "opacity" );
|
6634 |
+
return ret === "" ? "1" : ret;
|
6635 |
+
}
|
6636 |
+
}
|
6637 |
+
}
|
6638 |
+
},
|
6639 |
+
|
6640 |
+
// Don't automatically add "px" to these possibly-unitless properties
|
6641 |
+
cssNumber: {
|
6642 |
+
"animationIterationCount": true,
|
6643 |
+
"columnCount": true,
|
6644 |
+
"fillOpacity": true,
|
6645 |
+
"flexGrow": true,
|
6646 |
+
"flexShrink": true,
|
6647 |
+
"fontWeight": true,
|
6648 |
+
"lineHeight": true,
|
6649 |
+
"opacity": true,
|
6650 |
+
"order": true,
|
6651 |
+
"orphans": true,
|
6652 |
+
"widows": true,
|
6653 |
+
"zIndex": true,
|
6654 |
+
"zoom": true
|
6655 |
+
},
|
6656 |
+
|
6657 |
+
// Add in properties whose names you wish to fix before
|
6658 |
+
// setting or getting the value
|
6659 |
+
cssProps: {},
|
6660 |
+
|
6661 |
+
// Get and set the style property on a DOM Node
|
6662 |
+
style: function( elem, name, value, extra ) {
|
6663 |
+
|
6664 |
+
// Don't set styles on text and comment nodes
|
6665 |
+
if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
|
6666 |
+
return;
|
6667 |
+
}
|
6668 |
+
|
6669 |
+
// Make sure that we're working with the right name
|
6670 |
+
var ret, type, hooks,
|
6671 |
+
origName = camelCase( name ),
|
6672 |
+
isCustomProp = rcustomProp.test( name ),
|
6673 |
+
style = elem.style;
|
6674 |
+
|
6675 |
+
// Make sure that we're working with the right name. We don't
|
6676 |
+
// want to query the value if it is a CSS custom property
|
6677 |
+
// since they are user-defined.
|
6678 |
+
if ( !isCustomProp ) {
|
6679 |
+
name = finalPropName( origName );
|
6680 |
+
}
|
6681 |
+
|
6682 |
+
// Gets hook for the prefixed version, then unprefixed version
|
6683 |
+
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
|
6684 |
+
|
6685 |
+
// Check if we're setting a value
|
6686 |
+
if ( value !== undefined ) {
|
6687 |
+
type = typeof value;
|
6688 |
+
|
6689 |
+
// Convert "+=" or "-=" to relative numbers (#7345)
|
6690 |
+
if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {
|
6691 |
+
value = adjustCSS( elem, name, ret );
|
6692 |
+
|
6693 |
+
// Fixes bug #9237
|
6694 |
+
type = "number";
|
6695 |
+
}
|
6696 |
+
|
6697 |
+
// Make sure that null and NaN values aren't set (#7116)
|
6698 |
+
if ( value == null || value !== value ) {
|
6699 |
+
return;
|
6700 |
+
}
|
6701 |
+
|
6702 |
+
// If a number was passed in, add the unit (except for certain CSS properties)
|
6703 |
+
if ( type === "number" ) {
|
6704 |
+
value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" );
|
6705 |
+
}
|
6706 |
+
|
6707 |
+
// background-* props affect original clone's values
|
6708 |
+
if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
|
6709 |
+
style[ name ] = "inherit";
|
6710 |
+
}
|
6711 |
+
|
6712 |
+
// If a hook was provided, use that value, otherwise just set the specified value
|
6713 |
+
if ( !hooks || !( "set" in hooks ) ||
|
6714 |
+
( value = hooks.set( elem, value, extra ) ) !== undefined ) {
|
6715 |
+
|
6716 |
+
if ( isCustomProp ) {
|
6717 |
+
style.setProperty( name, value );
|
6718 |
+
} else {
|
6719 |
+
style[ name ] = value;
|
6720 |
+
}
|
6721 |
+
}
|
6722 |
+
|
6723 |
+
} else {
|
6724 |
+
|
6725 |
+
// If a hook was provided get the non-computed value from there
|
6726 |
+
if ( hooks && "get" in hooks &&
|
6727 |
+
( ret = hooks.get( elem, false, extra ) ) !== undefined ) {
|
6728 |
+
|
6729 |
+
return ret;
|
6730 |
+
}
|
6731 |
+
|
6732 |
+
// Otherwise just get the value from the style object
|
6733 |
+
return style[ name ];
|
6734 |
+
}
|
6735 |
+
},
|
6736 |
+
|
6737 |
+
css: function( elem, name, extra, styles ) {
|
6738 |
+
var val, num, hooks,
|
6739 |
+
origName = camelCase( name ),
|
6740 |
+
isCustomProp = rcustomProp.test( name );
|
6741 |
+
|
6742 |
+
// Make sure that we're working with the right name. We don't
|
6743 |
+
// want to modify the value if it is a CSS custom property
|
6744 |
+
// since they are user-defined.
|
6745 |
+
if ( !isCustomProp ) {
|
6746 |
+
name = finalPropName( origName );
|
6747 |
+
}
|
6748 |
+
|
6749 |
+
// Try prefixed name followed by the unprefixed name
|
6750 |
+
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
|
6751 |
+
|
6752 |
+
// If a hook was provided get the computed value from there
|
6753 |
+
if ( hooks && "get" in hooks ) {
|
6754 |
+
val = hooks.get( elem, true, extra );
|
6755 |
+
}
|
6756 |
+
|
6757 |
+
// Otherwise, if a way to get the computed value exists, use that
|
6758 |
+
if ( val === undefined ) {
|
6759 |
+
val = curCSS( elem, name, styles );
|
6760 |
+
}
|
6761 |
+
|
6762 |
+
// Convert "normal" to computed value
|
6763 |
+
if ( val === "normal" && name in cssNormalTransform ) {
|
6764 |
+
val = cssNormalTransform[ name ];
|
6765 |
+
}
|
6766 |
+
|
6767 |
+
// Make numeric if forced or a qualifier was provided and val looks numeric
|
6768 |
+
if ( extra === "" || extra ) {
|
6769 |
+
num = parseFloat( val );
|
6770 |
+
return extra === true || isFinite( num ) ? num || 0 : val;
|
6771 |
+
}
|
6772 |
+
|
6773 |
+
return val;
|
6774 |
+
}
|
6775 |
+
} );
|
6776 |
+
|
6777 |
+
jQuery.each( [ "height", "width" ], function( i, dimension ) {
|
6778 |
+
jQuery.cssHooks[ dimension ] = {
|
6779 |
+
get: function( elem, computed, extra ) {
|
6780 |
+
if ( computed ) {
|
6781 |
+
|
6782 |
+
// Certain elements can have dimension info if we invisibly show them
|
6783 |
+
// but it must have a current display style that would benefit
|
6784 |
+
return rdisplayswap.test( jQuery.css( elem, "display" ) ) &&
|
6785 |
+
|
6786 |
+
// Support: Safari 8+
|
6787 |
+
// Table columns in Safari have non-zero offsetWidth & zero
|
6788 |
+
// getBoundingClientRect().width unless display is changed.
|
6789 |
+
// Support: IE <=11 only
|
6790 |
+
// Running getBoundingClientRect on a disconnected node
|
6791 |
+
// in IE throws an error.
|
6792 |
+
( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?
|
6793 |
+
swap( elem, cssShow, function() {
|
6794 |
+
return getWidthOrHeight( elem, dimension, extra );
|
6795 |
+
} ) :
|
6796 |
+
getWidthOrHeight( elem, dimension, extra );
|
6797 |
+
}
|
6798 |
+
},
|
6799 |
+
|
6800 |
+
set: function( elem, value, extra ) {
|
6801 |
+
var matches,
|
6802 |
+
styles = getStyles( elem ),
|
6803 |
+
isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
|
6804 |
+
subtract = extra && boxModelAdjustment(
|
6805 |
+
elem,
|
6806 |
+
dimension,
|
6807 |
+
extra,
|
6808 |
+
isBorderBox,
|
6809 |
+
styles
|
6810 |
+
);
|
6811 |
+
|
6812 |
+
// Account for unreliable border-box dimensions by comparing offset* to computed and
|
6813 |
+
// faking a content-box to get border and padding (gh-3699)
|
6814 |
+
if ( isBorderBox && support.scrollboxSize() === styles.position ) {
|
6815 |
+
subtract -= Math.ceil(
|
6816 |
+
elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
|
6817 |
+
parseFloat( styles[ dimension ] ) -
|
6818 |
+
boxModelAdjustment( elem, dimension, "border", false, styles ) -
|
6819 |
+
0.5
|
6820 |
+
);
|
6821 |
+
}
|
6822 |
+
|
6823 |
+
// Convert to pixels if value adjustment is needed
|
6824 |
+
if ( subtract && ( matches = rcssNum.exec( value ) ) &&
|
6825 |
+
( matches[ 3 ] || "px" ) !== "px" ) {
|
6826 |
+
|
6827 |
+
elem.style[ dimension ] = value;
|
6828 |
+
value = jQuery.css( elem, dimension );
|
6829 |
+
}
|
6830 |
+
|
6831 |
+
return setPositiveNumber( elem, value, subtract );
|
6832 |
+
}
|
6833 |
+
};
|
6834 |
+
} );
|
6835 |
+
|
6836 |
+
jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,
|
6837 |
+
function( elem, computed ) {
|
6838 |
+
if ( computed ) {
|
6839 |
+
return ( parseFloat( curCSS( elem, "marginLeft" ) ) ||
|
6840 |
+
elem.getBoundingClientRect().left -
|
6841 |
+
swap( elem, { marginLeft: 0 }, function() {
|
6842 |
+
return elem.getBoundingClientRect().left;
|
6843 |
+
} )
|
6844 |
+
) + "px";
|
6845 |
+
}
|
6846 |
+
}
|
6847 |
+
);
|
6848 |
+
|
6849 |
+
// These hooks are used by animate to expand properties
|
6850 |
+
jQuery.each( {
|
6851 |
+
margin: "",
|
6852 |
+
padding: "",
|
6853 |
+
border: "Width"
|
6854 |
+
}, function( prefix, suffix ) {
|
6855 |
+
jQuery.cssHooks[ prefix + suffix ] = {
|
6856 |
+
expand: function( value ) {
|
6857 |
+
var i = 0,
|
6858 |
+
expanded = {},
|
6859 |
+
|
6860 |
+
// Assumes a single number if not a string
|
6861 |
+
parts = typeof value === "string" ? value.split( " " ) : [ value ];
|
6862 |
+
|
6863 |
+
for ( ; i < 4; i++ ) {
|
6864 |
+
expanded[ prefix + cssExpand[ i ] + suffix ] =
|
6865 |
+
parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
|
6866 |
+
}
|
6867 |
+
|
6868 |
+
return expanded;
|
6869 |
+
}
|
6870 |
+
};
|
6871 |
+
|
6872 |
+
if ( prefix !== "margin" ) {
|
6873 |
+
jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
|
6874 |
+
}
|
6875 |
+
} );
|
6876 |
+
|
6877 |
+
jQuery.fn.extend( {
|
6878 |
+
css: function( name, value ) {
|
6879 |
+
return access( this, function( elem, name, value ) {
|
6880 |
+
var styles, len,
|
6881 |
+
map = {},
|
6882 |
+
i = 0;
|
6883 |
+
|
6884 |
+
if ( Array.isArray( name ) ) {
|
6885 |
+
styles = getStyles( elem );
|
6886 |
+
len = name.length;
|
6887 |
+
|
6888 |
+
for ( ; i < len; i++ ) {
|
6889 |
+
map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
|
6890 |
+
}
|
6891 |
+
|
6892 |
+
return map;
|
6893 |
+
}
|
6894 |
+
|
6895 |
+
return value !== undefined ?
|
6896 |
+
jQuery.style( elem, name, value ) :
|
6897 |
+
jQuery.css( elem, name );
|
6898 |
+
}, name, value, arguments.length > 1 );
|
6899 |
+
}
|
6900 |
+
} );
|
6901 |
+
|
6902 |
+
|
6903 |
+
function Tween( elem, options, prop, end, easing ) {
|
6904 |
+
return new Tween.prototype.init( elem, options, prop, end, easing );
|
6905 |
+
}
|
6906 |
+
jQuery.Tween = Tween;
|
6907 |
+
|
6908 |
+
Tween.prototype = {
|
6909 |
+
constructor: Tween,
|
6910 |
+
init: function( elem, options, prop, end, easing, unit ) {
|
6911 |
+
this.elem = elem;
|
6912 |
+
this.prop = prop;
|
6913 |
+
this.easing = easing || jQuery.easing._default;
|
6914 |
+
this.options = options;
|
6915 |
+
this.start = this.now = this.cur();
|
6916 |
+
this.end = end;
|
6917 |
+
this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
|
6918 |
+
},
|
6919 |
+
cur: function() {
|
6920 |
+
var hooks = Tween.propHooks[ this.prop ];
|
6921 |
+
|
6922 |
+
return hooks && hooks.get ?
|
6923 |
+
hooks.get( this ) :
|
6924 |
+
Tween.propHooks._default.get( this );
|
6925 |
+
},
|
6926 |
+
run: function( percent ) {
|
6927 |
+
var eased,
|
6928 |
+
hooks = Tween.propHooks[ this.prop ];
|
6929 |
+
|
6930 |
+
if ( this.options.duration ) {
|
6931 |
+
this.pos = eased = jQuery.easing[ this.easing ](
|
6932 |
+
percent, this.options.duration * percent, 0, 1, this.options.duration
|
6933 |
+
);
|
6934 |
+
} else {
|
6935 |
+
this.pos = eased = percent;
|
6936 |
+
}
|
6937 |
+
this.now = ( this.end - this.start ) * eased + this.start;
|
6938 |
+
|
6939 |
+
if ( this.options.step ) {
|
6940 |
+
this.options.step.call( this.elem, this.now, this );
|
6941 |
+
}
|
6942 |
+
|
6943 |
+
if ( hooks && hooks.set ) {
|
6944 |
+
hooks.set( this );
|
6945 |
+
} else {
|
6946 |
+
Tween.propHooks._default.set( this );
|
6947 |
+
}
|
6948 |
+
return this;
|
6949 |
+
}
|
6950 |
+
};
|
6951 |
+
|
6952 |
+
Tween.prototype.init.prototype = Tween.prototype;
|
6953 |
+
|
6954 |
+
Tween.propHooks = {
|
6955 |
+
_default: {
|
6956 |
+
get: function( tween ) {
|
6957 |
+
var result;
|
6958 |
+
|
6959 |
+
// Use a property on the element directly when it is not a DOM element,
|
6960 |
+
// or when there is no matching style property that exists.
|
6961 |
+
if ( tween.elem.nodeType !== 1 ||
|
6962 |
+
tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {
|
6963 |
+
return tween.elem[ tween.prop ];
|
6964 |
+
}
|
6965 |
+
|
6966 |
+
// Passing an empty string as a 3rd parameter to .css will automatically
|
6967 |
+
// attempt a parseFloat and fallback to a string if the parse fails.
|
6968 |
+
// Simple values such as "10px" are parsed to Float;
|
6969 |
+
// complex values such as "rotate(1rad)" are returned as-is.
|
6970 |
+
result = jQuery.css( tween.elem, tween.prop, "" );
|
6971 |
+
|
6972 |
+
// Empty strings, null, undefined and "auto" are converted to 0.
|
6973 |
+
return !result || result === "auto" ? 0 : result;
|
6974 |
+
},
|
6975 |
+
set: function( tween ) {
|
6976 |
+
|
6977 |
+
// Use step hook for back compat.
|
6978 |
+
// Use cssHook if its there.
|
6979 |
+
// Use .style if available and use plain properties where available.
|
6980 |
+
if ( jQuery.fx.step[ tween.prop ] ) {
|
6981 |
+
jQuery.fx.step[ tween.prop ]( tween );
|
6982 |
+
} else if ( tween.elem.nodeType === 1 &&
|
6983 |
+
( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null ||
|
6984 |
+
jQuery.cssHooks[ tween.prop ] ) ) {
|
6985 |
+
jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
|
6986 |
+
} else {
|
6987 |
+
tween.elem[ tween.prop ] = tween.now;
|
6988 |
+
}
|
6989 |
+
}
|
6990 |
+
}
|
6991 |
+
};
|
6992 |
+
|
6993 |
+
// Support: IE <=9 only
|
6994 |
+
// Panic based approach to setting things on disconnected nodes
|
6995 |
+
Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
|
6996 |
+
set: function( tween ) {
|
6997 |
+
if ( tween.elem.nodeType && tween.elem.parentNode ) {
|
6998 |
+
tween.elem[ tween.prop ] = tween.now;
|
6999 |
+
}
|
7000 |
+
}
|
7001 |
+
};
|
7002 |
+
|
7003 |
+
jQuery.easing = {
|
7004 |
+
linear: function( p ) {
|
7005 |
+
return p;
|
7006 |
+
},
|
7007 |
+
swing: function( p ) {
|
7008 |
+
return 0.5 - Math.cos( p * Math.PI ) / 2;
|
7009 |
+
},
|
7010 |
+
_default: "swing"
|
7011 |
+
};
|
7012 |
+
|
7013 |
+
jQuery.fx = Tween.prototype.init;
|
7014 |
+
|
7015 |
+
// Back compat <1.8 extension point
|
7016 |
+
jQuery.fx.step = {};
|
7017 |
+
|
7018 |
+
|
7019 |
+
|
7020 |
+
|
7021 |
+
var
|
7022 |
+
fxNow, inProgress,
|
7023 |
+
rfxtypes = /^(?:toggle|show|hide)$/,
|
7024 |
+
rrun = /queueHooks$/;
|
7025 |
+
|
7026 |
+
function schedule() {
|
7027 |
+
if ( inProgress ) {
|
7028 |
+
if ( document.hidden === false && window.requestAnimationFrame ) {
|
7029 |
+
window.requestAnimationFrame( schedule );
|
7030 |
+
} else {
|
7031 |
+
window.setTimeout( schedule, jQuery.fx.interval );
|
7032 |
+
}
|
7033 |
+
|
7034 |
+
jQuery.fx.tick();
|
7035 |
+
}
|
7036 |
+
}
|
7037 |
+
|
7038 |
+
// Animations created synchronously will run synchronously
|
7039 |
+
function createFxNow() {
|
7040 |
+
window.setTimeout( function() {
|
7041 |
+
fxNow = undefined;
|
7042 |
+
} );
|
7043 |
+
return ( fxNow = Date.now() );
|
7044 |
+
}
|
7045 |
+
|
7046 |
+
// Generate parameters to create a standard animation
|
7047 |
+
function genFx( type, includeWidth ) {
|
7048 |
+
var which,
|
7049 |
+
i = 0,
|
7050 |
+
attrs = { height: type };
|
7051 |
+
|
7052 |
+
// If we include width, step value is 1 to do all cssExpand values,
|
7053 |
+
// otherwise step value is 2 to skip over Left and Right
|
7054 |
+
includeWidth = includeWidth ? 1 : 0;
|
7055 |
+
for ( ; i < 4; i += 2 - includeWidth ) {
|
7056 |
+
which = cssExpand[ i ];
|
7057 |
+
attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
|
7058 |
+
}
|
7059 |
+
|
7060 |
+
if ( includeWidth ) {
|
7061 |
+
attrs.opacity = attrs.width = type;
|
7062 |
+
}
|
7063 |
+
|
7064 |
+
return attrs;
|
7065 |
+
}
|
7066 |
+
|
7067 |
+
function createTween( value, prop, animation ) {
|
7068 |
+
var tween,
|
7069 |
+
collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ),
|
7070 |
+
index = 0,
|
7071 |
+
length = collection.length;
|
7072 |
+
for ( ; index < length; index++ ) {
|
7073 |
+
if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {
|
7074 |
+
|
7075 |
+
// We're done with this property
|
7076 |
+
return tween;
|
7077 |
+
}
|
7078 |
+
}
|
7079 |
+
}
|
7080 |
+
|
7081 |
+
function defaultPrefilter( elem, props, opts ) {
|
7082 |
+
var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,
|
7083 |
+
isBox = "width" in props || "height" in props,
|
7084 |
+
anim = this,
|
7085 |
+
orig = {},
|
7086 |
+
style = elem.style,
|
7087 |
+
hidden = elem.nodeType && isHiddenWithinTree( elem ),
|
7088 |
+
dataShow = dataPriv.get( elem, "fxshow" );
|
7089 |
+
|
7090 |
+
// Queue-skipping animations hijack the fx hooks
|
7091 |
+
if ( !opts.queue ) {
|
7092 |
+
hooks = jQuery._queueHooks( elem, "fx" );
|
7093 |
+
if ( hooks.unqueued == null ) {
|
7094 |
+
hooks.unqueued = 0;
|
7095 |
+
oldfire = hooks.empty.fire;
|
7096 |
+
hooks.empty.fire = function() {
|
7097 |
+
if ( !hooks.unqueued ) {
|
7098 |
+
oldfire();
|
7099 |
+
}
|
7100 |
+
};
|
7101 |
+
}
|
7102 |
+
hooks.unqueued++;
|
7103 |
+
|
7104 |
+
anim.always( function() {
|
7105 |
+
|
7106 |
+
// Ensure the complete handler is called before this completes
|
7107 |
+
anim.always( function() {
|
7108 |
+
hooks.unqueued--;
|
7109 |
+
if ( !jQuery.queue( elem, "fx" ).length ) {
|
7110 |
+
hooks.empty.fire();
|
7111 |
+
}
|
7112 |
+
} );
|
7113 |
+
} );
|
7114 |
+
}
|
7115 |
+
|
7116 |
+
// Detect show/hide animations
|
7117 |
+
for ( prop in props ) {
|
7118 |
+
value = props[ prop ];
|
7119 |
+
if ( rfxtypes.test( value ) ) {
|
7120 |
+
delete props[ prop ];
|
7121 |
+
toggle = toggle || value === "toggle";
|
7122 |
+
if ( value === ( hidden ? "hide" : "show" ) ) {
|
7123 |
+
|
7124 |
+
// Pretend to be hidden if this is a "show" and
|
7125 |
+
// there is still data from a stopped show/hide
|
7126 |
+
if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
|
7127 |
+
hidden = true;
|
7128 |
+
|
7129 |
+
// Ignore all other no-op show/hide data
|
7130 |
+
} else {
|
7131 |
+
continue;
|
7132 |
+
}
|
7133 |
+
}
|
7134 |
+
orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
|
7135 |
+
}
|
7136 |
+
}
|
7137 |
+
|
7138 |
+
// Bail out if this is a no-op like .hide().hide()
|
7139 |
+
propTween = !jQuery.isEmptyObject( props );
|
7140 |
+
if ( !propTween && jQuery.isEmptyObject( orig ) ) {
|
7141 |
+
return;
|
7142 |
+
}
|
7143 |
+
|
7144 |
+
// Restrict "overflow" and "display" styles during box animations
|
7145 |
+
if ( isBox && elem.nodeType === 1 ) {
|
7146 |
+
|
7147 |
+
// Support: IE <=9 - 11, Edge 12 - 15
|
7148 |
+
// Record all 3 overflow attributes because IE does not infer the shorthand
|
7149 |
+
// from identically-valued overflowX and overflowY and Edge just mirrors
|
7150 |
+
// the overflowX value there.
|
7151 |
+
opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
|
7152 |
+
|
7153 |
+
// Identify a display type, preferring old show/hide data over the CSS cascade
|
7154 |
+
restoreDisplay = dataShow && dataShow.display;
|
7155 |
+
if ( restoreDisplay == null ) {
|
7156 |
+
restoreDisplay = dataPriv.get( elem, "display" );
|
7157 |
+
}
|
7158 |
+
display = jQuery.css( elem, "display" );
|
7159 |
+
if ( display === "none" ) {
|
7160 |
+
if ( restoreDisplay ) {
|
7161 |
+
display = restoreDisplay;
|
7162 |
+
} else {
|
7163 |
+
|
7164 |
+
// Get nonempty value(s) by temporarily forcing visibility
|
7165 |
+
showHide( [ elem ], true );
|
7166 |
+
restoreDisplay = elem.style.display || restoreDisplay;
|
7167 |
+
display = jQuery.css( elem, "display" );
|
7168 |
+
showHide( [ elem ] );
|
7169 |
+
}
|
7170 |
+
}
|
7171 |
+
|
7172 |
+
// Animate inline elements as inline-block
|
7173 |
+
if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) {
|
7174 |
+
if ( jQuery.css( elem, "float" ) === "none" ) {
|
7175 |
+
|
7176 |
+
// Restore the original display value at the end of pure show/hide animations
|
7177 |
+
if ( !propTween ) {
|
7178 |
+
anim.done( function() {
|
7179 |
+
style.display = restoreDisplay;
|
7180 |
+
} );
|
7181 |
+
if ( restoreDisplay == null ) {
|
7182 |
+
display = style.display;
|
7183 |
+
restoreDisplay = display === "none" ? "" : display;
|
7184 |
+
}
|
7185 |
+
}
|
7186 |
+
style.display = "inline-block";
|
7187 |
+
}
|
7188 |
+
}
|
7189 |
+
}
|
7190 |
+
|
7191 |
+
if ( opts.overflow ) {
|
7192 |
+
style.overflow = "hidden";
|
7193 |
+
anim.always( function() {
|
7194 |
+
style.overflow = opts.overflow[ 0 ];
|
7195 |
+
style.overflowX = opts.overflow[ 1 ];
|
7196 |
+
style.overflowY = opts.overflow[ 2 ];
|
7197 |
+
} );
|
7198 |
+
}
|
7199 |
+
|
7200 |
+
// Implement show/hide animations
|
7201 |
+
propTween = false;
|
7202 |
+
for ( prop in orig ) {
|
7203 |
+
|
7204 |
+
// General show/hide setup for this element animation
|
7205 |
+
if ( !propTween ) {
|
7206 |
+
if ( dataShow ) {
|
7207 |
+
if ( "hidden" in dataShow ) {
|
7208 |
+
hidden = dataShow.hidden;
|
7209 |
+
}
|
7210 |
+
} else {
|
7211 |
+
dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } );
|
7212 |
+
}
|
7213 |
+
|
7214 |
+
// Store hidden/visible for toggle so `.stop().toggle()` "reverses"
|
7215 |
+
if ( toggle ) {
|
7216 |
+
dataShow.hidden = !hidden;
|
7217 |
+
}
|
7218 |
+
|
7219 |
+
// Show elements before animating them
|
7220 |
+
if ( hidden ) {
|
7221 |
+
showHide( [ elem ], true );
|
7222 |
+
}
|
7223 |
+
|
7224 |
+
/* eslint-disable no-loop-func */
|
7225 |
+
|
7226 |
+
anim.done( function() {
|
7227 |
+
|
7228 |
+
/* eslint-enable no-loop-func */
|
7229 |
+
|
7230 |
+
// The final step of a "hide" animation is actually hiding the element
|
7231 |
+
if ( !hidden ) {
|
7232 |
+
showHide( [ elem ] );
|
7233 |
+
}
|
7234 |
+
dataPriv.remove( elem, "fxshow" );
|
7235 |
+
for ( prop in orig ) {
|
7236 |
+
jQuery.style( elem, prop, orig[ prop ] );
|
7237 |
+
}
|
7238 |
+
} );
|
7239 |
+
}
|
7240 |
+
|
7241 |
+
// Per-property setup
|
7242 |
+
propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
|
7243 |
+
if ( !( prop in dataShow ) ) {
|
7244 |
+
dataShow[ prop ] = propTween.start;
|
7245 |
+
if ( hidden ) {
|
7246 |
+
propTween.end = propTween.start;
|
7247 |
+
propTween.start = 0;
|
7248 |
+
}
|
7249 |
+
}
|
7250 |
+
}
|
7251 |
+
}
|
7252 |
+
|
7253 |
+
function propFilter( props, specialEasing ) {
|
7254 |
+
var index, name, easing, value, hooks;
|
7255 |
+
|
7256 |
+
// camelCase, specialEasing and expand cssHook pass
|
7257 |
+
for ( index in props ) {
|
7258 |
+
name = camelCase( index );
|
7259 |
+
easing = specialEasing[ name ];
|
7260 |
+
value = props[ index ];
|
7261 |
+
if ( Array.isArray( value ) ) {
|
7262 |
+
easing = value[ 1 ];
|
7263 |
+
value = props[ index ] = value[ 0 ];
|
7264 |
+
}
|
7265 |
+
|
7266 |
+
if ( index !== name ) {
|
7267 |
+
props[ name ] = value;
|
7268 |
+
delete props[ index ];
|
7269 |
+
}
|
7270 |
+
|
7271 |
+
hooks = jQuery.cssHooks[ name ];
|
7272 |
+
if ( hooks && "expand" in hooks ) {
|
7273 |
+
value = hooks.expand( value );
|
7274 |
+
delete props[ name ];
|
7275 |
+
|
7276 |
+
// Not quite $.extend, this won't overwrite existing keys.
|
7277 |
+
// Reusing 'index' because we have the correct "name"
|
7278 |
+
for ( index in value ) {
|
7279 |
+
if ( !( index in props ) ) {
|
7280 |
+
props[ index ] = value[ index ];
|
7281 |
+
specialEasing[ index ] = easing;
|
7282 |
+
}
|
7283 |
+
}
|
7284 |
+
} else {
|
7285 |
+
specialEasing[ name ] = easing;
|
7286 |
+
}
|
7287 |
+
}
|
7288 |
+
}
|
7289 |
+
|
7290 |
+
function Animation( elem, properties, options ) {
|
7291 |
+
var result,
|
7292 |
+
stopped,
|
7293 |
+
index = 0,
|
7294 |
+
length = Animation.prefilters.length,
|
7295 |
+
deferred = jQuery.Deferred().always( function() {
|
7296 |
+
|
7297 |
+
// Don't match elem in the :animated selector
|
7298 |
+
delete tick.elem;
|
7299 |
+
} ),
|
7300 |
+
tick = function() {
|
7301 |
+
if ( stopped ) {
|
7302 |
+
return false;
|
7303 |
+
}
|
7304 |
+
var currentTime = fxNow || createFxNow(),
|
7305 |
+
remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
|
7306 |
+
|
7307 |
+
// Support: Android 2.3 only
|
7308 |
+
// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)
|
7309 |
+
temp = remaining / animation.duration || 0,
|
7310 |
+
percent = 1 - temp,
|
7311 |
+
index = 0,
|
7312 |
+
length = animation.tweens.length;
|
7313 |
+
|
7314 |
+
for ( ; index < length; index++ ) {
|
7315 |
+
animation.tweens[ index ].run( percent );
|
7316 |
+
}
|
7317 |
+
|
7318 |
+
deferred.notifyWith( elem, [ animation, percent, remaining ] );
|
7319 |
+
|
7320 |
+
// If there's more to do, yield
|
7321 |
+
if ( percent < 1 && length ) {
|
7322 |
+
return remaining;
|
7323 |
+
}
|
7324 |
+
|
7325 |
+
// If this was an empty animation, synthesize a final progress notification
|
7326 |
+
if ( !length ) {
|
7327 |
+
deferred.notifyWith( elem, [ animation, 1, 0 ] );
|
7328 |
+
}
|
7329 |
+
|
7330 |
+
// Resolve the animation and report its conclusion
|
7331 |
+
deferred.resolveWith( elem, [ animation ] );
|
7332 |
+
return false;
|
7333 |
+
},
|
7334 |
+
animation = deferred.promise( {
|
7335 |
+
elem: elem,
|
7336 |
+
props: jQuery.extend( {}, properties ),
|
7337 |
+
opts: jQuery.extend( true, {
|
7338 |
+
specialEasing: {},
|
7339 |
+
easing: jQuery.easing._default
|
7340 |
+
}, options ),
|
7341 |
+
originalProperties: properties,
|
7342 |
+
originalOptions: options,
|
7343 |
+
startTime: fxNow || createFxNow(),
|
7344 |
+
duration: options.duration,
|
7345 |
+
tweens: [],
|
7346 |
+
createTween: function( prop, end ) {
|
7347 |
+
var tween = jQuery.Tween( elem, animation.opts, prop, end,
|
7348 |
+
animation.opts.specialEasing[ prop ] || animation.opts.easing );
|
7349 |
+
animation.tweens.push( tween );
|
7350 |
+
return tween;
|
7351 |
+
},
|
7352 |
+
stop: function( gotoEnd ) {
|
7353 |
+
var index = 0,
|
7354 |
+
|
7355 |
+
// If we are going to the end, we want to run all the tweens
|
7356 |
+
// otherwise we skip this part
|
7357 |
+
length = gotoEnd ? animation.tweens.length : 0;
|
7358 |
+
if ( stopped ) {
|
7359 |
+
return this;
|
7360 |
+
}
|
7361 |
+
stopped = true;
|
7362 |
+
for ( ; index < length; index++ ) {
|
7363 |
+
animation.tweens[ index ].run( 1 );
|
7364 |
+
}
|
7365 |
+
|
7366 |
+
// Resolve when we played the last frame; otherwise, reject
|
7367 |
+
if ( gotoEnd ) {
|
7368 |
+
deferred.notifyWith( elem, [ animation, 1, 0 ] );
|
7369 |
+
deferred.resolveWith( elem, [ animation, gotoEnd ] );
|
7370 |
+
} else {
|
7371 |
+
deferred.rejectWith( elem, [ animation, gotoEnd ] );
|
7372 |
+
}
|
7373 |
+
return this;
|
7374 |
+
}
|
7375 |
+
} ),
|
7376 |
+
props = animation.props;
|
7377 |
+
|
7378 |
+
propFilter( props, animation.opts.specialEasing );
|
7379 |
+
|
7380 |
+
for ( ; index < length; index++ ) {
|
7381 |
+
result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );
|
7382 |
+
if ( result ) {
|
7383 |
+
if ( isFunction( result.stop ) ) {
|
7384 |
+
jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =
|
7385 |
+
result.stop.bind( result );
|
7386 |
+
}
|
7387 |
+
return result;
|
7388 |
+
}
|
7389 |
+
}
|
7390 |
+
|
7391 |
+
jQuery.map( props, createTween, animation );
|
7392 |
+
|
7393 |
+
if ( isFunction( animation.opts.start ) ) {
|
7394 |
+
animation.opts.start.call( elem, animation );
|
7395 |
+
}
|
7396 |
+
|
7397 |
+
// Attach callbacks from options
|
7398 |
+
animation
|
7399 |
+
.progress( animation.opts.progress )
|
7400 |
+
.done( animation.opts.done, animation.opts.complete )
|
7401 |
+
.fail( animation.opts.fail )
|
7402 |
+
.always( animation.opts.always );
|
7403 |
+
|
7404 |
+
jQuery.fx.timer(
|
7405 |
+
jQuery.extend( tick, {
|
7406 |
+
elem: elem,
|
7407 |
+
anim: animation,
|
7408 |
+
queue: animation.opts.queue
|
7409 |
+
} )
|
7410 |
+
);
|
7411 |
+
|
7412 |
+
return animation;
|
7413 |
+
}
|
7414 |
+
|
7415 |
+
jQuery.Animation = jQuery.extend( Animation, {
|
7416 |
+
|
7417 |
+
tweeners: {
|
7418 |
+
"*": [ function( prop, value ) {
|
7419 |
+
var tween = this.createTween( prop, value );
|
7420 |
+
adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );
|
7421 |
+
return tween;
|
7422 |
+
} ]
|
7423 |
+
},
|
7424 |
+
|
7425 |
+
tweener: function( props, callback ) {
|
7426 |
+
if ( isFunction( props ) ) {
|
7427 |
+
callback = props;
|
7428 |
+
props = [ "*" ];
|
7429 |
+
} else {
|
7430 |
+
props = props.match( rnothtmlwhite );
|
7431 |
+
}
|
7432 |
+
|
7433 |
+
var prop,
|
7434 |
+
index = 0,
|
7435 |
+
length = props.length;
|
7436 |
+
|
7437 |
+
for ( ; index < length; index++ ) {
|
7438 |
+
prop = props[ index ];
|
7439 |
+
Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];
|
7440 |
+
Animation.tweeners[ prop ].unshift( callback );
|
7441 |
+
}
|
7442 |
+
},
|
7443 |
+
|
7444 |
+
prefilters: [ defaultPrefilter ],
|
7445 |
+
|
7446 |
+
prefilter: function( callback, prepend ) {
|
7447 |
+
if ( prepend ) {
|
7448 |
+
Animation.prefilters.unshift( callback );
|
7449 |
+
} else {
|
7450 |
+
Animation.prefilters.push( callback );
|
7451 |
+
}
|
7452 |
+
}
|
7453 |
+
} );
|
7454 |
+
|
7455 |
+
jQuery.speed = function( speed, easing, fn ) {
|
7456 |
+
var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
|
7457 |
+
complete: fn || !fn && easing ||
|
7458 |
+
isFunction( speed ) && speed,
|
7459 |
+
duration: speed,
|
7460 |
+
easing: fn && easing || easing && !isFunction( easing ) && easing
|
7461 |
+
};
|
7462 |
+
|
7463 |
+
// Go to the end state if fx are off
|
7464 |
+
if ( jQuery.fx.off ) {
|
7465 |
+
opt.duration = 0;
|
7466 |
+
|
7467 |
+
} else {
|
7468 |
+
if ( typeof opt.duration !== "number" ) {
|
7469 |
+
if ( opt.duration in jQuery.fx.speeds ) {
|
7470 |
+
opt.duration = jQuery.fx.speeds[ opt.duration ];
|
7471 |
+
|
7472 |
+
} else {
|
7473 |
+
opt.duration = jQuery.fx.speeds._default;
|
7474 |
+
}
|
7475 |
+
}
|
7476 |
+
}
|
7477 |
+
|
7478 |
+
// Normalize opt.queue - true/undefined/null -> "fx"
|
7479 |
+
if ( opt.queue == null || opt.queue === true ) {
|
7480 |
+
opt.queue = "fx";
|
7481 |
+
}
|
7482 |
+
|
7483 |
+
// Queueing
|
7484 |
+
opt.old = opt.complete;
|
7485 |
+
|
7486 |
+
opt.complete = function() {
|
7487 |
+
if ( isFunction( opt.old ) ) {
|
7488 |
+
opt.old.call( this );
|
7489 |
+
}
|
7490 |
+
|
7491 |
+
if ( opt.queue ) {
|
7492 |
+
jQuery.dequeue( this, opt.queue );
|
7493 |
+
}
|
7494 |
+
};
|
7495 |
+
|
7496 |
+
return opt;
|
7497 |
+
};
|
7498 |
+
|
7499 |
+
jQuery.fn.extend( {
|
7500 |
+
fadeTo: function( speed, to, easing, callback ) {
|
7501 |
+
|
7502 |
+
// Show any hidden elements after setting opacity to 0
|
7503 |
+
return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show()
|
7504 |
+
|
7505 |
+
// Animate to the value specified
|
7506 |
+
.end().animate( { opacity: to }, speed, easing, callback );
|
7507 |
+
},
|
7508 |
+
animate: function( prop, speed, easing, callback ) {
|
7509 |
+
var empty = jQuery.isEmptyObject( prop ),
|
7510 |
+
optall = jQuery.speed( speed, easing, callback ),
|
7511 |
+
doAnimation = function() {
|
7512 |
+
|
7513 |
+
// Operate on a copy of prop so per-property easing won't be lost
|
7514 |
+
var anim = Animation( this, jQuery.extend( {}, prop ), optall );
|
7515 |
+
|
7516 |
+
// Empty animations, or finishing resolves immediately
|
7517 |
+
if ( empty || dataPriv.get( this, "finish" ) ) {
|
7518 |
+
anim.stop( true );
|
7519 |
+
}
|
7520 |
+
};
|
7521 |
+
doAnimation.finish = doAnimation;
|
7522 |
+
|
7523 |
+
return empty || optall.queue === false ?
|
7524 |
+
this.each( doAnimation ) :
|
7525 |
+
this.queue( optall.queue, doAnimation );
|
7526 |
+
},
|
7527 |
+
stop: function( type, clearQueue, gotoEnd ) {
|
7528 |
+
var stopQueue = function( hooks ) {
|
7529 |
+
var stop = hooks.stop;
|
7530 |
+
delete hooks.stop;
|
7531 |
+
stop( gotoEnd );
|
7532 |
+
};
|
7533 |
+
|
7534 |
+
if ( typeof type !== "string" ) {
|
7535 |
+
gotoEnd = clearQueue;
|
7536 |
+
clearQueue = type;
|
7537 |
+
type = undefined;
|
7538 |
+
}
|
7539 |
+
if ( clearQueue && type !== false ) {
|
7540 |
+
this.queue( type || "fx", [] );
|
7541 |
+
}
|
7542 |
+
|
7543 |
+
return this.each( function() {
|
7544 |
+
var dequeue = true,
|
7545 |
+
index = type != null && type + "queueHooks",
|
7546 |
+
timers = jQuery.timers,
|
7547 |
+
data = dataPriv.get( this );
|
7548 |
+
|
7549 |
+
if ( index ) {
|
7550 |
+
if ( data[ index ] && data[ index ].stop ) {
|
7551 |
+
stopQueue( data[ index ] );
|
7552 |
+
}
|
7553 |
+
} else {
|
7554 |
+
for ( index in data ) {
|
7555 |
+
if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
|
7556 |
+
stopQueue( data[ index ] );
|
7557 |
+
}
|
7558 |
+
}
|
7559 |
+
}
|
7560 |
+
|
7561 |
+
for ( index = timers.length; index--; ) {
|
7562 |
+
if ( timers[ index ].elem === this &&
|
7563 |
+
( type == null || timers[ index ].queue === type ) ) {
|
7564 |
+
|
7565 |
+
timers[ index ].anim.stop( gotoEnd );
|
7566 |
+
dequeue = false;
|
7567 |
+
timers.splice( index, 1 );
|
7568 |
+
}
|
7569 |
+
}
|
7570 |
+
|
7571 |
+
// Start the next in the queue if the last step wasn't forced.
|
7572 |
+
// Timers currently will call their complete callbacks, which
|
7573 |
+
// will dequeue but only if they were gotoEnd.
|
7574 |
+
if ( dequeue || !gotoEnd ) {
|
7575 |
+
jQuery.dequeue( this, type );
|
7576 |
+
}
|
7577 |
+
} );
|
7578 |
+
},
|
7579 |
+
finish: function( type ) {
|
7580 |
+
if ( type !== false ) {
|
7581 |
+
type = type || "fx";
|
7582 |
+
}
|
7583 |
+
return this.each( function() {
|
7584 |
+
var index,
|
7585 |
+
data = dataPriv.get( this ),
|
7586 |
+
queue = data[ type + "queue" ],
|
7587 |
+
hooks = data[ type + "queueHooks" ],
|
7588 |
+
timers = jQuery.timers,
|
7589 |
+
length = queue ? queue.length : 0;
|
7590 |
+
|
7591 |
+
// Enable finishing flag on private data
|
7592 |
+
data.finish = true;
|
7593 |
+
|
7594 |
+
// Empty the queue first
|
7595 |
+
jQuery.queue( this, type, [] );
|
7596 |
+
|
7597 |
+
if ( hooks && hooks.stop ) {
|
7598 |
+
hooks.stop.call( this, true );
|
7599 |
+
}
|
7600 |
+
|
7601 |
+
// Look for any active animations, and finish them
|
7602 |
+
for ( index = timers.length; index--; ) {
|
7603 |
+
if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
|
7604 |
+
timers[ index ].anim.stop( true );
|
7605 |
+
timers.splice( index, 1 );
|
7606 |
+
}
|
7607 |
+
}
|
7608 |
+
|
7609 |
+
// Look for any animations in the old queue and finish them
|
7610 |
+
for ( index = 0; index < length; index++ ) {
|
7611 |
+
if ( queue[ index ] && queue[ index ].finish ) {
|
7612 |
+
queue[ index ].finish.call( this );
|
7613 |
+
}
|
7614 |
+
}
|
7615 |
+
|
7616 |
+
// Turn off finishing flag
|
7617 |
+
delete data.finish;
|
7618 |
+
} );
|
7619 |
+
}
|
7620 |
+
} );
|
7621 |
+
|
7622 |
+
jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) {
|
7623 |
+
var cssFn = jQuery.fn[ name ];
|
7624 |
+
jQuery.fn[ name ] = function( speed, easing, callback ) {
|
7625 |
+
return speed == null || typeof speed === "boolean" ?
|
7626 |
+
cssFn.apply( this, arguments ) :
|
7627 |
+
this.animate( genFx( name, true ), speed, easing, callback );
|
7628 |
+
};
|
7629 |
+
} );
|
7630 |
+
|
7631 |
+
// Generate shortcuts for custom animations
|
7632 |
+
jQuery.each( {
|
7633 |
+
slideDown: genFx( "show" ),
|
7634 |
+
slideUp: genFx( "hide" ),
|
7635 |
+
slideToggle: genFx( "toggle" ),
|
7636 |
+
fadeIn: { opacity: "show" },
|
7637 |
+
fadeOut: { opacity: "hide" },
|
7638 |
+
fadeToggle: { opacity: "toggle" }
|
7639 |
+
}, function( name, props ) {
|
7640 |
+
jQuery.fn[ name ] = function( speed, easing, callback ) {
|
7641 |
+
return this.animate( props, speed, easing, callback );
|
7642 |
+
};
|
7643 |
+
} );
|
7644 |
+
|
7645 |
+
jQuery.timers = [];
|
7646 |
+
jQuery.fx.tick = function() {
|
7647 |
+
var timer,
|
7648 |
+
i = 0,
|
7649 |
+
timers = jQuery.timers;
|
7650 |
+
|
7651 |
+
fxNow = Date.now();
|
7652 |
+
|
7653 |
+
for ( ; i < timers.length; i++ ) {
|
7654 |
+
timer = timers[ i ];
|
7655 |
+
|
7656 |
+
// Run the timer and safely remove it when done (allowing for external removal)
|
7657 |
+
if ( !timer() && timers[ i ] === timer ) {
|
7658 |
+
timers.splice( i--, 1 );
|
7659 |
+
}
|
7660 |
+
}
|
7661 |
+
|
7662 |
+
if ( !timers.length ) {
|
7663 |
+
jQuery.fx.stop();
|
7664 |
+
}
|
7665 |
+
fxNow = undefined;
|
7666 |
+
};
|
7667 |
+
|
7668 |
+
jQuery.fx.timer = function( timer ) {
|
7669 |
+
jQuery.timers.push( timer );
|
7670 |
+
jQuery.fx.start();
|
7671 |
+
};
|
7672 |
+
|
7673 |
+
jQuery.fx.interval = 13;
|
7674 |
+
jQuery.fx.start = function() {
|
7675 |
+
if ( inProgress ) {
|
7676 |
+
return;
|
7677 |
+
}
|
7678 |
+
|
7679 |
+
inProgress = true;
|
7680 |
+
schedule();
|
7681 |
+
};
|
7682 |
+
|
7683 |
+
jQuery.fx.stop = function() {
|
7684 |
+
inProgress = null;
|
7685 |
+
};
|
7686 |
+
|
7687 |
+
jQuery.fx.speeds = {
|
7688 |
+
slow: 600,
|
7689 |
+
fast: 200,
|
7690 |
+
|
7691 |
+
// Default speed
|
7692 |
+
_default: 400
|
7693 |
+
};
|
7694 |
+
|
7695 |
+
|
7696 |
+
// Based off of the plugin by Clint Helfers, with permission.
|
7697 |
+
// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/
|
7698 |
+
jQuery.fn.delay = function( time, type ) {
|
7699 |
+
time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
|
7700 |
+
type = type || "fx";
|
7701 |
+
|
7702 |
+
return this.queue( type, function( next, hooks ) {
|
7703 |
+
var timeout = window.setTimeout( next, time );
|
7704 |
+
hooks.stop = function() {
|
7705 |
+
window.clearTimeout( timeout );
|
7706 |
+
};
|
7707 |
+
} );
|
7708 |
+
};
|
7709 |
+
|
7710 |
+
|
7711 |
+
( function() {
|
7712 |
+
var input = document.createElement( "input" ),
|
7713 |
+
select = document.createElement( "select" ),
|
7714 |
+
opt = select.appendChild( document.createElement( "option" ) );
|
7715 |
+
|
7716 |
+
input.type = "checkbox";
|
7717 |
+
|
7718 |
+
// Support: Android <=4.3 only
|
7719 |
+
// Default value for a checkbox should be "on"
|
7720 |
+
support.checkOn = input.value !== "";
|
7721 |
+
|
7722 |
+
// Support: IE <=11 only
|
7723 |
+
// Must access selectedIndex to make default options select
|
7724 |
+
support.optSelected = opt.selected;
|
7725 |
+
|
7726 |
+
// Support: IE <=11 only
|
7727 |
+
// An input loses its value after becoming a radio
|
7728 |
+
input = document.createElement( "input" );
|
7729 |
+
input.value = "t";
|
7730 |
+
input.type = "radio";
|
7731 |
+
support.radioValue = input.value === "t";
|
7732 |
+
} )();
|
7733 |
+
|
7734 |
+
|
7735 |
+
var boolHook,
|
7736 |
+
attrHandle = jQuery.expr.attrHandle;
|
7737 |
+
|
7738 |
+
jQuery.fn.extend( {
|
7739 |
+
attr: function( name, value ) {
|
7740 |
+
return access( this, jQuery.attr, name, value, arguments.length > 1 );
|
7741 |
+
},
|
7742 |
+
|
7743 |
+
removeAttr: function( name ) {
|
7744 |
+
return this.each( function() {
|
7745 |
+
jQuery.removeAttr( this, name );
|
7746 |
+
} );
|
7747 |
+
}
|
7748 |
+
} );
|
7749 |
+
|
7750 |
+
jQuery.extend( {
|
7751 |
+
attr: function( elem, name, value ) {
|
7752 |
+
var ret, hooks,
|
7753 |
+
nType = elem.nodeType;
|
7754 |
+
|
7755 |
+
// Don't get/set attributes on text, comment and attribute nodes
|
7756 |
+
if ( nType === 3 || nType === 8 || nType === 2 ) {
|
7757 |
+
return;
|
7758 |
+
}
|
7759 |
+
|
7760 |
+
// Fallback to prop when attributes are not supported
|
7761 |
+
if ( typeof elem.getAttribute === "undefined" ) {
|
7762 |
+
return jQuery.prop( elem, name, value );
|
7763 |
+
}
|
7764 |
+
|
7765 |
+
// Attribute hooks are determined by the lowercase version
|
7766 |
+
// Grab necessary hook if one is defined
|
7767 |
+
if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
|
7768 |
+
hooks = jQuery.attrHooks[ name.toLowerCase() ] ||
|
7769 |
+
( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );
|
7770 |
+
}
|
7771 |
+
|
7772 |
+
if ( value !== undefined ) {
|
7773 |
+
if ( value === null ) {
|
7774 |
+
jQuery.removeAttr( elem, name );
|
7775 |
+
return;
|
7776 |
+
}
|
7777 |
+
|
7778 |
+
if ( hooks && "set" in hooks &&
|
7779 |
+
( ret = hooks.set( elem, value, name ) ) !== undefined ) {
|
7780 |
+
return ret;
|
7781 |
+
}
|
7782 |
+
|
7783 |
+
elem.setAttribute( name, value + "" );
|
7784 |
+
return value;
|
7785 |
+
}
|
7786 |
+
|
7787 |
+
if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
|
7788 |
+
return ret;
|
7789 |
+
}
|
7790 |
+
|
7791 |
+
ret = jQuery.find.attr( elem, name );
|
7792 |
+
|
7793 |
+
// Non-existent attributes return null, we normalize to undefined
|
7794 |
+
return ret == null ? undefined : ret;
|
7795 |
+
},
|
7796 |
+
|
7797 |
+
attrHooks: {
|
7798 |
+
type: {
|
7799 |
+
set: function( elem, value ) {
|
7800 |
+
if ( !support.radioValue && value === "radio" &&
|
7801 |
+
nodeName( elem, "input" ) ) {
|
7802 |
+
var val = elem.value;
|
7803 |
+
elem.setAttribute( "type", value );
|
7804 |
+
if ( val ) {
|
7805 |
+
elem.value = val;
|
7806 |
+
}
|
7807 |
+
return value;
|
7808 |
+
}
|
7809 |
+
}
|
7810 |
+
}
|
7811 |
+
},
|
7812 |
+
|
7813 |
+
removeAttr: function( elem, value ) {
|
7814 |
+
var name,
|
7815 |
+
i = 0,
|
7816 |
+
|
7817 |
+
// Attribute names can contain non-HTML whitespace characters
|
7818 |
+
// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
|
7819 |
+
attrNames = value && value.match( rnothtmlwhite );
|
7820 |
+
|
7821 |
+
if ( attrNames && elem.nodeType === 1 ) {
|
7822 |
+
while ( ( name = attrNames[ i++ ] ) ) {
|
7823 |
+
elem.removeAttribute( name );
|
7824 |
+
}
|
7825 |
+
}
|
7826 |
+
}
|
7827 |
+
} );
|
7828 |
+
|
7829 |
+
// Hooks for boolean attributes
|
7830 |
+
boolHook = {
|
7831 |
+
set: function( elem, value, name ) {
|
7832 |
+
if ( value === false ) {
|
7833 |
+
|
7834 |
+
// Remove boolean attributes when set to false
|
7835 |
+
jQuery.removeAttr( elem, name );
|
7836 |
+
} else {
|
7837 |
+
elem.setAttribute( name, name );
|
7838 |
+
}
|
7839 |
+
return name;
|
7840 |
+
}
|
7841 |
+
};
|
7842 |
+
|
7843 |
+
jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
|
7844 |
+
var getter = attrHandle[ name ] || jQuery.find.attr;
|
7845 |
+
|
7846 |
+
attrHandle[ name ] = function( elem, name, isXML ) {
|
7847 |
+
var ret, handle,
|
7848 |
+
lowercaseName = name.toLowerCase();
|
7849 |
+
|
7850 |
+
if ( !isXML ) {
|
7851 |
+
|
7852 |
+
// Avoid an infinite loop by temporarily removing this function from the getter
|
7853 |
+
handle = attrHandle[ lowercaseName ];
|
7854 |
+
attrHandle[ lowercaseName ] = ret;
|
7855 |
+
ret = getter( elem, name, isXML ) != null ?
|
7856 |
+
lowercaseName :
|
7857 |
+
null;
|
7858 |
+
attrHandle[ lowercaseName ] = handle;
|
7859 |
+
}
|
7860 |
+
return ret;
|
7861 |
+
};
|
7862 |
+
} );
|
7863 |
+
|
7864 |
+
|
7865 |
+
|
7866 |
+
|
7867 |
+
var rfocusable = /^(?:input|select|textarea|button)$/i,
|
7868 |
+
rclickable = /^(?:a|area)$/i;
|
7869 |
+
|
7870 |
+
jQuery.fn.extend( {
|
7871 |
+
prop: function( name, value ) {
|
7872 |
+
return access( this, jQuery.prop, name, value, arguments.length > 1 );
|
7873 |
+
},
|
7874 |
+
|
7875 |
+
removeProp: function( name ) {
|
7876 |
+
return this.each( function() {
|
7877 |
+
delete this[ jQuery.propFix[ name ] || name ];
|
7878 |
+
} );
|
7879 |
+
}
|
7880 |
+
} );
|
7881 |
+
|
7882 |
+
jQuery.extend( {
|
7883 |
+
prop: function( elem, name, value ) {
|
7884 |
+
var ret, hooks,
|
7885 |
+
nType = elem.nodeType;
|
7886 |
+
|
7887 |
+
// Don't get/set properties on text, comment and attribute nodes
|
7888 |
+
if ( nType === 3 || nType === 8 || nType === 2 ) {
|
7889 |
+
return;
|
7890 |
+
}
|
7891 |
+
|
7892 |
+
if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
|
7893 |
+
|
7894 |
+
// Fix name and attach hooks
|
7895 |
+
name = jQuery.propFix[ name ] || name;
|
7896 |
+
hooks = jQuery.propHooks[ name ];
|
7897 |
+
}
|
7898 |
+
|
7899 |
+
if ( value !== undefined ) {
|
7900 |
+
if ( hooks && "set" in hooks &&
|
7901 |
+
( ret = hooks.set( elem, value, name ) ) !== undefined ) {
|
7902 |
+
return ret;
|
7903 |
+
}
|
7904 |
+
|
7905 |
+
return ( elem[ name ] = value );
|
7906 |
+
}
|
7907 |
+
|
7908 |
+
if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
|
7909 |
+
return ret;
|
7910 |
+
}
|
7911 |
+
|
7912 |
+
return elem[ name ];
|
7913 |
+
},
|
7914 |
+
|
7915 |
+
propHooks: {
|
7916 |
+
tabIndex: {
|
7917 |
+
get: function( elem ) {
|
7918 |
+
|
7919 |
+
// Support: IE <=9 - 11 only
|
7920 |
+
// elem.tabIndex doesn't always return the
|
7921 |
+
// correct value when it hasn't been explicitly set
|
7922 |
+
// https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
|
7923 |
+
// Use proper attribute retrieval(#12072)
|
7924 |
+
var tabindex = jQuery.find.attr( elem, "tabindex" );
|
7925 |
+
|
7926 |
+
if ( tabindex ) {
|
7927 |
+
return parseInt( tabindex, 10 );
|
7928 |
+
}
|
7929 |
+
|
7930 |
+
if (
|
7931 |
+
rfocusable.test( elem.nodeName ) ||
|
7932 |
+
rclickable.test( elem.nodeName ) &&
|
7933 |
+
elem.href
|
7934 |
+
) {
|
7935 |
+
return 0;
|
7936 |
+
}
|
7937 |
+
|
7938 |
+
return -1;
|
7939 |
+
}
|
7940 |
+
}
|
7941 |
+
},
|
7942 |
+
|
7943 |
+
propFix: {
|
7944 |
+
"for": "htmlFor",
|
7945 |
+
"class": "className"
|
7946 |
+
}
|
7947 |
+
} );
|
7948 |
+
|
7949 |
+
// Support: IE <=11 only
|
7950 |
+
// Accessing the selectedIndex property
|
7951 |
+
// forces the browser to respect setting selected
|
7952 |
+
// on the option
|
7953 |
+
// The getter ensures a default option is selected
|
7954 |
+
// when in an optgroup
|
7955 |
+
// eslint rule "no-unused-expressions" is disabled for this code
|
7956 |
+
// since it considers such accessions noop
|
7957 |
+
if ( !support.optSelected ) {
|
7958 |
+
jQuery.propHooks.selected = {
|
7959 |
+
get: function( elem ) {
|
7960 |
+
|
7961 |
+
/* eslint no-unused-expressions: "off" */
|
7962 |
+
|
7963 |
+
var parent = elem.parentNode;
|
7964 |
+
if ( parent && parent.parentNode ) {
|
7965 |
+
parent.parentNode.selectedIndex;
|
7966 |
+
}
|
7967 |
+
return null;
|
7968 |
+
},
|
7969 |
+
set: function( elem ) {
|
7970 |
+
|
7971 |
+
/* eslint no-unused-expressions: "off" */
|
7972 |
+
|
7973 |
+
var parent = elem.parentNode;
|
7974 |
+
if ( parent ) {
|
7975 |
+
parent.selectedIndex;
|
7976 |
+
|
7977 |
+
if ( parent.parentNode ) {
|
7978 |
+
parent.parentNode.selectedIndex;
|
7979 |
+
}
|
7980 |
+
}
|
7981 |
+
}
|
7982 |
+
};
|
7983 |
+
}
|
7984 |
+
|
7985 |
+
jQuery.each( [
|
7986 |
+
"tabIndex",
|
7987 |
+
"readOnly",
|
7988 |
+
"maxLength",
|
7989 |
+
"cellSpacing",
|
7990 |
+
"cellPadding",
|
7991 |
+
"rowSpan",
|
7992 |
+
"colSpan",
|
7993 |
+
"useMap",
|
7994 |
+
"frameBorder",
|
7995 |
+
"contentEditable"
|
7996 |
+
], function() {
|
7997 |
+
jQuery.propFix[ this.toLowerCase() ] = this;
|
7998 |
+
} );
|
7999 |
+
|
8000 |
+
|
8001 |
+
|
8002 |
+
|
8003 |
+
// Strip and collapse whitespace according to HTML spec
|
8004 |
+
// https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace
|
8005 |
+
function stripAndCollapse( value ) {
|
8006 |
+
var tokens = value.match( rnothtmlwhite ) || [];
|
8007 |
+
return tokens.join( " " );
|
8008 |
+
}
|
8009 |
+
|
8010 |
+
|
8011 |
+
function getClass( elem ) {
|
8012 |
+
return elem.getAttribute && elem.getAttribute( "class" ) || "";
|
8013 |
+
}
|
8014 |
+
|
8015 |
+
function classesToArray( value ) {
|
8016 |
+
if ( Array.isArray( value ) ) {
|
8017 |
+
return value;
|
8018 |
+
}
|
8019 |
+
if ( typeof value === "string" ) {
|
8020 |
+
return value.match( rnothtmlwhite ) || [];
|
8021 |
+
}
|
8022 |
+
return [];
|
8023 |
+
}
|
8024 |
+
|
8025 |
+
jQuery.fn.extend( {
|
8026 |
+
addClass: function( value ) {
|
8027 |
+
var classes, elem, cur, curValue, clazz, j, finalValue,
|
8028 |
+
i = 0;
|
8029 |
+
|
8030 |
+
if ( isFunction( value ) ) {
|
8031 |
+
return this.each( function( j ) {
|
8032 |
+
jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );
|
8033 |
+
} );
|
8034 |
+
}
|
8035 |
+
|
8036 |
+
classes = classesToArray( value );
|
8037 |
+
|
8038 |
+
if ( classes.length ) {
|
8039 |
+
while ( ( elem = this[ i++ ] ) ) {
|
8040 |
+
curValue = getClass( elem );
|
8041 |
+
cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
|
8042 |
+
|
8043 |
+
if ( cur ) {
|
8044 |
+
j = 0;
|
8045 |
+
while ( ( clazz = classes[ j++ ] ) ) {
|
8046 |
+
if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
|
8047 |
+
cur += clazz + " ";
|
8048 |
+
}
|
8049 |
+
}
|
8050 |
+
|
8051 |
+
// Only assign if different to avoid unneeded rendering.
|
8052 |
+
finalValue = stripAndCollapse( cur );
|
8053 |
+
if ( curValue !== finalValue ) {
|
8054 |
+
elem.setAttribute( "class", finalValue );
|
8055 |
+
}
|
8056 |
+
}
|
8057 |
+
}
|
8058 |
+
}
|
8059 |
+
|
8060 |
+
return this;
|
8061 |
+
},
|
8062 |
+
|
8063 |
+
removeClass: function( value ) {
|
8064 |
+
var classes, elem, cur, curValue, clazz, j, finalValue,
|
8065 |
+
i = 0;
|
8066 |
+
|
8067 |
+
if ( isFunction( value ) ) {
|
8068 |
+
return this.each( function( j ) {
|
8069 |
+
jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );
|
8070 |
+
} );
|
8071 |
+
}
|
8072 |
+
|
8073 |
+
if ( !arguments.length ) {
|
8074 |
+
return this.attr( "class", "" );
|
8075 |
+
}
|
8076 |
+
|
8077 |
+
classes = classesToArray( value );
|
8078 |
+
|
8079 |
+
if ( classes.length ) {
|
8080 |
+
while ( ( elem = this[ i++ ] ) ) {
|
8081 |
+
curValue = getClass( elem );
|
8082 |
+
|
8083 |
+
// This expression is here for better compressibility (see addClass)
|
8084 |
+
cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
|
8085 |
+
|
8086 |
+
if ( cur ) {
|
8087 |
+
j = 0;
|
8088 |
+
while ( ( clazz = classes[ j++ ] ) ) {
|
8089 |
+
|
8090 |
+
// Remove *all* instances
|
8091 |
+
while ( cur.indexOf( " " + clazz + " " ) > -1 ) {
|
8092 |
+
cur = cur.replace( " " + clazz + " ", " " );
|
8093 |
+
}
|
8094 |
+
}
|
8095 |
+
|
8096 |
+
// Only assign if different to avoid unneeded rendering.
|
8097 |
+
finalValue = stripAndCollapse( cur );
|
8098 |
+
if ( curValue !== finalValue ) {
|
8099 |
+
elem.setAttribute( "class", finalValue );
|
8100 |
+
}
|
8101 |
+
}
|
8102 |
+
}
|
8103 |
+
}
|
8104 |
+
|
8105 |
+
return this;
|
8106 |
+
},
|
8107 |
+
|
8108 |
+
toggleClass: function( value, stateVal ) {
|
8109 |
+
var type = typeof value,
|
8110 |
+
isValidValue = type === "string" || Array.isArray( value );
|
8111 |
+
|
8112 |
+
if ( typeof stateVal === "boolean" && isValidValue ) {
|
8113 |
+
return stateVal ? this.addClass( value ) : this.removeClass( value );
|
8114 |
+
}
|
8115 |
+
|
8116 |
+
if ( isFunction( value ) ) {
|
8117 |
+
return this.each( function( i ) {
|
8118 |
+
jQuery( this ).toggleClass(
|
8119 |
+
value.call( this, i, getClass( this ), stateVal ),
|
8120 |
+
stateVal
|
8121 |
+
);
|
8122 |
+
} );
|
8123 |
+
}
|
8124 |
+
|
8125 |
+
return this.each( function() {
|
8126 |
+
var className, i, self, classNames;
|
8127 |
+
|
8128 |
+
if ( isValidValue ) {
|
8129 |
+
|
8130 |
+
// Toggle individual class names
|
8131 |
+
i = 0;
|
8132 |
+
self = jQuery( this );
|
8133 |
+
classNames = classesToArray( value );
|
8134 |
+
|
8135 |
+
while ( ( className = classNames[ i++ ] ) ) {
|
8136 |
+
|
8137 |
+
// Check each className given, space separated list
|
8138 |
+
if ( self.hasClass( className ) ) {
|
8139 |
+
self.removeClass( className );
|
8140 |
+
} else {
|
8141 |
+
self.addClass( className );
|
8142 |
+
}
|
8143 |
+
}
|
8144 |
+
|
8145 |
+
// Toggle whole class name
|
8146 |
+
} else if ( value === undefined || type === "boolean" ) {
|
8147 |
+
className = getClass( this );
|
8148 |
+
if ( className ) {
|
8149 |
+
|
8150 |
+
// Store className if set
|
8151 |
+
dataPriv.set( this, "__className__", className );
|
8152 |
+
}
|
8153 |
+
|
8154 |
+
// If the element has a class name or if we're passed `false`,
|
8155 |
+
// then remove the whole classname (if there was one, the above saved it).
|
8156 |
+
// Otherwise bring back whatever was previously saved (if anything),
|
8157 |
+
// falling back to the empty string if nothing was stored.
|
8158 |
+
if ( this.setAttribute ) {
|
8159 |
+
this.setAttribute( "class",
|
8160 |
+
className || value === false ?
|
8161 |
+
"" :
|
8162 |
+
dataPriv.get( this, "__className__" ) || ""
|
8163 |
+
);
|
8164 |
+
}
|
8165 |
+
}
|
8166 |
+
} );
|
8167 |
+
},
|
8168 |
+
|
8169 |
+
hasClass: function( selector ) {
|
8170 |
+
var className, elem,
|
8171 |
+
i = 0;
|
8172 |
+
|
8173 |
+
className = " " + selector + " ";
|
8174 |
+
while ( ( elem = this[ i++ ] ) ) {
|
8175 |
+
if ( elem.nodeType === 1 &&
|
8176 |
+
( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) {
|
8177 |
+
return true;
|
8178 |
+
}
|
8179 |
+
}
|
8180 |
+
|
8181 |
+
return false;
|
8182 |
+
}
|
8183 |
+
} );
|
8184 |
+
|
8185 |
+
|
8186 |
+
|
8187 |
+
|
8188 |
+
var rreturn = /\r/g;
|
8189 |
+
|
8190 |
+
jQuery.fn.extend( {
|
8191 |
+
val: function( value ) {
|
8192 |
+
var hooks, ret, valueIsFunction,
|
8193 |
+
elem = this[ 0 ];
|
8194 |
+
|
8195 |
+
if ( !arguments.length ) {
|
8196 |
+
if ( elem ) {
|
8197 |
+
hooks = jQuery.valHooks[ elem.type ] ||
|
8198 |
+
jQuery.valHooks[ elem.nodeName.toLowerCase() ];
|
8199 |
+
|
8200 |
+
if ( hooks &&
|
8201 |
+
"get" in hooks &&
|
8202 |
+
( ret = hooks.get( elem, "value" ) ) !== undefined
|
8203 |
+
) {
|
8204 |
+
return ret;
|
8205 |
+
}
|
8206 |
+
|
8207 |
+
ret = elem.value;
|
8208 |
+
|
8209 |
+
// Handle most common string cases
|
8210 |
+
if ( typeof ret === "string" ) {
|
8211 |
+
return ret.replace( rreturn, "" );
|
8212 |
+
}
|
8213 |
+
|
8214 |
+
// Handle cases where value is null/undef or number
|
8215 |
+
return ret == null ? "" : ret;
|
8216 |
+
}
|
8217 |
+
|
8218 |
+
return;
|
8219 |
+
}
|
8220 |
+
|
8221 |
+
valueIsFunction = isFunction( value );
|
8222 |
+
|
8223 |
+
return this.each( function( i ) {
|
8224 |
+
var val;
|
8225 |
+
|
8226 |
+
if ( this.nodeType !== 1 ) {
|
8227 |
+
return;
|
8228 |
+
}
|
8229 |
+
|
8230 |
+
if ( valueIsFunction ) {
|
8231 |
+
val = value.call( this, i, jQuery( this ).val() );
|
8232 |
+
} else {
|
8233 |
+
val = value;
|
8234 |
+
}
|
8235 |
+
|
8236 |
+
// Treat null/undefined as ""; convert numbers to string
|
8237 |
+
if ( val == null ) {
|
8238 |
+
val = "";
|
8239 |
+
|
8240 |
+
} else if ( typeof val === "number" ) {
|
8241 |
+
val += "";
|
8242 |
+
|
8243 |
+
} else if ( Array.isArray( val ) ) {
|
8244 |
+
val = jQuery.map( val, function( value ) {
|
8245 |
+
return value == null ? "" : value + "";
|
8246 |
+
} );
|
8247 |
+
}
|
8248 |
+
|
8249 |
+
hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
|
8250 |
+
|
8251 |
+
// If set returns undefined, fall back to normal setting
|
8252 |
+
if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) {
|
8253 |
+
this.value = val;
|
8254 |
+
}
|
8255 |
+
} );
|
8256 |
+
}
|
8257 |
+
} );
|
8258 |
+
|
8259 |
+
jQuery.extend( {
|
8260 |
+
valHooks: {
|
8261 |
+
option: {
|
8262 |
+
get: function( elem ) {
|
8263 |
+
|
8264 |
+
var val = jQuery.find.attr( elem, "value" );
|
8265 |
+
return val != null ?
|
8266 |
+
val :
|
8267 |
+
|
8268 |
+
// Support: IE <=10 - 11 only
|
8269 |
+
// option.text throws exceptions (#14686, #14858)
|
8270 |
+
// Strip and collapse whitespace
|
8271 |
+
// https://html.spec.whatwg.org/#strip-and-collapse-whitespace
|
8272 |
+
stripAndCollapse( jQuery.text( elem ) );
|
8273 |
+
}
|
8274 |
+
},
|
8275 |
+
select: {
|
8276 |
+
get: function( elem ) {
|
8277 |
+
var value, option, i,
|
8278 |
+
options = elem.options,
|
8279 |
+
index = elem.selectedIndex,
|
8280 |
+
one = elem.type === "select-one",
|
8281 |
+
values = one ? null : [],
|
8282 |
+
max = one ? index + 1 : options.length;
|
8283 |
+
|
8284 |
+
if ( index < 0 ) {
|
8285 |
+
i = max;
|
8286 |
+
|
8287 |
+
} else {
|
8288 |
+
i = one ? index : 0;
|
8289 |
+
}
|
8290 |
+
|
8291 |
+
// Loop through all the selected options
|
8292 |
+
for ( ; i < max; i++ ) {
|
8293 |
+
option = options[ i ];
|
8294 |
+
|
8295 |
+
// Support: IE <=9 only
|
8296 |
+
// IE8-9 doesn't update selected after form reset (#2551)
|
8297 |
+
if ( ( option.selected || i === index ) &&
|
8298 |
+
|
8299 |
+
// Don't return options that are disabled or in a disabled optgroup
|
8300 |
+
!option.disabled &&
|
8301 |
+
( !option.parentNode.disabled ||
|
8302 |
+
!nodeName( option.parentNode, "optgroup" ) ) ) {
|
8303 |
+
|
8304 |
+
// Get the specific value for the option
|
8305 |
+
value = jQuery( option ).val();
|
8306 |
+
|
8307 |
+
// We don't need an array for one selects
|
8308 |
+
if ( one ) {
|
8309 |
+
return value;
|
8310 |
+
}
|
8311 |
+
|
8312 |
+
// Multi-Selects return an array
|
8313 |
+
values.push( value );
|
8314 |
+
}
|
8315 |
+
}
|
8316 |
+
|
8317 |
+
return values;
|
8318 |
+
},
|
8319 |
+
|
8320 |
+
set: function( elem, value ) {
|
8321 |
+
var optionSet, option,
|
8322 |
+
options = elem.options,
|
8323 |
+
values = jQuery.makeArray( value ),
|
8324 |
+
i = options.length;
|
8325 |
+
|
8326 |
+
while ( i-- ) {
|
8327 |
+
option = options[ i ];
|
8328 |
+
|
8329 |
+
/* eslint-disable no-cond-assign */
|
8330 |
+
|
8331 |
+
if ( option.selected =
|
8332 |
+
jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1
|
8333 |
+
) {
|
8334 |
+
optionSet = true;
|
8335 |
+
}
|
8336 |
+
|
8337 |
+
/* eslint-enable no-cond-assign */
|
8338 |
+
}
|
8339 |
+
|
8340 |
+
// Force browsers to behave consistently when non-matching value is set
|
8341 |
+
if ( !optionSet ) {
|
8342 |
+
elem.selectedIndex = -1;
|
8343 |
+
}
|
8344 |
+
return values;
|
8345 |
+
}
|
8346 |
+
}
|
8347 |
+
}
|
8348 |
+
} );
|
8349 |
+
|
8350 |
+
// Radios and checkboxes getter/setter
|
8351 |
+
jQuery.each( [ "radio", "checkbox" ], function() {
|
8352 |
+
jQuery.valHooks[ this ] = {
|
8353 |
+
set: function( elem, value ) {
|
8354 |
+
if ( Array.isArray( value ) ) {
|
8355 |
+
return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );
|
8356 |
+
}
|
8357 |
+
}
|
8358 |
+
};
|
8359 |
+
if ( !support.checkOn ) {
|
8360 |
+
jQuery.valHooks[ this ].get = function( elem ) {
|
8361 |
+
return elem.getAttribute( "value" ) === null ? "on" : elem.value;
|
8362 |
+
};
|
8363 |
+
}
|
8364 |
+
} );
|
8365 |
+
|
8366 |
+
|
8367 |
+
|
8368 |
+
|
8369 |
+
// Return jQuery for attributes-only inclusion
|
8370 |
+
|
8371 |
+
|
8372 |
+
support.focusin = "onfocusin" in window;
|
8373 |
+
|
8374 |
+
|
8375 |
+
var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
|
8376 |
+
stopPropagationCallback = function( e ) {
|
8377 |
+
e.stopPropagation();
|
8378 |
+
};
|
8379 |
+
|
8380 |
+
jQuery.extend( jQuery.event, {
|
8381 |
+
|
8382 |
+
trigger: function( event, data, elem, onlyHandlers ) {
|
8383 |
+
|
8384 |
+
var i, cur, tmp, bubbleType, ontype, handle, special, lastElement,
|
8385 |
+
eventPath = [ elem || document ],
|
8386 |
+
type = hasOwn.call( event, "type" ) ? event.type : event,
|
8387 |
+
namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : [];
|
8388 |
+
|
8389 |
+
cur = lastElement = tmp = elem = elem || document;
|
8390 |
+
|
8391 |
+
// Don't do events on text and comment nodes
|
8392 |
+
if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
|
8393 |
+
return;
|
8394 |
+
}
|
8395 |
+
|
8396 |
+
// focus/blur morphs to focusin/out; ensure we're not firing them right now
|
8397 |
+
if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
|
8398 |
+
return;
|
8399 |
+
}
|
8400 |
+
|
8401 |
+
if ( type.indexOf( "." ) > -1 ) {
|
8402 |
+
|
8403 |
+
// Namespaced trigger; create a regexp to match event type in handle()
|
8404 |
+
namespaces = type.split( "." );
|
8405 |
+
type = namespaces.shift();
|
8406 |
+
namespaces.sort();
|
8407 |
+
}
|
8408 |
+
ontype = type.indexOf( ":" ) < 0 && "on" + type;
|
8409 |
+
|
8410 |
+
// Caller can pass in a jQuery.Event object, Object, or just an event type string
|
8411 |
+
event = event[ jQuery.expando ] ?
|
8412 |
+
event :
|
8413 |
+
new jQuery.Event( type, typeof event === "object" && event );
|
8414 |
+
|
8415 |
+
// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
|
8416 |
+
event.isTrigger = onlyHandlers ? 2 : 3;
|
8417 |
+
event.namespace = namespaces.join( "." );
|
8418 |
+
event.rnamespace = event.namespace ?
|
8419 |
+
new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) :
|
8420 |
+
null;
|
8421 |
+
|
8422 |
+
// Clean up the event in case it is being reused
|
8423 |
+
event.result = undefined;
|
8424 |
+
if ( !event.target ) {
|
8425 |
+
event.target = elem;
|
8426 |
+
}
|
8427 |
+
|
8428 |
+
// Clone any incoming data and prepend the event, creating the handler arg list
|
8429 |
+
data = data == null ?
|
8430 |
+
[ event ] :
|
8431 |
+
jQuery.makeArray( data, [ event ] );
|
8432 |
+
|
8433 |
+
// Allow special events to draw outside the lines
|
8434 |
+
special = jQuery.event.special[ type ] || {};
|
8435 |
+
if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
|
8436 |
+
return;
|
8437 |
+
}
|
8438 |
+
|
8439 |
+
// Determine event propagation path in advance, per W3C events spec (#9951)
|
8440 |
+
// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
|
8441 |
+
if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) {
|
8442 |
+
|
8443 |
+
bubbleType = special.delegateType || type;
|
8444 |
+
if ( !rfocusMorph.test( bubbleType + type ) ) {
|
8445 |
+
cur = cur.parentNode;
|
8446 |
+
}
|
8447 |
+
for ( ; cur; cur = cur.parentNode ) {
|
8448 |
+
eventPath.push( cur );
|
8449 |
+
tmp = cur;
|
8450 |
+
}
|
8451 |
+
|
8452 |
+
// Only add window if we got to document (e.g., not plain obj or detached DOM)
|
8453 |
+
if ( tmp === ( elem.ownerDocument || document ) ) {
|
8454 |
+
eventPath.push( tmp.defaultView || tmp.parentWindow || window );
|
8455 |
+
}
|
8456 |
+
}
|
8457 |
+
|
8458 |
+
// Fire handlers on the event path
|
8459 |
+
i = 0;
|
8460 |
+
while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {
|
8461 |
+
lastElement = cur;
|
8462 |
+
event.type = i > 1 ?
|
8463 |
+
bubbleType :
|
8464 |
+
special.bindType || type;
|
8465 |
+
|
8466 |
+
// jQuery handler
|
8467 |
+
handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] &&
|
8468 |
+
dataPriv.get( cur, "handle" );
|
8469 |
+
if ( handle ) {
|
8470 |
+
handle.apply( cur, data );
|
8471 |
+
}
|
8472 |
+
|
8473 |
+
// Native handler
|
8474 |
+
handle = ontype && cur[ ontype ];
|
8475 |
+
if ( handle && handle.apply && acceptData( cur ) ) {
|
8476 |
+
event.result = handle.apply( cur, data );
|
8477 |
+
if ( event.result === false ) {
|
8478 |
+
event.preventDefault();
|
8479 |
+
}
|
8480 |
+
}
|
8481 |
+
}
|
8482 |
+
event.type = type;
|
8483 |
+
|
8484 |
+
// If nobody prevented the default action, do it now
|
8485 |
+
if ( !onlyHandlers && !event.isDefaultPrevented() ) {
|
8486 |
+
|
8487 |
+
if ( ( !special._default ||
|
8488 |
+
special._default.apply( eventPath.pop(), data ) === false ) &&
|
8489 |
+
acceptData( elem ) ) {
|
8490 |
+
|
8491 |
+
// Call a native DOM method on the target with the same name as the event.
|
8492 |
+
// Don't do default actions on window, that's where global variables be (#6170)
|
8493 |
+
if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) {
|
8494 |
+
|
8495 |
+
// Don't re-trigger an onFOO event when we call its FOO() method
|
8496 |
+
tmp = elem[ ontype ];
|
8497 |
+
|
8498 |
+
if ( tmp ) {
|
8499 |
+
elem[ ontype ] = null;
|
8500 |
+
}
|
8501 |
+
|
8502 |
+
// Prevent re-triggering of the same event, since we already bubbled it above
|
8503 |
+
jQuery.event.triggered = type;
|
8504 |
+
|
8505 |
+
if ( event.isPropagationStopped() ) {
|
8506 |
+
lastElement.addEventListener( type, stopPropagationCallback );
|
8507 |
+
}
|
8508 |
+
|
8509 |
+
elem[ type ]();
|
8510 |
+
|
8511 |
+
if ( event.isPropagationStopped() ) {
|
8512 |
+
lastElement.removeEventListener( type, stopPropagationCallback );
|
8513 |
+
}
|
8514 |
+
|
8515 |
+
jQuery.event.triggered = undefined;
|
8516 |
+
|
8517 |
+
if ( tmp ) {
|
8518 |
+
elem[ ontype ] = tmp;
|
8519 |
+
}
|
8520 |
+
}
|
8521 |
+
}
|
8522 |
+
}
|
8523 |
+
|
8524 |
+
return event.result;
|
8525 |
+
},
|
8526 |
+
|
8527 |
+
// Piggyback on a donor event to simulate a different one
|
8528 |
+
// Used only for `focus(in | out)` events
|
8529 |
+
simulate: function( type, elem, event ) {
|
8530 |
+
var e = jQuery.extend(
|
8531 |
+
new jQuery.Event(),
|
8532 |
+
event,
|
8533 |
+
{
|
8534 |
+
type: type,
|
8535 |
+
isSimulated: true
|
8536 |
+
}
|
8537 |
+
);
|
8538 |
+
|
8539 |
+
jQuery.event.trigger( e, null, elem );
|
8540 |
+
}
|
8541 |
+
|
8542 |
+
} );
|
8543 |
+
|
8544 |
+
jQuery.fn.extend( {
|
8545 |
+
|
8546 |
+
trigger: function( type, data ) {
|
8547 |
+
return this.each( function() {
|
8548 |
+
jQuery.event.trigger( type, data, this );
|
8549 |
+
} );
|
8550 |
+
},
|
8551 |
+
triggerHandler: function( type, data ) {
|
8552 |
+
var elem = this[ 0 ];
|
8553 |
+
if ( elem ) {
|
8554 |
+
return jQuery.event.trigger( type, data, elem, true );
|
8555 |
+
}
|
8556 |
+
}
|
8557 |
+
} );
|
8558 |
+
|
8559 |
+
|
8560 |
+
// Support: Firefox <=44
|
8561 |
+
// Firefox doesn't have focus(in | out) events
|
8562 |
+
// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
|
8563 |
+
//
|
8564 |
+
// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1
|
8565 |
+
// focus(in | out) events fire after focus & blur events,
|
8566 |
+
// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
|
8567 |
+
// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857
|
8568 |
+
if ( !support.focusin ) {
|
8569 |
+
jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) {
|
8570 |
+
|
8571 |
+
// Attach a single capturing handler on the document while someone wants focusin/focusout
|
8572 |
+
var handler = function( event ) {
|
8573 |
+
jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );
|
8574 |
+
};
|
8575 |
+
|
8576 |
+
jQuery.event.special[ fix ] = {
|
8577 |
+
setup: function() {
|
8578 |
+
var doc = this.ownerDocument || this,
|
8579 |
+
attaches = dataPriv.access( doc, fix );
|
8580 |
+
|
8581 |
+
if ( !attaches ) {
|
8582 |
+
doc.addEventListener( orig, handler, true );
|
8583 |
+
}
|
8584 |
+
dataPriv.access( doc, fix, ( attaches || 0 ) + 1 );
|
8585 |
+
},
|
8586 |
+
teardown: function() {
|
8587 |
+
var doc = this.ownerDocument || this,
|
8588 |
+
attaches = dataPriv.access( doc, fix ) - 1;
|
8589 |
+
|
8590 |
+
if ( !attaches ) {
|
8591 |
+
doc.removeEventListener( orig, handler, true );
|
8592 |
+
dataPriv.remove( doc, fix );
|
8593 |
+
|
8594 |
+
} else {
|
8595 |
+
dataPriv.access( doc, fix, attaches );
|
8596 |
+
}
|
8597 |
+
}
|
8598 |
+
};
|
8599 |
+
} );
|
8600 |
+
}
|
8601 |
+
var location = window.location;
|
8602 |
+
|
8603 |
+
var nonce = Date.now();
|
8604 |
+
|
8605 |
+
var rquery = ( /\?/ );
|
8606 |
+
|
8607 |
+
|
8608 |
+
|
8609 |
+
// Cross-browser xml parsing
|
8610 |
+
jQuery.parseXML = function( data ) {
|
8611 |
+
var xml;
|
8612 |
+
if ( !data || typeof data !== "string" ) {
|
8613 |
+
return null;
|
8614 |
+
}
|
8615 |
+
|
8616 |
+
// Support: IE 9 - 11 only
|
8617 |
+
// IE throws on parseFromString with invalid input.
|
8618 |
+
try {
|
8619 |
+
xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" );
|
8620 |
+
} catch ( e ) {
|
8621 |
+
xml = undefined;
|
8622 |
+
}
|
8623 |
+
|
8624 |
+
if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
|
8625 |
+
jQuery.error( "Invalid XML: " + data );
|
8626 |
+
}
|
8627 |
+
return xml;
|
8628 |
+
};
|
8629 |
+
|
8630 |
+
|
8631 |
+
var
|
8632 |
+
rbracket = /\[\]$/,
|
8633 |
+
rCRLF = /\r?\n/g,
|
8634 |
+
rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
|
8635 |
+
rsubmittable = /^(?:input|select|textarea|keygen)/i;
|
8636 |
+
|
8637 |
+
function buildParams( prefix, obj, traditional, add ) {
|
8638 |
+
var name;
|
8639 |
+
|
8640 |
+
if ( Array.isArray( obj ) ) {
|
8641 |
+
|
8642 |
+
// Serialize array item.
|
8643 |
+
jQuery.each( obj, function( i, v ) {
|
8644 |
+
if ( traditional || rbracket.test( prefix ) ) {
|
8645 |
+
|
8646 |
+
// Treat each array item as a scalar.
|
8647 |
+
add( prefix, v );
|
8648 |
+
|
8649 |
+
} else {
|
8650 |
+
|
8651 |
+
// Item is non-scalar (array or object), encode its numeric index.
|
8652 |
+
buildParams(
|
8653 |
+
prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]",
|
8654 |
+
v,
|
8655 |
+
traditional,
|
8656 |
+
add
|
8657 |
+
);
|
8658 |
+
}
|
8659 |
+
} );
|
8660 |
+
|
8661 |
+
} else if ( !traditional && toType( obj ) === "object" ) {
|
8662 |
+
|
8663 |
+
// Serialize object item.
|
8664 |
+
for ( name in obj ) {
|
8665 |
+
buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
|
8666 |
+
}
|
8667 |
+
|
8668 |
+
} else {
|
8669 |
+
|
8670 |
+
// Serialize scalar item.
|
8671 |
+
add( prefix, obj );
|
8672 |
+
}
|
8673 |
+
}
|
8674 |
+
|
8675 |
+
// Serialize an array of form elements or a set of
|
8676 |
+
// key/values into a query string
|
8677 |
+
jQuery.param = function( a, traditional ) {
|
8678 |
+
var prefix,
|
8679 |
+
s = [],
|
8680 |
+
add = function( key, valueOrFunction ) {
|
8681 |
+
|
8682 |
+
// If value is a function, invoke it and use its return value
|
8683 |
+
var value = isFunction( valueOrFunction ) ?
|
8684 |
+
valueOrFunction() :
|
8685 |
+
valueOrFunction;
|
8686 |
+
|
8687 |
+
s[ s.length ] = encodeURIComponent( key ) + "=" +
|
8688 |
+
encodeURIComponent( value == null ? "" : value );
|
8689 |
+
};
|
8690 |
+
|
8691 |
+
// If an array was passed in, assume that it is an array of form elements.
|
8692 |
+
if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
|
8693 |
+
|
8694 |
+
// Serialize the form elements
|
8695 |
+
jQuery.each( a, function() {
|
8696 |
+
add( this.name, this.value );
|
8697 |
+
} );
|
8698 |
+
|
8699 |
+
} else {
|
8700 |
+
|
8701 |
+
// If traditional, encode the "old" way (the way 1.3.2 or older
|
8702 |
+
// did it), otherwise encode params recursively.
|
8703 |
+
for ( prefix in a ) {
|
8704 |
+
buildParams( prefix, a[ prefix ], traditional, add );
|
8705 |
+
}
|
8706 |
+
}
|
8707 |
+
|
8708 |
+
// Return the resulting serialization
|
8709 |
+
return s.join( "&" );
|
8710 |
+
};
|
8711 |
+
|
8712 |
+
jQuery.fn.extend( {
|
8713 |
+
serialize: function() {
|
8714 |
+
return jQuery.param( this.serializeArray() );
|
8715 |
+
},
|
8716 |
+
serializeArray: function() {
|
8717 |
+
return this.map( function() {
|
8718 |
+
|
8719 |
+
// Can add propHook for "elements" to filter or add form elements
|
8720 |
+
var elements = jQuery.prop( this, "elements" );
|
8721 |
+
return elements ? jQuery.makeArray( elements ) : this;
|
8722 |
+
} )
|
8723 |
+
.filter( function() {
|
8724 |
+
var type = this.type;
|
8725 |
+
|
8726 |
+
// Use .is( ":disabled" ) so that fieldset[disabled] works
|
8727 |
+
return this.name && !jQuery( this ).is( ":disabled" ) &&
|
8728 |
+
rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
|
8729 |
+
( this.checked || !rcheckableType.test( type ) );
|
8730 |
+
} )
|
8731 |
+
.map( function( i, elem ) {
|
8732 |
+
var val = jQuery( this ).val();
|
8733 |
+
|
8734 |
+
if ( val == null ) {
|
8735 |
+
return null;
|
8736 |
+
}
|
8737 |
+
|
8738 |
+
if ( Array.isArray( val ) ) {
|
8739 |
+
return jQuery.map( val, function( val ) {
|
8740 |
+
return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
|
8741 |
+
} );
|
8742 |
+
}
|
8743 |
+
|
8744 |
+
return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
|
8745 |
+
} ).get();
|
8746 |
+
}
|
8747 |
+
} );
|
8748 |
+
|
8749 |
+
|
8750 |
+
var
|
8751 |
+
r20 = /%20/g,
|
8752 |
+
rhash = /#.*$/,
|
8753 |
+
rantiCache = /([?&])_=[^&]*/,
|
8754 |
+
rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
|
8755 |
+
|
8756 |
+
// #7653, #8125, #8152: local protocol detection
|
8757 |
+
rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
|
8758 |
+
rnoContent = /^(?:GET|HEAD)$/,
|
8759 |
+
rprotocol = /^\/\//,
|
8760 |
+
|
8761 |
+
/* Prefilters
|
8762 |
+
* 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
|
8763 |
+
* 2) These are called:
|
8764 |
+
* - BEFORE asking for a transport
|
8765 |
+
* - AFTER param serialization (s.data is a string if s.processData is true)
|
8766 |
+
* 3) key is the dataType
|
8767 |
+
* 4) the catchall symbol "*" can be used
|
8768 |
+
* 5) execution will start with transport dataType and THEN continue down to "*" if needed
|
8769 |
+
*/
|
8770 |
+
prefilters = {},
|
8771 |
+
|
8772 |
+
/* Transports bindings
|
8773 |
+
* 1) key is the dataType
|
8774 |
+
* 2) the catchall symbol "*" can be used
|
8775 |
+
* 3) selection will start with transport dataType and THEN go to "*" if needed
|
8776 |
+
*/
|
8777 |
+
transports = {},
|
8778 |
+
|
8779 |
+
// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
|
8780 |
+
allTypes = "*/".concat( "*" ),
|
8781 |
+
|
8782 |
+
// Anchor tag for parsing the document origin
|
8783 |
+
originAnchor = document.createElement( "a" );
|
8784 |
+
originAnchor.href = location.href;
|
8785 |
+
|
8786 |
+
// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
|
8787 |
+
function addToPrefiltersOrTransports( structure ) {
|
8788 |
+
|
8789 |
+
// dataTypeExpression is optional and defaults to "*"
|
8790 |
+
return function( dataTypeExpression, func ) {
|
8791 |
+
|
8792 |
+
if ( typeof dataTypeExpression !== "string" ) {
|
8793 |
+
func = dataTypeExpression;
|
8794 |
+
dataTypeExpression = "*";
|
8795 |
+
}
|
8796 |
+
|
8797 |
+
var dataType,
|
8798 |
+
i = 0,
|
8799 |
+
dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];
|
8800 |
+
|
8801 |
+
if ( isFunction( func ) ) {
|
8802 |
+
|
8803 |
+
// For each dataType in the dataTypeExpression
|
8804 |
+
while ( ( dataType = dataTypes[ i++ ] ) ) {
|
8805 |
+
|
8806 |
+
// Prepend if requested
|
8807 |
+
if ( dataType[ 0 ] === "+" ) {
|
8808 |
+
dataType = dataType.slice( 1 ) || "*";
|
8809 |
+
( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );
|
8810 |
+
|
8811 |
+
// Otherwise append
|
8812 |
+
} else {
|
8813 |
+
( structure[ dataType ] = structure[ dataType ] || [] ).push( func );
|
8814 |
+
}
|
8815 |
+
}
|
8816 |
+
}
|
8817 |
+
};
|
8818 |
+
}
|
8819 |
+
|
8820 |
+
// Base inspection function for prefilters and transports
|
8821 |
+
function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
|
8822 |
+
|
8823 |
+
var inspected = {},
|
8824 |
+
seekingTransport = ( structure === transports );
|
8825 |
+
|
8826 |
+
function inspect( dataType ) {
|
8827 |
+
var selected;
|
8828 |
+
inspected[ dataType ] = true;
|
8829 |
+
jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
|
8830 |
+
var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
|
8831 |
+
if ( typeof dataTypeOrTransport === "string" &&
|
8832 |
+
!seekingTransport && !inspected[ dataTypeOrTransport ] ) {
|
8833 |
+
|
8834 |
+
options.dataTypes.unshift( dataTypeOrTransport );
|
8835 |
+
inspect( dataTypeOrTransport );
|
8836 |
+
return false;
|
8837 |
+
} else if ( seekingTransport ) {
|
8838 |
+
return !( selected = dataTypeOrTransport );
|
8839 |
+
}
|
8840 |
+
} );
|
8841 |
+
return selected;
|
8842 |
+
}
|
8843 |
+
|
8844 |
+
return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
|
8845 |
+
}
|
8846 |
+
|
8847 |
+
// A special extend for ajax options
|
8848 |
+
// that takes "flat" options (not to be deep extended)
|
8849 |
+
// Fixes #9887
|
8850 |
+
function ajaxExtend( target, src ) {
|
8851 |
+
var key, deep,
|
8852 |
+
flatOptions = jQuery.ajaxSettings.flatOptions || {};
|
8853 |
+
|
8854 |
+
for ( key in src ) {
|
8855 |
+
if ( src[ key ] !== undefined ) {
|
8856 |
+
( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
|
8857 |
+
}
|
8858 |
+
}
|
8859 |
+
if ( deep ) {
|
8860 |
+
jQuery.extend( true, target, deep );
|
8861 |
+
}
|
8862 |
+
|
8863 |
+
return target;
|
8864 |
+
}
|
8865 |
+
|
8866 |
+
/* Handles responses to an ajax request:
|
8867 |
+
* - finds the right dataType (mediates between content-type and expected dataType)
|
8868 |
+
* - returns the corresponding response
|
8869 |
+
*/
|
8870 |
+
function ajaxHandleResponses( s, jqXHR, responses ) {
|
8871 |
+
|
8872 |
+
var ct, type, finalDataType, firstDataType,
|
8873 |
+
contents = s.contents,
|
8874 |
+
dataTypes = s.dataTypes;
|
8875 |
+
|
8876 |
+
// Remove auto dataType and get content-type in the process
|
8877 |
+
while ( dataTypes[ 0 ] === "*" ) {
|
8878 |
+
dataTypes.shift();
|
8879 |
+
if ( ct === undefined ) {
|
8880 |
+
ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" );
|
8881 |
+
}
|
8882 |
+
}
|
8883 |
+
|
8884 |
+
// Check if we're dealing with a known content-type
|
8885 |
+
if ( ct ) {
|
8886 |
+
for ( type in contents ) {
|
8887 |
+
if ( contents[ type ] && contents[ type ].test( ct ) ) {
|
8888 |
+
dataTypes.unshift( type );
|
8889 |
+
break;
|
8890 |
+
}
|
8891 |
+
}
|
8892 |
+
}
|
8893 |
+
|
8894 |
+
// Check to see if we have a response for the expected dataType
|
8895 |
+
if ( dataTypes[ 0 ] in responses ) {
|
8896 |
+
finalDataType = dataTypes[ 0 ];
|
8897 |
+
} else {
|
8898 |
+
|
8899 |
+
// Try convertible dataTypes
|
8900 |
+
for ( type in responses ) {
|
8901 |
+
if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) {
|
8902 |
+
finalDataType = type;
|
8903 |
+
break;
|
8904 |
+
}
|
8905 |
+
if ( !firstDataType ) {
|
8906 |
+
firstDataType = type;
|
8907 |
+
}
|
8908 |
+
}
|
8909 |
+
|
8910 |
+
// Or just use first one
|
8911 |
+
finalDataType = finalDataType || firstDataType;
|
8912 |
+
}
|
8913 |
+
|
8914 |
+
// If we found a dataType
|
8915 |
+
// We add the dataType to the list if needed
|
8916 |
+
// and return the corresponding response
|
8917 |
+
if ( finalDataType ) {
|
8918 |
+
if ( finalDataType !== dataTypes[ 0 ] ) {
|
8919 |
+
dataTypes.unshift( finalDataType );
|
8920 |
+
}
|
8921 |
+
return responses[ finalDataType ];
|
8922 |
+
}
|
8923 |
+
}
|
8924 |
+
|
8925 |
+
/* Chain conversions given the request and the original response
|
8926 |
+
* Also sets the responseXXX fields on the jqXHR instance
|
8927 |
+
*/
|
8928 |
+
function ajaxConvert( s, response, jqXHR, isSuccess ) {
|
8929 |
+
var conv2, current, conv, tmp, prev,
|
8930 |
+
converters = {},
|
8931 |
+
|
8932 |
+
// Work with a copy of dataTypes in case we need to modify it for conversion
|
8933 |
+
dataTypes = s.dataTypes.slice();
|
8934 |
+
|
8935 |
+
// Create converters map with lowercased keys
|
8936 |
+
if ( dataTypes[ 1 ] ) {
|
8937 |
+
for ( conv in s.converters ) {
|
8938 |
+
converters[ conv.toLowerCase() ] = s.converters[ conv ];
|
8939 |
+
}
|
8940 |
+
}
|
8941 |
+
|
8942 |
+
current = dataTypes.shift();
|
8943 |
+
|
8944 |
+
// Convert to each sequential dataType
|
8945 |
+
while ( current ) {
|
8946 |
+
|
8947 |
+
if ( s.responseFields[ current ] ) {
|
8948 |
+
jqXHR[ s.responseFields[ current ] ] = response;
|
8949 |
+
}
|
8950 |
+
|
8951 |
+
// Apply the dataFilter if provided
|
8952 |
+
if ( !prev && isSuccess && s.dataFilter ) {
|
8953 |
+
response = s.dataFilter( response, s.dataType );
|
8954 |
+
}
|
8955 |
+
|
8956 |
+
prev = current;
|
8957 |
+
current = dataTypes.shift();
|
8958 |
+
|
8959 |
+
if ( current ) {
|
8960 |
+
|
8961 |
+
// There's only work to do if current dataType is non-auto
|
8962 |
+
if ( current === "*" ) {
|
8963 |
+
|
8964 |
+
current = prev;
|
8965 |
+
|
8966 |
+
// Convert response if prev dataType is non-auto and differs from current
|
8967 |
+
} else if ( prev !== "*" && prev !== current ) {
|
8968 |
+
|
8969 |
+
// Seek a direct converter
|
8970 |
+
conv = converters[ prev + " " + current ] || converters[ "* " + current ];
|
8971 |
+
|
8972 |
+
// If none found, seek a pair
|
8973 |
+
if ( !conv ) {
|
8974 |
+
for ( conv2 in converters ) {
|
8975 |
+
|
8976 |
+
// If conv2 outputs current
|
8977 |
+
tmp = conv2.split( " " );
|
8978 |
+
if ( tmp[ 1 ] === current ) {
|
8979 |
+
|
8980 |
+
// If prev can be converted to accepted input
|
8981 |
+
conv = converters[ prev + " " + tmp[ 0 ] ] ||
|
8982 |
+
converters[ "* " + tmp[ 0 ] ];
|
8983 |
+
if ( conv ) {
|
8984 |
+
|
8985 |
+
// Condense equivalence converters
|
8986 |
+
if ( conv === true ) {
|
8987 |
+
conv = converters[ conv2 ];
|
8988 |
+
|
8989 |
+
// Otherwise, insert the intermediate dataType
|
8990 |
+
} else if ( converters[ conv2 ] !== true ) {
|
8991 |
+
current = tmp[ 0 ];
|
8992 |
+
dataTypes.unshift( tmp[ 1 ] );
|
8993 |
+
}
|
8994 |
+
break;
|
8995 |
+
}
|
8996 |
+
}
|
8997 |
+
}
|
8998 |
+
}
|
8999 |
+
|
9000 |
+
// Apply converter (if not an equivalence)
|
9001 |
+
if ( conv !== true ) {
|
9002 |
+
|
9003 |
+
// Unless errors are allowed to bubble, catch and return them
|
9004 |
+
if ( conv && s.throws ) {
|
9005 |
+
response = conv( response );
|
9006 |
+
} else {
|
9007 |
+
try {
|
9008 |
+
response = conv( response );
|
9009 |
+
} catch ( e ) {
|
9010 |
+
return {
|
9011 |
+
state: "parsererror",
|
9012 |
+
error: conv ? e : "No conversion from " + prev + " to " + current
|
9013 |
+
};
|
9014 |
+
}
|
9015 |
+
}
|
9016 |
+
}
|
9017 |
+
}
|
9018 |
+
}
|
9019 |
+
}
|
9020 |
+
|
9021 |
+
return { state: "success", data: response };
|
9022 |
+
}
|
9023 |
+
|
9024 |
+
jQuery.extend( {
|
9025 |
+
|
9026 |
+
// Counter for holding the number of active queries
|
9027 |
+
active: 0,
|
9028 |
+
|
9029 |
+
// Last-Modified header cache for next request
|
9030 |
+
lastModified: {},
|
9031 |
+
etag: {},
|
9032 |
+
|
9033 |
+
ajaxSettings: {
|
9034 |
+
url: location.href,
|
9035 |
+
type: "GET",
|
9036 |
+
isLocal: rlocalProtocol.test( location.protocol ),
|
9037 |
+
global: true,
|
9038 |
+
processData: true,
|
9039 |
+
async: true,
|
9040 |
+
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
|
9041 |
+
|
9042 |
+
/*
|
9043 |
+
timeout: 0,
|
9044 |
+
data: null,
|
9045 |
+
dataType: null,
|
9046 |
+
username: null,
|
9047 |
+
password: null,
|
9048 |
+
cache: null,
|
9049 |
+
throws: false,
|
9050 |
+
traditional: false,
|
9051 |
+
headers: {},
|
9052 |
+
*/
|
9053 |
+
|
9054 |
+
accepts: {
|
9055 |
+
"*": allTypes,
|
9056 |
+
text: "text/plain",
|
9057 |
+
html: "text/html",
|
9058 |
+
xml: "application/xml, text/xml",
|
9059 |
+
json: "application/json, text/javascript"
|
9060 |
+
},
|
9061 |
+
|
9062 |
+
contents: {
|
9063 |
+
xml: /\bxml\b/,
|
9064 |
+
html: /\bhtml/,
|
9065 |
+
json: /\bjson\b/
|
9066 |
+
},
|
9067 |
+
|
9068 |
+
responseFields: {
|
9069 |
+
xml: "responseXML",
|
9070 |
+
text: "responseText",
|
9071 |
+
json: "responseJSON"
|
9072 |
+
},
|
9073 |
+
|
9074 |
+
// Data converters
|
9075 |
+
// Keys separate source (or catchall "*") and destination types with a single space
|
9076 |
+
converters: {
|
9077 |
+
|
9078 |
+
// Convert anything to text
|
9079 |
+
"* text": String,
|
9080 |
+
|
9081 |
+
// Text to html (true = no transformation)
|
9082 |
+
"text html": true,
|
9083 |
+
|
9084 |
+
// Evaluate text as a json expression
|
9085 |
+
"text json": JSON.parse,
|
9086 |
+
|
9087 |
+
// Parse text as xml
|
9088 |
+
"text xml": jQuery.parseXML
|
9089 |
+
},
|
9090 |
+
|
9091 |
+
// For options that shouldn't be deep extended:
|
9092 |
+
// you can add your own custom options here if
|
9093 |
+
// and when you create one that shouldn't be
|
9094 |
+
// deep extended (see ajaxExtend)
|
9095 |
+
flatOptions: {
|
9096 |
+
url: true,
|
9097 |
+
context: true
|
9098 |
+
}
|
9099 |
+
},
|
9100 |
+
|
9101 |
+
// Creates a full fledged settings object into target
|
9102 |
+
// with both ajaxSettings and settings fields.
|
9103 |
+
// If target is omitted, writes into ajaxSettings.
|
9104 |
+
ajaxSetup: function( target, settings ) {
|
9105 |
+
return settings ?
|
9106 |
+
|
9107 |
+
// Building a settings object
|
9108 |
+
ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
|
9109 |
+
|
9110 |
+
// Extending ajaxSettings
|
9111 |
+
ajaxExtend( jQuery.ajaxSettings, target );
|
9112 |
+
},
|
9113 |
+
|
9114 |
+
ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
|
9115 |
+
ajaxTransport: addToPrefiltersOrTransports( transports ),
|
9116 |
+
|
9117 |
+
// Main method
|
9118 |
+
ajax: function( url, options ) {
|
9119 |
+
|
9120 |
+
// If url is an object, simulate pre-1.5 signature
|
9121 |
+
if ( typeof url === "object" ) {
|
9122 |
+
options = url;
|
9123 |
+
url = undefined;
|
9124 |
+
}
|
9125 |
+
|
9126 |
+
// Force options to be an object
|
9127 |
+
options = options || {};
|
9128 |
+
|
9129 |
+
var transport,
|
9130 |
+
|
9131 |
+
// URL without anti-cache param
|
9132 |
+
cacheURL,
|
9133 |
+
|
9134 |
+
// Response headers
|
9135 |
+
responseHeadersString,
|
9136 |
+
responseHeaders,
|
9137 |
+
|
9138 |
+
// timeout handle
|
9139 |
+
timeoutTimer,
|
9140 |
+
|
9141 |
+
// Url cleanup var
|
9142 |
+
urlAnchor,
|
9143 |
+
|
9144 |
+
// Request state (becomes false upon send and true upon completion)
|
9145 |
+
completed,
|
9146 |
+
|
9147 |
+
// To know if global events are to be dispatched
|
9148 |
+
fireGlobals,
|
9149 |
+
|
9150 |
+
// Loop variable
|
9151 |
+
i,
|
9152 |
+
|
9153 |
+
// uncached part of the url
|
9154 |
+
uncached,
|
9155 |
+
|
9156 |
+
// Create the final options object
|
9157 |
+
s = jQuery.ajaxSetup( {}, options ),
|
9158 |
+
|
9159 |
+
// Callbacks context
|
9160 |
+
callbackContext = s.context || s,
|
9161 |
+
|
9162 |
+
// Context for global events is callbackContext if it is a DOM node or jQuery collection
|
9163 |
+
globalEventContext = s.context &&
|
9164 |
+
( callbackContext.nodeType || callbackContext.jquery ) ?
|
9165 |
+
jQuery( callbackContext ) :
|
9166 |
+
jQuery.event,
|
9167 |
+
|
9168 |
+
// Deferreds
|
9169 |
+
deferred = jQuery.Deferred(),
|
9170 |
+
completeDeferred = jQuery.Callbacks( "once memory" ),
|
9171 |
+
|
9172 |
+
// Status-dependent callbacks
|
9173 |
+
statusCode = s.statusCode || {},
|
9174 |
+
|
9175 |
+
// Headers (they are sent all at once)
|
9176 |
+
requestHeaders = {},
|
9177 |
+
requestHeadersNames = {},
|
9178 |
+
|
9179 |
+
// Default abort message
|
9180 |
+
strAbort = "canceled",
|
9181 |
+
|
9182 |
+
// Fake xhr
|
9183 |
+
jqXHR = {
|
9184 |
+
readyState: 0,
|
9185 |
+
|
9186 |
+
// Builds headers hashtable if needed
|
9187 |
+
getResponseHeader: function( key ) {
|
9188 |
+
var match;
|
9189 |
+
if ( completed ) {
|
9190 |
+
if ( !responseHeaders ) {
|
9191 |
+
responseHeaders = {};
|
9192 |
+
while ( ( match = rheaders.exec( responseHeadersString ) ) ) {
|
9193 |
+
responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];
|
9194 |
+
}
|
9195 |
+
}
|
9196 |
+
match = responseHeaders[ key.toLowerCase() ];
|
9197 |
+
}
|
9198 |
+
return match == null ? null : match;
|
9199 |
+
},
|
9200 |
+
|
9201 |
+
// Raw string
|
9202 |
+
getAllResponseHeaders: function() {
|
9203 |
+
return completed ? responseHeadersString : null;
|
9204 |
+
},
|
9205 |
+
|
9206 |
+
// Caches the header
|
9207 |
+
setRequestHeader: function( name, value ) {
|
9208 |
+
if ( completed == null ) {
|
9209 |
+
name = requestHeadersNames[ name.toLowerCase() ] =
|
9210 |
+
requestHeadersNames[ name.toLowerCase() ] || name;
|
9211 |
+
requestHeaders[ name ] = value;
|
9212 |
+
}
|
9213 |
+
return this;
|
9214 |
+
},
|
9215 |
+
|
9216 |
+
// Overrides response content-type header
|
9217 |
+
overrideMimeType: function( type ) {
|
9218 |
+
if ( completed == null ) {
|
9219 |
+
s.mimeType = type;
|
9220 |
+
}
|
9221 |
+
return this;
|
9222 |
+
},
|
9223 |
+
|
9224 |
+
// Status-dependent callbacks
|
9225 |
+
statusCode: function( map ) {
|
9226 |
+
var code;
|
9227 |
+
if ( map ) {
|
9228 |
+
if ( completed ) {
|
9229 |
+
|
9230 |
+
// Execute the appropriate callbacks
|
9231 |
+
jqXHR.always( map[ jqXHR.status ] );
|
9232 |
+
} else {
|
9233 |
+
|
9234 |
+
// Lazy-add the new callbacks in a way that preserves old ones
|
9235 |
+
for ( code in map ) {
|
9236 |
+
statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
|
9237 |
+
}
|
9238 |
+
}
|
9239 |
+
}
|
9240 |
+
return this;
|
9241 |
+
},
|
9242 |
+
|
9243 |
+
// Cancel the request
|
9244 |
+
abort: function( statusText ) {
|
9245 |
+
var finalText = statusText || strAbort;
|
9246 |
+
if ( transport ) {
|
9247 |
+
transport.abort( finalText );
|
9248 |
+
}
|
9249 |
+
done( 0, finalText );
|
9250 |
+
return this;
|
9251 |
+
}
|
9252 |
+
};
|
9253 |
+
|
9254 |
+
// Attach deferreds
|
9255 |
+
deferred.promise( jqXHR );
|
9256 |
+
|
9257 |
+
// Add protocol if not provided (prefilters might expect it)
|
9258 |
+
// Handle falsy url in the settings object (#10093: consistency with old signature)
|
9259 |
+
// We also use the url parameter if available
|
9260 |
+
s.url = ( ( url || s.url || location.href ) + "" )
|
9261 |
+
.replace( rprotocol, location.protocol + "//" );
|
9262 |
+
|
9263 |
+
// Alias method option to type as per ticket #12004
|
9264 |
+
s.type = options.method || options.type || s.method || s.type;
|
9265 |
+
|
9266 |
+
// Extract dataTypes list
|
9267 |
+
s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ];
|
9268 |
+
|
9269 |
+
// A cross-domain request is in order when the origin doesn't match the current origin.
|
9270 |
+
if ( s.crossDomain == null ) {
|
9271 |
+
urlAnchor = document.createElement( "a" );
|
9272 |
+
|
9273 |
+
// Support: IE <=8 - 11, Edge 12 - 15
|
9274 |
+
// IE throws exception on accessing the href property if url is malformed,
|
9275 |
+
// e.g. http://example.com:80x/
|
9276 |
+
try {
|
9277 |
+
urlAnchor.href = s.url;
|
9278 |
+
|
9279 |
+
// Support: IE <=8 - 11 only
|
9280 |
+
// Anchor's host property isn't correctly set when s.url is relative
|
9281 |
+
urlAnchor.href = urlAnchor.href;
|
9282 |
+
s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !==
|
9283 |
+
urlAnchor.protocol + "//" + urlAnchor.host;
|
9284 |
+
} catch ( e ) {
|
9285 |
+
|
9286 |
+
// If there is an error parsing the URL, assume it is crossDomain,
|
9287 |
+
// it can be rejected by the transport if it is invalid
|
9288 |
+
s.crossDomain = true;
|
9289 |
+
}
|
9290 |
+
}
|
9291 |
+
|
9292 |
+
// Convert data if not already a string
|
9293 |
+
if ( s.data && s.processData && typeof s.data !== "string" ) {
|
9294 |
+
s.data = jQuery.param( s.data, s.traditional );
|
9295 |
+
}
|
9296 |
+
|
9297 |
+
// Apply prefilters
|
9298 |
+
inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
|
9299 |
+
|
9300 |
+
// If request was aborted inside a prefilter, stop there
|
9301 |
+
if ( completed ) {
|
9302 |
+
return jqXHR;
|
9303 |
+
}
|
9304 |
+
|
9305 |
+
// We can fire global events as of now if asked to
|
9306 |
+
// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
|
9307 |
+
fireGlobals = jQuery.event && s.global;
|
9308 |
+
|
9309 |
+
// Watch for a new set of requests
|
9310 |
+
if ( fireGlobals && jQuery.active++ === 0 ) {
|
9311 |
+
jQuery.event.trigger( "ajaxStart" );
|
9312 |
+
}
|
9313 |
+
|
9314 |
+
// Uppercase the type
|
9315 |
+
s.type = s.type.toUpperCase();
|
9316 |
+
|
9317 |
+
// Determine if request has content
|
9318 |
+
s.hasContent = !rnoContent.test( s.type );
|
9319 |
+
|
9320 |
+
// Save the URL in case we're toying with the If-Modified-Since
|
9321 |
+
// and/or If-None-Match header later on
|
9322 |
+
// Remove hash to simplify url manipulation
|
9323 |
+
cacheURL = s.url.replace( rhash, "" );
|
9324 |
+
|
9325 |
+
// More options handling for requests with no content
|
9326 |
+
if ( !s.hasContent ) {
|
9327 |
+
|
9328 |
+
// Remember the hash so we can put it back
|
9329 |
+
uncached = s.url.slice( cacheURL.length );
|
9330 |
+
|
9331 |
+
// If data is available and should be processed, append data to url
|
9332 |
+
if ( s.data && ( s.processData || typeof s.data === "string" ) ) {
|
9333 |
+
cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data;
|
9334 |
+
|
9335 |
+
// #9682: remove data so that it's not used in an eventual retry
|
9336 |
+
delete s.data;
|
9337 |
+
}
|
9338 |
+
|
9339 |
+
// Add or update anti-cache param if needed
|
9340 |
+
if ( s.cache === false ) {
|
9341 |
+
cacheURL = cacheURL.replace( rantiCache, "$1" );
|
9342 |
+
uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached;
|
9343 |
+
}
|
9344 |
+
|
9345 |
+
// Put hash and anti-cache on the URL that will be requested (gh-1732)
|
9346 |
+
s.url = cacheURL + uncached;
|
9347 |
+
|
9348 |
+
// Change '%20' to '+' if this is encoded form body content (gh-2658)
|
9349 |
+
} else if ( s.data && s.processData &&
|
9350 |
+
( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) {
|
9351 |
+
s.data = s.data.replace( r20, "+" );
|
9352 |
+
}
|
9353 |
+
|
9354 |
+
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
|
9355 |
+
if ( s.ifModified ) {
|
9356 |
+
if ( jQuery.lastModified[ cacheURL ] ) {
|
9357 |
+
jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
|
9358 |
+
}
|
9359 |
+
if ( jQuery.etag[ cacheURL ] ) {
|
9360 |
+
jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
|
9361 |
+
}
|
9362 |
+
}
|
9363 |
+
|
9364 |
+
// Set the correct header, if data is being sent
|
9365 |
+
if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
|
9366 |
+
jqXHR.setRequestHeader( "Content-Type", s.contentType );
|
9367 |
+
}
|
9368 |
+
|
9369 |
+
// Set the Accepts header for the server, depending on the dataType
|
9370 |
+
jqXHR.setRequestHeader(
|
9371 |
+
"Accept",
|
9372 |
+
s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?
|
9373 |
+
s.accepts[ s.dataTypes[ 0 ] ] +
|
9374 |
+
( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
|
9375 |
+
s.accepts[ "*" ]
|
9376 |
+
);
|
9377 |
+
|
9378 |
+
// Check for headers option
|
9379 |
+
for ( i in s.headers ) {
|
9380 |
+
jqXHR.setRequestHeader( i, s.headers[ i ] );
|
9381 |
+
}
|
9382 |
+
|
9383 |
+
// Allow custom headers/mimetypes and early abort
|
9384 |
+
if ( s.beforeSend &&
|
9385 |
+
( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {
|
9386 |
+
|
9387 |
+
// Abort if not done already and return
|
9388 |
+
return jqXHR.abort();
|
9389 |
+
}
|
9390 |
+
|
9391 |
+
// Aborting is no longer a cancellation
|
9392 |
+
strAbort = "abort";
|
9393 |
+
|
9394 |
+
// Install callbacks on deferreds
|
9395 |
+
completeDeferred.add( s.complete );
|
9396 |
+
jqXHR.done( s.success );
|
9397 |
+
jqXHR.fail( s.error );
|
9398 |
+
|
9399 |
+
// Get transport
|
9400 |
+
transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
|
9401 |
+
|
9402 |
+
// If no transport, we auto-abort
|
9403 |
+
if ( !transport ) {
|
9404 |
+
done( -1, "No Transport" );
|
9405 |
+
} else {
|
9406 |
+
jqXHR.readyState = 1;
|
9407 |
+
|
9408 |
+
// Send global event
|
9409 |
+
if ( fireGlobals ) {
|
9410 |
+
globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
|
9411 |
+
}
|
9412 |
+
|
9413 |
+
// If request was aborted inside ajaxSend, stop there
|
9414 |
+
if ( completed ) {
|
9415 |
+
return jqXHR;
|
9416 |
+
}
|
9417 |
+
|
9418 |
+
// Timeout
|
9419 |
+
if ( s.async && s.timeout > 0 ) {
|
9420 |
+
timeoutTimer = window.setTimeout( function() {
|
9421 |
+
jqXHR.abort( "timeout" );
|
9422 |
+
}, s.timeout );
|
9423 |
+
}
|
9424 |
+
|
9425 |
+
try {
|
9426 |
+
completed = false;
|
9427 |
+
transport.send( requestHeaders, done );
|
9428 |
+
} catch ( e ) {
|
9429 |
+
|
9430 |
+
// Rethrow post-completion exceptions
|
9431 |
+
if ( completed ) {
|
9432 |
+
throw e;
|
9433 |
+
}
|
9434 |
+
|
9435 |
+
// Propagate others as results
|
9436 |
+
done( -1, e );
|
9437 |
+
}
|
9438 |
+
}
|
9439 |
+
|
9440 |
+
// Callback for when everything is done
|
9441 |
+
function done( status, nativeStatusText, responses, headers ) {
|
9442 |
+
var isSuccess, success, error, response, modified,
|
9443 |
+
statusText = nativeStatusText;
|
9444 |
+
|
9445 |
+
// Ignore repeat invocations
|
9446 |
+
if ( completed ) {
|
9447 |
+
return;
|
9448 |
+
}
|
9449 |
+
|
9450 |
+
completed = true;
|
9451 |
+
|
9452 |
+
// Clear timeout if it exists
|
9453 |
+
if ( timeoutTimer ) {
|
9454 |
+
window.clearTimeout( timeoutTimer );
|
9455 |
+
}
|
9456 |
+
|
9457 |
+
// Dereference transport for early garbage collection
|
9458 |
+
// (no matter how long the jqXHR object will be used)
|
9459 |
+
transport = undefined;
|
9460 |
+
|
9461 |
+
// Cache response headers
|
9462 |
+
responseHeadersString = headers || "";
|
9463 |
+
|
9464 |
+
// Set readyState
|
9465 |
+
jqXHR.readyState = status > 0 ? 4 : 0;
|
9466 |
+
|
9467 |
+
// Determine if successful
|
9468 |
+
isSuccess = status >= 200 && status < 300 || status === 304;
|
9469 |
+
|
9470 |
+
// Get response data
|
9471 |
+
if ( responses ) {
|
9472 |
+
response = ajaxHandleResponses( s, jqXHR, responses );
|
9473 |
+
}
|
9474 |
+
|
9475 |
+
// Convert no matter what (that way responseXXX fields are always set)
|
9476 |
+
response = ajaxConvert( s, response, jqXHR, isSuccess );
|
9477 |
+
|
9478 |
+
// If successful, handle type chaining
|
9479 |
+
if ( isSuccess ) {
|
9480 |
+
|
9481 |
+
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
|
9482 |
+
if ( s.ifModified ) {
|
9483 |
+
modified = jqXHR.getResponseHeader( "Last-Modified" );
|
9484 |
+
if ( modified ) {
|
9485 |
+
jQuery.lastModified[ cacheURL ] = modified;
|
9486 |
+
}
|
9487 |
+
modified = jqXHR.getResponseHeader( "etag" );
|
9488 |
+
if ( modified ) {
|
9489 |
+
jQuery.etag[ cacheURL ] = modified;
|
9490 |
+
}
|
9491 |
+
}
|
9492 |
+
|
9493 |
+
// if no content
|
9494 |
+
if ( status === 204 || s.type === "HEAD" ) {
|
9495 |
+
statusText = "nocontent";
|
9496 |
+
|
9497 |
+
// if not modified
|
9498 |
+
} else if ( status === 304 ) {
|
9499 |
+
statusText = "notmodified";
|
9500 |
+
|
9501 |
+
// If we have data, let's convert it
|
9502 |
+
} else {
|
9503 |
+
statusText = response.state;
|
9504 |
+
success = response.data;
|
9505 |
+
error = response.error;
|
9506 |
+
isSuccess = !error;
|
9507 |
+
}
|
9508 |
+
} else {
|
9509 |
+
|
9510 |
+
// Extract error from statusText and normalize for non-aborts
|
9511 |
+
error = statusText;
|
9512 |
+
if ( status || !statusText ) {
|
9513 |
+
statusText = "error";
|
9514 |
+
if ( status < 0 ) {
|
9515 |
+
status = 0;
|
9516 |
+
}
|
9517 |
+
}
|
9518 |
+
}
|
9519 |
+
|
9520 |
+
// Set data for the fake xhr object
|
9521 |
+
jqXHR.status = status;
|
9522 |
+
jqXHR.statusText = ( nativeStatusText || statusText ) + "";
|
9523 |
+
|
9524 |
+
// Success/Error
|
9525 |
+
if ( isSuccess ) {
|
9526 |
+
deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
|
9527 |
+
} else {
|
9528 |
+
deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
|
9529 |
+
}
|
9530 |
+
|
9531 |
+
// Status-dependent callbacks
|
9532 |
+
jqXHR.statusCode( statusCode );
|
9533 |
+
statusCode = undefined;
|
9534 |
+
|
9535 |
+
if ( fireGlobals ) {
|
9536 |
+
globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
|
9537 |
+
[ jqXHR, s, isSuccess ? success : error ] );
|
9538 |
+
}
|
9539 |
+
|
9540 |
+
// Complete
|
9541 |
+
completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
|
9542 |
+
|
9543 |
+
if ( fireGlobals ) {
|
9544 |
+
globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
|
9545 |
+
|
9546 |
+
// Handle the global AJAX counter
|
9547 |
+
if ( !( --jQuery.active ) ) {
|
9548 |
+
jQuery.event.trigger( "ajaxStop" );
|
9549 |
+
}
|
9550 |
+
}
|
9551 |
+
}
|
9552 |
+
|
9553 |
+
return jqXHR;
|
9554 |
+
},
|
9555 |
+
|
9556 |
+
getJSON: function( url, data, callback ) {
|
9557 |
+
return jQuery.get( url, data, callback, "json" );
|
9558 |
+
},
|
9559 |
+
|
9560 |
+
getScript: function( url, callback ) {
|
9561 |
+
return jQuery.get( url, undefined, callback, "script" );
|
9562 |
+
}
|
9563 |
+
} );
|
9564 |
+
|
9565 |
+
jQuery.each( [ "get", "post" ], function( i, method ) {
|
9566 |
+
jQuery[ method ] = function( url, data, callback, type ) {
|
9567 |
+
|
9568 |
+
// Shift arguments if data argument was omitted
|
9569 |
+
if ( isFunction( data ) ) {
|
9570 |
+
type = type || callback;
|
9571 |
+
callback = data;
|
9572 |
+
data = undefined;
|
9573 |
+
}
|
9574 |
+
|
9575 |
+
// The url can be an options object (which then must have .url)
|
9576 |
+
return jQuery.ajax( jQuery.extend( {
|
9577 |
+
url: url,
|
9578 |
+
type: method,
|
9579 |
+
dataType: type,
|
9580 |
+
data: data,
|
9581 |
+
success: callback
|
9582 |
+
}, jQuery.isPlainObject( url ) && url ) );
|
9583 |
+
};
|
9584 |
+
} );
|
9585 |
+
|
9586 |
+
|
9587 |
+
jQuery._evalUrl = function( url ) {
|
9588 |
+
return jQuery.ajax( {
|
9589 |
+
url: url,
|
9590 |
+
|
9591 |
+
// Make this explicit, since user can override this through ajaxSetup (#11264)
|
9592 |
+
type: "GET",
|
9593 |
+
dataType: "script",
|
9594 |
+
cache: true,
|
9595 |
+
async: false,
|
9596 |
+
global: false,
|
9597 |
+
"throws": true
|
9598 |
+
} );
|
9599 |
+
};
|
9600 |
+
|
9601 |
+
|
9602 |
+
jQuery.fn.extend( {
|
9603 |
+
wrapAll: function( html ) {
|
9604 |
+
var wrap;
|
9605 |
+
|
9606 |
+
if ( this[ 0 ] ) {
|
9607 |
+
if ( isFunction( html ) ) {
|
9608 |
+
html = html.call( this[ 0 ] );
|
9609 |
+
}
|
9610 |
+
|
9611 |
+
// The elements to wrap the target around
|
9612 |
+
wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
|
9613 |
+
|
9614 |
+
if ( this[ 0 ].parentNode ) {
|
9615 |
+
wrap.insertBefore( this[ 0 ] );
|
9616 |
+
}
|
9617 |
+
|
9618 |
+
wrap.map( function() {
|
9619 |
+
var elem = this;
|
9620 |
+
|
9621 |
+
while ( elem.firstElementChild ) {
|
9622 |
+
elem = elem.firstElementChild;
|
9623 |
+
}
|
9624 |
+
|
9625 |
+
return elem;
|
9626 |
+
} ).append( this );
|
9627 |
+
}
|
9628 |
+
|
9629 |
+
return this;
|
9630 |
+
},
|
9631 |
+
|
9632 |
+
wrapInner: function( html ) {
|
9633 |
+
if ( isFunction( html ) ) {
|
9634 |
+
return this.each( function( i ) {
|
9635 |
+
jQuery( this ).wrapInner( html.call( this, i ) );
|
9636 |
+
} );
|
9637 |
+
}
|
9638 |
+
|
9639 |
+
return this.each( function() {
|
9640 |
+
var self = jQuery( this ),
|
9641 |
+
contents = self.contents();
|
9642 |
+
|
9643 |
+
if ( contents.length ) {
|
9644 |
+
contents.wrapAll( html );
|
9645 |
+
|
9646 |
+
} else {
|
9647 |
+
self.append( html );
|
9648 |
+
}
|
9649 |
+
} );
|
9650 |
+
},
|
9651 |
+
|
9652 |
+
wrap: function( html ) {
|
9653 |
+
var htmlIsFunction = isFunction( html );
|
9654 |
+
|
9655 |
+
return this.each( function( i ) {
|
9656 |
+
jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html );
|
9657 |
+
} );
|
9658 |
+
},
|
9659 |
+
|
9660 |
+
unwrap: function( selector ) {
|
9661 |
+
this.parent( selector ).not( "body" ).each( function() {
|
9662 |
+
jQuery( this ).replaceWith( this.childNodes );
|
9663 |
+
} );
|
9664 |
+
return this;
|
9665 |
+
}
|
9666 |
+
} );
|
9667 |
+
|
9668 |
+
|
9669 |
+
jQuery.expr.pseudos.hidden = function( elem ) {
|
9670 |
+
return !jQuery.expr.pseudos.visible( elem );
|
9671 |
+
};
|
9672 |
+
jQuery.expr.pseudos.visible = function( elem ) {
|
9673 |
+
return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
|
9674 |
+
};
|
9675 |
+
|
9676 |
+
|
9677 |
+
|
9678 |
+
|
9679 |
+
jQuery.ajaxSettings.xhr = function() {
|
9680 |
+
try {
|
9681 |
+
return new window.XMLHttpRequest();
|
9682 |
+
} catch ( e ) {}
|
9683 |
+
};
|
9684 |
+
|
9685 |
+
var xhrSuccessStatus = {
|
9686 |
+
|
9687 |
+
// File protocol always yields status code 0, assume 200
|
9688 |
+
0: 200,
|
9689 |
+
|
9690 |
+
// Support: IE <=9 only
|
9691 |
+
// #1450: sometimes IE returns 1223 when it should be 204
|
9692 |
+
1223: 204
|
9693 |
+
},
|
9694 |
+
xhrSupported = jQuery.ajaxSettings.xhr();
|
9695 |
+
|
9696 |
+
support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
|
9697 |
+
support.ajax = xhrSupported = !!xhrSupported;
|
9698 |
+
|
9699 |
+
jQuery.ajaxTransport( function( options ) {
|
9700 |
+
var callback, errorCallback;
|
9701 |
+
|
9702 |
+
// Cross domain only allowed if supported through XMLHttpRequest
|
9703 |
+
if ( support.cors || xhrSupported && !options.crossDomain ) {
|
9704 |
+
return {
|
9705 |
+
send: function( headers, complete ) {
|
9706 |
+
var i,
|
9707 |
+
xhr = options.xhr();
|
9708 |
+
|
9709 |
+
xhr.open(
|
9710 |
+
options.type,
|
9711 |
+
options.url,
|
9712 |
+
options.async,
|
9713 |
+
options.username,
|
9714 |
+
options.password
|
9715 |
+
);
|
9716 |
+
|
9717 |
+
// Apply custom fields if provided
|
9718 |
+
if ( options.xhrFields ) {
|
9719 |
+
for ( i in options.xhrFields ) {
|
9720 |
+
xhr[ i ] = options.xhrFields[ i ];
|
9721 |
+
}
|
9722 |
+
}
|
9723 |
+
|
9724 |
+
// Override mime type if needed
|
9725 |
+
if ( options.mimeType && xhr.overrideMimeType ) {
|
9726 |
+
xhr.overrideMimeType( options.mimeType );
|
9727 |
+
}
|
9728 |
+
|
9729 |
+
// X-Requested-With header
|
9730 |
+
// For cross-domain requests, seeing as conditions for a preflight are
|
9731 |
+
// akin to a jigsaw puzzle, we simply never set it to be sure.
|
9732 |
+
// (it can always be set on a per-request basis or even using ajaxSetup)
|
9733 |
+
// For same-domain requests, won't change header if already provided.
|
9734 |
+
if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) {
|
9735 |
+
headers[ "X-Requested-With" ] = "XMLHttpRequest";
|
9736 |
+
}
|
9737 |
+
|
9738 |
+
// Set headers
|
9739 |
+
for ( i in headers ) {
|
9740 |
+
xhr.setRequestHeader( i, headers[ i ] );
|
9741 |
+
}
|
9742 |
+
|
9743 |
+
// Callback
|
9744 |
+
callback = function( type ) {
|
9745 |
+
return function() {
|
9746 |
+
if ( callback ) {
|
9747 |
+
callback = errorCallback = xhr.onload =
|
9748 |
+
xhr.onerror = xhr.onabort = xhr.ontimeout =
|
9749 |
+
xhr.onreadystatechange = null;
|
9750 |
+
|
9751 |
+
if ( type === "abort" ) {
|
9752 |
+
xhr.abort();
|
9753 |
+
} else if ( type === "error" ) {
|
9754 |
+
|
9755 |
+
// Support: IE <=9 only
|
9756 |
+
// On a manual native abort, IE9 throws
|
9757 |
+
// errors on any property access that is not readyState
|
9758 |
+
if ( typeof xhr.status !== "number" ) {
|
9759 |
+
complete( 0, "error" );
|
9760 |
+
} else {
|
9761 |
+
complete(
|
9762 |
+
|
9763 |
+
// File: protocol always yields status 0; see #8605, #14207
|
9764 |
+
xhr.status,
|
9765 |
+
xhr.statusText
|
9766 |
+
);
|
9767 |
+
}
|
9768 |
+
} else {
|
9769 |
+
complete(
|
9770 |
+
xhrSuccessStatus[ xhr.status ] || xhr.status,
|
9771 |
+
xhr.statusText,
|
9772 |
+
|
9773 |
+
// Support: IE <=9 only
|
9774 |
+
// IE9 has no XHR2 but throws on binary (trac-11426)
|
9775 |
+
// For XHR2 non-text, let the caller handle it (gh-2498)
|
9776 |
+
( xhr.responseType || "text" ) !== "text" ||
|
9777 |
+
typeof xhr.responseText !== "string" ?
|
9778 |
+
{ binary: xhr.response } :
|
9779 |
+
{ text: xhr.responseText },
|
9780 |
+
xhr.getAllResponseHeaders()
|
9781 |
+
);
|
9782 |
+
}
|
9783 |
+
}
|
9784 |
+
};
|
9785 |
+
};
|
9786 |
+
|
9787 |
+
// Listen to events
|
9788 |
+
xhr.onload = callback();
|
9789 |
+
errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" );
|
9790 |
+
|
9791 |
+
// Support: IE 9 only
|
9792 |
+
// Use onreadystatechange to replace onabort
|
9793 |
+
// to handle uncaught aborts
|
9794 |
+
if ( xhr.onabort !== undefined ) {
|
9795 |
+
xhr.onabort = errorCallback;
|
9796 |
+
} else {
|
9797 |
+
xhr.onreadystatechange = function() {
|
9798 |
+
|
9799 |
+
// Check readyState before timeout as it changes
|
9800 |
+
if ( xhr.readyState === 4 ) {
|
9801 |
+
|
9802 |
+
// Allow onerror to be called first,
|
9803 |
+
// but that will not handle a native abort
|
9804 |
+
// Also, save errorCallback to a variable
|
9805 |
+
// as xhr.onerror cannot be accessed
|
9806 |
+
window.setTimeout( function() {
|
9807 |
+
if ( callback ) {
|
9808 |
+
errorCallback();
|
9809 |
+
}
|
9810 |
+
} );
|
9811 |
+
}
|
9812 |
+
};
|
9813 |
+
}
|
9814 |
+
|
9815 |
+
// Create the abort callback
|
9816 |
+
callback = callback( "abort" );
|
9817 |
+
|
9818 |
+
try {
|
9819 |
+
|
9820 |
+
// Do send the request (this may raise an exception)
|
9821 |
+
xhr.send( options.hasContent && options.data || null );
|
9822 |
+
} catch ( e ) {
|
9823 |
+
|
9824 |
+
// #14683: Only rethrow if this hasn't been notified as an error yet
|
9825 |
+
if ( callback ) {
|
9826 |
+
throw e;
|
9827 |
+
}
|
9828 |
+
}
|
9829 |
+
},
|
9830 |
+
|
9831 |
+
abort: function() {
|
9832 |
+
if ( callback ) {
|
9833 |
+
callback();
|
9834 |
+
}
|
9835 |
+
}
|
9836 |
+
};
|
9837 |
+
}
|
9838 |
+
} );
|
9839 |
+
|
9840 |
+
|
9841 |
+
|
9842 |
+
|
9843 |
+
// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)
|
9844 |
+
jQuery.ajaxPrefilter( function( s ) {
|
9845 |
+
if ( s.crossDomain ) {
|
9846 |
+
s.contents.script = false;
|
9847 |
+
}
|
9848 |
+
} );
|
9849 |
+
|
9850 |
+
// Install script dataType
|
9851 |
+
jQuery.ajaxSetup( {
|
9852 |
+
accepts: {
|
9853 |
+
script: "text/javascript, application/javascript, " +
|
9854 |
+
"application/ecmascript, application/x-ecmascript"
|
9855 |
+
},
|
9856 |
+
contents: {
|
9857 |
+
script: /\b(?:java|ecma)script\b/
|
9858 |
+
},
|
9859 |
+
converters: {
|
9860 |
+
"text script": function( text ) {
|
9861 |
+
jQuery.globalEval( text );
|
9862 |
+
return text;
|
9863 |
+
}
|
9864 |
+
}
|
9865 |
+
} );
|
9866 |
+
|
9867 |
+
// Handle cache's special case and crossDomain
|
9868 |
+
jQuery.ajaxPrefilter( "script", function( s ) {
|
9869 |
+
if ( s.cache === undefined ) {
|
9870 |
+
s.cache = false;
|
9871 |
+
}
|
9872 |
+
if ( s.crossDomain ) {
|
9873 |
+
s.type = "GET";
|
9874 |
+
}
|
9875 |
+
} );
|
9876 |
+
|
9877 |
+
// Bind script tag hack transport
|
9878 |
+
jQuery.ajaxTransport( "script", function( s ) {
|
9879 |
+
|
9880 |
+
// This transport only deals with cross domain requests
|
9881 |
+
if ( s.crossDomain ) {
|
9882 |
+
var script, callback;
|
9883 |
+
return {
|
9884 |
+
send: function( _, complete ) {
|
9885 |
+
script = jQuery( "<script>" ).prop( {
|
9886 |
+
charset: s.scriptCharset,
|
9887 |
+
src: s.url
|
9888 |
+
} ).on(
|
9889 |
+
"load error",
|
9890 |
+
callback = function( evt ) {
|
9891 |
+
script.remove();
|
9892 |
+
callback = null;
|
9893 |
+
if ( evt ) {
|
9894 |
+
complete( evt.type === "error" ? 404 : 200, evt.type );
|
9895 |
+
}
|
9896 |
+
}
|
9897 |
+
);
|
9898 |
+
|
9899 |
+
// Use native DOM manipulation to avoid our domManip AJAX trickery
|
9900 |
+
document.head.appendChild( script[ 0 ] );
|
9901 |
+
},
|
9902 |
+
abort: function() {
|
9903 |
+
if ( callback ) {
|
9904 |
+
callback();
|
9905 |
+
}
|
9906 |
+
}
|
9907 |
+
};
|
9908 |
+
}
|
9909 |
+
} );
|
9910 |
+
|
9911 |
+
|
9912 |
+
|
9913 |
+
|
9914 |
+
var oldCallbacks = [],
|
9915 |
+
rjsonp = /(=)\?(?=&|$)|\?\?/;
|
9916 |
+
|
9917 |
+
// Default jsonp settings
|
9918 |
+
jQuery.ajaxSetup( {
|
9919 |
+
jsonp: "callback",
|
9920 |
+
jsonpCallback: function() {
|
9921 |
+
var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
|
9922 |
+
this[ callback ] = true;
|
9923 |
+
return callback;
|
9924 |
+
}
|
9925 |
+
} );
|
9926 |
+
|
9927 |
+
// Detect, normalize options and install callbacks for jsonp requests
|
9928 |
+
jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
|
9929 |
+
|
9930 |
+
var callbackName, overwritten, responseContainer,
|
9931 |
+
jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
|
9932 |
+
"url" :
|
9933 |
+
typeof s.data === "string" &&
|
9934 |
+
( s.contentType || "" )
|
9935 |
+
.indexOf( "application/x-www-form-urlencoded" ) === 0 &&
|
9936 |
+
rjsonp.test( s.data ) && "data"
|
9937 |
+
);
|
9938 |
+
|
9939 |
+
// Handle iff the expected data type is "jsonp" or we have a parameter to set
|
9940 |
+
if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
|
9941 |
+
|
9942 |
+
// Get callback name, remembering preexisting value associated with it
|
9943 |
+
callbackName = s.jsonpCallback = isFunction( s.jsonpCallback ) ?
|
9944 |
+
s.jsonpCallback() :
|
9945 |
+
s.jsonpCallback;
|
9946 |
+
|
9947 |
+
// Insert callback into url or form data
|
9948 |
+
if ( jsonProp ) {
|
9949 |
+
s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
|
9950 |
+
} else if ( s.jsonp !== false ) {
|
9951 |
+
s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
|
9952 |
+
}
|
9953 |
+
|
9954 |
+
// Use data converter to retrieve json after script execution
|
9955 |
+
s.converters[ "script json" ] = function() {
|
9956 |
+
if ( !responseContainer ) {
|
9957 |
+
jQuery.error( callbackName + " was not called" );
|
9958 |
+
}
|
9959 |
+
return responseContainer[ 0 ];
|
9960 |
+
};
|
9961 |
+
|
9962 |
+
// Force json dataType
|
9963 |
+
s.dataTypes[ 0 ] = "json";
|
9964 |
+
|
9965 |
+
// Install callback
|
9966 |
+
overwritten = window[ callbackName ];
|
9967 |
+
window[ callbackName ] = function() {
|
9968 |
+
responseContainer = arguments;
|
9969 |
+
};
|
9970 |
+
|
9971 |
+
// Clean-up function (fires after converters)
|
9972 |
+
jqXHR.always( function() {
|
9973 |
+
|
9974 |
+
// If previous value didn't exist - remove it
|
9975 |
+
if ( overwritten === undefined ) {
|
9976 |
+
jQuery( window ).removeProp( callbackName );
|
9977 |
+
|
9978 |
+
// Otherwise restore preexisting value
|
9979 |
+
} else {
|
9980 |
+
window[ callbackName ] = overwritten;
|
9981 |
+
}
|
9982 |
+
|
9983 |
+
// Save back as free
|
9984 |
+
if ( s[ callbackName ] ) {
|
9985 |
+
|
9986 |
+
// Make sure that re-using the options doesn't screw things around
|
9987 |
+
s.jsonpCallback = originalSettings.jsonpCallback;
|
9988 |
+
|
9989 |
+
// Save the callback name for future use
|
9990 |
+
oldCallbacks.push( callbackName );
|
9991 |
+
}
|
9992 |
+
|
9993 |
+
// Call if it was a function and we have a response
|
9994 |
+
if ( responseContainer && isFunction( overwritten ) ) {
|
9995 |
+
overwritten( responseContainer[ 0 ] );
|
9996 |
+
}
|
9997 |
+
|
9998 |
+
responseContainer = overwritten = undefined;
|
9999 |
+
} );
|
10000 |
+
|
10001 |
+
// Delegate to script
|
10002 |
+
return "script";
|
10003 |
+
}
|
10004 |
+
} );
|
10005 |
+
|
10006 |
+
|
10007 |
+
|
10008 |
+
|
10009 |
+
// Support: Safari 8 only
|
10010 |
+
// In Safari 8 documents created via document.implementation.createHTMLDocument
|
10011 |
+
// collapse sibling forms: the second one becomes a child of the first one.
|
10012 |
+
// Because of that, this security measure has to be disabled in Safari 8.
|
10013 |
+
// https://bugs.webkit.org/show_bug.cgi?id=137337
|
10014 |
+
support.createHTMLDocument = ( function() {
|
10015 |
+
var body = document.implementation.createHTMLDocument( "" ).body;
|
10016 |
+
body.innerHTML = "<form></form><form></form>";
|
10017 |
+
return body.childNodes.length === 2;
|
10018 |
+
} )();
|
10019 |
+
|
10020 |
+
|
10021 |
+
// Argument "data" should be string of html
|
10022 |
+
// context (optional): If specified, the fragment will be created in this context,
|
10023 |
+
// defaults to document
|
10024 |
+
// keepScripts (optional): If true, will include scripts passed in the html string
|
10025 |
+
jQuery.parseHTML = function( data, context, keepScripts ) {
|
10026 |
+
if ( typeof data !== "string" ) {
|
10027 |
+
return [];
|
10028 |
+
}
|
10029 |
+
if ( typeof context === "boolean" ) {
|
10030 |
+
keepScripts = context;
|
10031 |
+
context = false;
|
10032 |
+
}
|
10033 |
+
|
10034 |
+
var base, parsed, scripts;
|
10035 |
+
|
10036 |
+
if ( !context ) {
|
10037 |
+
|
10038 |
+
// Stop scripts or inline event handlers from being executed immediately
|
10039 |
+
// by using document.implementation
|
10040 |
+
if ( support.createHTMLDocument ) {
|
10041 |
+
context = document.implementation.createHTMLDocument( "" );
|
10042 |
+
|
10043 |
+
// Set the base href for the created document
|
10044 |
+
// so any parsed elements with URLs
|
10045 |
+
// are based on the document's URL (gh-2965)
|
10046 |
+
base = context.createElement( "base" );
|
10047 |
+
base.href = document.location.href;
|
10048 |
+
context.head.appendChild( base );
|
10049 |
+
} else {
|
10050 |
+
context = document;
|
10051 |
+
}
|
10052 |
+
}
|
10053 |
+
|
10054 |
+
parsed = rsingleTag.exec( data );
|
10055 |
+
scripts = !keepScripts && [];
|
10056 |
+
|
10057 |
+
// Single tag
|
10058 |
+
if ( parsed ) {
|
10059 |
+
return [ context.createElement( parsed[ 1 ] ) ];
|
10060 |
+
}
|
10061 |
+
|
10062 |
+
parsed = buildFragment( [ data ], context, scripts );
|
10063 |
+
|
10064 |
+
if ( scripts && scripts.length ) {
|
10065 |
+
jQuery( scripts ).remove();
|
10066 |
+
}
|
10067 |
+
|
10068 |
+
return jQuery.merge( [], parsed.childNodes );
|
10069 |
+
};
|
10070 |
+
|
10071 |
+
|
10072 |
+
/**
|
10073 |
+
* Load a url into a page
|
10074 |
+
*/
|
10075 |
+
jQuery.fn.load = function( url, params, callback ) {
|
10076 |
+
var selector, type, response,
|
10077 |
+
self = this,
|
10078 |
+
off = url.indexOf( " " );
|
10079 |
+
|
10080 |
+
if ( off > -1 ) {
|
10081 |
+
selector = stripAndCollapse( url.slice( off ) );
|
10082 |
+
url = url.slice( 0, off );
|
10083 |
+
}
|
10084 |
+
|
10085 |
+
// If it's a function
|
10086 |
+
if ( isFunction( params ) ) {
|
10087 |
+
|
10088 |
+
// We assume that it's the callback
|
10089 |
+
callback = params;
|
10090 |
+
params = undefined;
|
10091 |
+
|
10092 |
+
// Otherwise, build a param string
|
10093 |
+
} else if ( params && typeof params === "object" ) {
|
10094 |
+
type = "POST";
|
10095 |
+
}
|
10096 |
+
|
10097 |
+
// If we have elements to modify, make the request
|
10098 |
+
if ( self.length > 0 ) {
|
10099 |
+
jQuery.ajax( {
|
10100 |
+
url: url,
|
10101 |
+
|
10102 |
+
// If "type" variable is undefined, then "GET" method will be used.
|
10103 |
+
// Make value of this field explicit since
|
10104 |
+
// user can override it through ajaxSetup method
|
10105 |
+
type: type || "GET",
|
10106 |
+
dataType: "html",
|
10107 |
+
data: params
|
10108 |
+
} ).done( function( responseText ) {
|
10109 |
+
|
10110 |
+
// Save response for use in complete callback
|
10111 |
+
response = arguments;
|
10112 |
+
|
10113 |
+
self.html( selector ?
|
10114 |
+
|
10115 |
+
// If a selector was specified, locate the right elements in a dummy div
|
10116 |
+
// Exclude scripts to avoid IE 'Permission Denied' errors
|
10117 |
+
jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :
|
10118 |
+
|
10119 |
+
// Otherwise use the full result
|
10120 |
+
responseText );
|
10121 |
+
|
10122 |
+
// If the request succeeds, this function gets "data", "status", "jqXHR"
|
10123 |
+
// but they are ignored because response was set above.
|
10124 |
+
// If it fails, this function gets "jqXHR", "status", "error"
|
10125 |
+
} ).always( callback && function( jqXHR, status ) {
|
10126 |
+
self.each( function() {
|
10127 |
+
callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );
|
10128 |
+
} );
|
10129 |
+
} );
|
10130 |
+
}
|
10131 |
+
|
10132 |
+
return this;
|
10133 |
+
};
|
10134 |
+
|
10135 |
+
|
10136 |
+
|
10137 |
+
|
10138 |
+
// Attach a bunch of functions for handling common AJAX events
|
10139 |
+
jQuery.each( [
|
10140 |
+
"ajaxStart",
|
10141 |
+
"ajaxStop",
|
10142 |
+
"ajaxComplete",
|
10143 |
+
"ajaxError",
|
10144 |
+
"ajaxSuccess",
|
10145 |
+
"ajaxSend"
|
10146 |
+
], function( i, type ) {
|
10147 |
+
jQuery.fn[ type ] = function( fn ) {
|
10148 |
+
return this.on( type, fn );
|
10149 |
+
};
|
10150 |
+
} );
|
10151 |
+
|
10152 |
+
|
10153 |
+
|
10154 |
+
|
10155 |
+
jQuery.expr.pseudos.animated = function( elem ) {
|
10156 |
+
return jQuery.grep( jQuery.timers, function( fn ) {
|
10157 |
+
return elem === fn.elem;
|
10158 |
+
} ).length;
|
10159 |
+
};
|
10160 |
+
|
10161 |
+
|
10162 |
+
|
10163 |
+
|
10164 |
+
jQuery.offset = {
|
10165 |
+
setOffset: function( elem, options, i ) {
|
10166 |
+
var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
|
10167 |
+
position = jQuery.css( elem, "position" ),
|
10168 |
+
curElem = jQuery( elem ),
|
10169 |
+
props = {};
|
10170 |
+
|
10171 |
+
// Set position first, in-case top/left are set even on static elem
|
10172 |
+
if ( position === "static" ) {
|
10173 |
+
elem.style.position = "relative";
|
10174 |
+
}
|
10175 |
+
|
10176 |
+
curOffset = curElem.offset();
|
10177 |
+
curCSSTop = jQuery.css( elem, "top" );
|
10178 |
+
curCSSLeft = jQuery.css( elem, "left" );
|
10179 |
+
calculatePosition = ( position === "absolute" || position === "fixed" ) &&
|
10180 |
+
( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -1;
|
10181 |
+
|
10182 |
+
// Need to be able to calculate position if either
|
10183 |
+
// top or left is auto and position is either absolute or fixed
|
10184 |
+
if ( calculatePosition ) {
|
10185 |
+
curPosition = curElem.position();
|
10186 |
+
curTop = curPosition.top;
|
10187 |
+
curLeft = curPosition.left;
|
10188 |
+
|
10189 |
+
} else {
|
10190 |
+
curTop = parseFloat( curCSSTop ) || 0;
|
10191 |
+
curLeft = parseFloat( curCSSLeft ) || 0;
|
10192 |
+
}
|
10193 |
+
|
10194 |
+
if ( isFunction( options ) ) {
|
10195 |
+
|
10196 |
+
// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
|
10197 |
+
options = options.call( elem, i, jQuery.extend( {}, curOffset ) );
|
10198 |
+
}
|
10199 |
+
|
10200 |
+
if ( options.top != null ) {
|
10201 |
+
props.top = ( options.top - curOffset.top ) + curTop;
|
10202 |
+
}
|
10203 |
+
if ( options.left != null ) {
|
10204 |
+
props.left = ( options.left - curOffset.left ) + curLeft;
|
10205 |
+
}
|
10206 |
+
|
10207 |
+
if ( "using" in options ) {
|
10208 |
+
options.using.call( elem, props );
|
10209 |
+
|
10210 |
+
} else {
|
10211 |
+
curElem.css( props );
|
10212 |
+
}
|
10213 |
+
}
|
10214 |
+
};
|
10215 |
+
|
10216 |
+
jQuery.fn.extend( {
|
10217 |
+
|
10218 |
+
// offset() relates an element's border box to the document origin
|
10219 |
+
offset: function( options ) {
|
10220 |
+
|
10221 |
+
// Preserve chaining for setter
|
10222 |
+
if ( arguments.length ) {
|
10223 |
+
return options === undefined ?
|
10224 |
+
this :
|
10225 |
+
this.each( function( i ) {
|
10226 |
+
jQuery.offset.setOffset( this, options, i );
|
10227 |
+
} );
|
10228 |
+
}
|
10229 |
+
|
10230 |
+
var rect, win,
|
10231 |
+
elem = this[ 0 ];
|
10232 |
+
|
10233 |
+
if ( !elem ) {
|
10234 |
+
return;
|
10235 |
+
}
|
10236 |
+
|
10237 |
+
// Return zeros for disconnected and hidden (display: none) elements (gh-2310)
|
10238 |
+
// Support: IE <=11 only
|
10239 |
+
// Running getBoundingClientRect on a
|
10240 |
+
// disconnected node in IE throws an error
|
10241 |
+
if ( !elem.getClientRects().length ) {
|
10242 |
+
return { top: 0, left: 0 };
|
10243 |
+
}
|
10244 |
+
|
10245 |
+
// Get document-relative position by adding viewport scroll to viewport-relative gBCR
|
10246 |
+
rect = elem.getBoundingClientRect();
|
10247 |
+
win = elem.ownerDocument.defaultView;
|
10248 |
+
return {
|
10249 |
+
top: rect.top + win.pageYOffset,
|
10250 |
+
left: rect.left + win.pageXOffset
|
10251 |
+
};
|
10252 |
+
},
|
10253 |
+
|
10254 |
+
// position() relates an element's margin box to its offset parent's padding box
|
10255 |
+
// This corresponds to the behavior of CSS absolute positioning
|
10256 |
+
position: function() {
|
10257 |
+
if ( !this[ 0 ] ) {
|
10258 |
+
return;
|
10259 |
+
}
|
10260 |
+
|
10261 |
+
var offsetParent, offset, doc,
|
10262 |
+
elem = this[ 0 ],
|
10263 |
+
parentOffset = { top: 0, left: 0 };
|
10264 |
+
|
10265 |
+
// position:fixed elements are offset from the viewport, which itself always has zero offset
|
10266 |
+
if ( jQuery.css( elem, "position" ) === "fixed" ) {
|
10267 |
+
|
10268 |
+
// Assume position:fixed implies availability of getBoundingClientRect
|
10269 |
+
offset = elem.getBoundingClientRect();
|
10270 |
+
|
10271 |
+
} else {
|
10272 |
+
offset = this.offset();
|
10273 |
+
|
10274 |
+
// Account for the *real* offset parent, which can be the document or its root element
|
10275 |
+
// when a statically positioned element is identified
|
10276 |
+
doc = elem.ownerDocument;
|
10277 |
+
offsetParent = elem.offsetParent || doc.documentElement;
|
10278 |
+
while ( offsetParent &&
|
10279 |
+
( offsetParent === doc.body || offsetParent === doc.documentElement ) &&
|
10280 |
+
jQuery.css( offsetParent, "position" ) === "static" ) {
|
10281 |
+
|
10282 |
+
offsetParent = offsetParent.parentNode;
|
10283 |
+
}
|
10284 |
+
if ( offsetParent && offsetParent !== elem && offsetParent.nodeType === 1 ) {
|
10285 |
+
|
10286 |
+
// Incorporate borders into its offset, since they are outside its content origin
|
10287 |
+
parentOffset = jQuery( offsetParent ).offset();
|
10288 |
+
parentOffset.top += jQuery.css( offsetParent, "borderTopWidth", true );
|
10289 |
+
parentOffset.left += jQuery.css( offsetParent, "borderLeftWidth", true );
|
10290 |
+
}
|
10291 |
+
}
|
10292 |
+
|
10293 |
+
// Subtract parent offsets and element margins
|
10294 |
+
return {
|
10295 |
+
top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
|
10296 |
+
left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
|
10297 |
+
};
|
10298 |
+
},
|
10299 |
+
|
10300 |
+
// This method will return documentElement in the following cases:
|
10301 |
+
// 1) For the element inside the iframe without offsetParent, this method will return
|
10302 |
+
// documentElement of the parent window
|
10303 |
+
// 2) For the hidden or detached element
|
10304 |
+
// 3) For body or html element, i.e. in case of the html node - it will return itself
|
10305 |
+
//
|
10306 |
+
// but those exceptions were never presented as a real life use-cases
|
10307 |
+
// and might be considered as more preferable results.
|
10308 |
+
//
|
10309 |
+
// This logic, however, is not guaranteed and can change at any point in the future
|
10310 |
+
offsetParent: function() {
|
10311 |
+
return this.map( function() {
|
10312 |
+
var offsetParent = this.offsetParent;
|
10313 |
+
|
10314 |
+
while ( offsetParent && jQuery.css( offsetParent, "position" ) === "static" ) {
|
10315 |
+
offsetParent = offsetParent.offsetParent;
|
10316 |
+
}
|
10317 |
+
|
10318 |
+
return offsetParent || documentElement;
|
10319 |
+
} );
|
10320 |
+
}
|
10321 |
+
} );
|
10322 |
+
|
10323 |
+
// Create scrollLeft and scrollTop methods
|
10324 |
+
jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
|
10325 |
+
var top = "pageYOffset" === prop;
|
10326 |
+
|
10327 |
+
jQuery.fn[ method ] = function( val ) {
|
10328 |
+
return access( this, function( elem, method, val ) {
|
10329 |
+
|
10330 |
+
// Coalesce documents and windows
|
10331 |
+
var win;
|
10332 |
+
if ( isWindow( elem ) ) {
|
10333 |
+
win = elem;
|
10334 |
+
} else if ( elem.nodeType === 9 ) {
|
10335 |
+
win = elem.defaultView;
|
10336 |
+
}
|
10337 |
+
|
10338 |
+
if ( val === undefined ) {
|
10339 |
+
return win ? win[ prop ] : elem[ method ];
|
10340 |
+
}
|
10341 |
+
|
10342 |
+
if ( win ) {
|
10343 |
+
win.scrollTo(
|
10344 |
+
!top ? val : win.pageXOffset,
|
10345 |
+
top ? val : win.pageYOffset
|
10346 |
+
);
|
10347 |
+
|
10348 |
+
} else {
|
10349 |
+
elem[ method ] = val;
|
10350 |
+
}
|
10351 |
+
}, method, val, arguments.length );
|
10352 |
+
};
|
10353 |
+
} );
|
10354 |
+
|
10355 |
+
// Support: Safari <=7 - 9.1, Chrome <=37 - 49
|
10356 |
+
// Add the top/left cssHooks using jQuery.fn.position
|
10357 |
+
// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
|
10358 |
+
// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347
|
10359 |
+
// getComputedStyle returns percent when specified for top/left/bottom/right;
|
10360 |
+
// rather than make the css module depend on the offset module, just check for it here
|
10361 |
+
jQuery.each( [ "top", "left" ], function( i, prop ) {
|
10362 |
+
jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
|
10363 |
+
function( elem, computed ) {
|
10364 |
+
if ( computed ) {
|
10365 |
+
computed = curCSS( elem, prop );
|
10366 |
+
|
10367 |
+
// If curCSS returns percentage, fallback to offset
|
10368 |
+
return rnumnonpx.test( computed ) ?
|
10369 |
+
jQuery( elem ).position()[ prop ] + "px" :
|
10370 |
+
computed;
|
10371 |
+
}
|
10372 |
+
}
|
10373 |
+
);
|
10374 |
+
} );
|
10375 |
+
|
10376 |
+
|
10377 |
+
// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
|
10378 |
+
jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
|
10379 |
+
jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name },
|
10380 |
+
function( defaultExtra, funcName ) {
|
10381 |
+
|
10382 |
+
// Margin is only for outerHeight, outerWidth
|
10383 |
+
jQuery.fn[ funcName ] = function( margin, value ) {
|
10384 |
+
var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
|
10385 |
+
extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
|
10386 |
+
|
10387 |
+
return access( this, function( elem, type, value ) {
|
10388 |
+
var doc;
|
10389 |
+
|
10390 |
+
if ( isWindow( elem ) ) {
|
10391 |
+
|
10392 |
+
// $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)
|
10393 |
+
return funcName.indexOf( "outer" ) === 0 ?
|
10394 |
+
elem[ "inner" + name ] :
|
10395 |
+
elem.document.documentElement[ "client" + name ];
|
10396 |
+
}
|
10397 |
+
|
10398 |
+
// Get document width or height
|
10399 |
+
if ( elem.nodeType === 9 ) {
|
10400 |
+
doc = elem.documentElement;
|
10401 |
+
|
10402 |
+
// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
|
10403 |
+
// whichever is greatest
|
10404 |
+
return Math.max(
|
10405 |
+
elem.body[ "scroll" + name ], doc[ "scroll" + name ],
|
10406 |
+
elem.body[ "offset" + name ], doc[ "offset" + name ],
|
10407 |
+
doc[ "client" + name ]
|
10408 |
+
);
|
10409 |
+
}
|
10410 |
+
|
10411 |
+
return value === undefined ?
|
10412 |
+
|
10413 |
+
// Get width or height on the element, requesting but not forcing parseFloat
|
10414 |
+
jQuery.css( elem, type, extra ) :
|
10415 |
+
|
10416 |
+
// Set width or height on the element
|
10417 |
+
jQuery.style( elem, type, value, extra );
|
10418 |
+
}, type, chainable ? margin : undefined, chainable );
|
10419 |
+
};
|
10420 |
+
} );
|
10421 |
+
} );
|
10422 |
+
|
10423 |
+
|
10424 |
+
jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " +
|
10425 |
+
"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
|
10426 |
+
"change select submit keydown keypress keyup contextmenu" ).split( " " ),
|
10427 |
+
function( i, name ) {
|
10428 |
+
|
10429 |
+
// Handle event binding
|
10430 |
+
jQuery.fn[ name ] = function( data, fn ) {
|
10431 |
+
return arguments.length > 0 ?
|
10432 |
+
this.on( name, null, data, fn ) :
|
10433 |
+
this.trigger( name );
|
10434 |
+
};
|
10435 |
+
} );
|
10436 |
+
|
10437 |
+
jQuery.fn.extend( {
|
10438 |
+
hover: function( fnOver, fnOut ) {
|
10439 |
+
return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
|
10440 |
+
}
|
10441 |
+
} );
|
10442 |
+
|
10443 |
+
|
10444 |
+
|
10445 |
+
|
10446 |
+
jQuery.fn.extend( {
|
10447 |
+
|
10448 |
+
bind: function( types, data, fn ) {
|
10449 |
+
return this.on( types, null, data, fn );
|
10450 |
+
},
|
10451 |
+
unbind: function( types, fn ) {
|
10452 |
+
return this.off( types, null, fn );
|
10453 |
+
},
|
10454 |
+
|
10455 |
+
delegate: function( selector, types, data, fn ) {
|
10456 |
+
return this.on( types, selector, data, fn );
|
10457 |
+
},
|
10458 |
+
undelegate: function( selector, types, fn ) {
|
10459 |
+
|
10460 |
+
// ( namespace ) or ( selector, types [, fn] )
|
10461 |
+
return arguments.length === 1 ?
|
10462 |
+
this.off( selector, "**" ) :
|
10463 |
+
this.off( types, selector || "**", fn );
|
10464 |
+
}
|
10465 |
+
} );
|
10466 |
+
|
10467 |
+
// Bind a function to a context, optionally partially applying any
|
10468 |
+
// arguments.
|
10469 |
+
// jQuery.proxy is deprecated to promote standards (specifically Function#bind)
|
10470 |
+
// However, it is not slated for removal any time soon
|
10471 |
+
jQuery.proxy = function( fn, context ) {
|
10472 |
+
var tmp, args, proxy;
|
10473 |
+
|
10474 |
+
if ( typeof context === "string" ) {
|
10475 |
+
tmp = fn[ context ];
|
10476 |
+
context = fn;
|
10477 |
+
fn = tmp;
|
10478 |
+
}
|
10479 |
+
|
10480 |
+
// Quick check to determine if target is callable, in the spec
|
10481 |
+
// this throws a TypeError, but we will just return undefined.
|
10482 |
+
if ( !isFunction( fn ) ) {
|
10483 |
+
return undefined;
|
10484 |
+
}
|
10485 |
+
|
10486 |
+
// Simulated bind
|
10487 |
+
args = slice.call( arguments, 2 );
|
10488 |
+
proxy = function() {
|
10489 |
+
return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
|
10490 |
+
};
|
10491 |
+
|
10492 |
+
// Set the guid of unique handler to the same of original handler, so it can be removed
|
10493 |
+
proxy.guid = fn.guid = fn.guid || jQuery.guid++;
|
10494 |
+
|
10495 |
+
return proxy;
|
10496 |
+
};
|
10497 |
+
|
10498 |
+
jQuery.holdReady = function( hold ) {
|
10499 |
+
if ( hold ) {
|
10500 |
+
jQuery.readyWait++;
|
10501 |
+
} else {
|
10502 |
+
jQuery.ready( true );
|
10503 |
+
}
|
10504 |
+
};
|
10505 |
+
jQuery.isArray = Array.isArray;
|
10506 |
+
jQuery.parseJSON = JSON.parse;
|
10507 |
+
jQuery.nodeName = nodeName;
|
10508 |
+
jQuery.isFunction = isFunction;
|
10509 |
+
jQuery.isWindow = isWindow;
|
10510 |
+
jQuery.camelCase = camelCase;
|
10511 |
+
jQuery.type = toType;
|
10512 |
+
|
10513 |
+
jQuery.now = Date.now;
|
10514 |
+
|
10515 |
+
jQuery.isNumeric = function( obj ) {
|
10516 |
+
|
10517 |
+
// As of jQuery 3.0, isNumeric is limited to
|
10518 |
+
// strings and numbers (primitives or objects)
|
10519 |
+
// that can be coerced to finite numbers (gh-2662)
|
10520 |
+
var type = jQuery.type( obj );
|
10521 |
+
return ( type === "number" || type === "string" ) &&
|
10522 |
+
|
10523 |
+
// parseFloat NaNs numeric-cast false positives ("")
|
10524 |
+
// ...but misinterprets leading-number strings, particularly hex literals ("0x...")
|
10525 |
+
// subtraction forces infinities to NaN
|
10526 |
+
!isNaN( obj - parseFloat( obj ) );
|
10527 |
+
};
|
10528 |
+
|
10529 |
+
|
10530 |
+
|
10531 |
+
|
10532 |
+
// Register as a named AMD module, since jQuery can be concatenated with other
|
10533 |
+
// files that may use define, but not via a proper concatenation script that
|
10534 |
+
// understands anonymous AMD modules. A named AMD is safest and most robust
|
10535 |
+
// way to register. Lowercase jquery is used because AMD module names are
|
10536 |
+
// derived from file names, and jQuery is normally delivered in a lowercase
|
10537 |
+
// file name. Do this after creating the global so that if an AMD module wants
|
10538 |
+
// to call noConflict to hide this version of jQuery, it will work.
|
10539 |
+
|
10540 |
+
// Note that for maximum portability, libraries that are not jQuery should
|
10541 |
+
// declare themselves as anonymous modules, and avoid setting a global if an
|
10542 |
+
// AMD loader is present. jQuery is a special case. For more information, see
|
10543 |
+
// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
|
10544 |
+
|
10545 |
+
if ( true ) {
|
10546 |
+
!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = (function() {
|
10547 |
+
return jQuery;
|
10548 |
+
}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),
|
10549 |
+
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
|
10550 |
+
}
|
10551 |
+
|
10552 |
+
|
10553 |
+
|
10554 |
+
|
10555 |
+
var
|
10556 |
+
|
10557 |
+
// Map over jQuery in case of overwrite
|
10558 |
+
_jQuery = window.jQuery,
|
10559 |
+
|
10560 |
+
// Map over the $ in case of overwrite
|
10561 |
+
_$ = window.$;
|
10562 |
+
|
10563 |
+
jQuery.noConflict = function( deep ) {
|
10564 |
+
if ( window.$ === jQuery ) {
|
10565 |
+
window.$ = _$;
|
10566 |
+
}
|
10567 |
+
|
10568 |
+
if ( deep && window.jQuery === jQuery ) {
|
10569 |
+
window.jQuery = _jQuery;
|
10570 |
+
}
|
10571 |
+
|
10572 |
+
return jQuery;
|
10573 |
+
};
|
10574 |
+
|
10575 |
+
// Expose jQuery and $ identifiers, even in AMD
|
10576 |
+
// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
|
10577 |
+
// and CommonJS for browser emulators (#13566)
|
10578 |
+
if ( !noGlobal ) {
|
10579 |
+
window.jQuery = window.$ = jQuery;
|
10580 |
+
}
|
10581 |
+
|
10582 |
+
|
10583 |
+
|
10584 |
+
|
10585 |
+
return jQuery;
|
10586 |
+
} );
|
10587 |
+
|
10588 |
+
|
10589 |
+
/***/ })
|
10590 |
+
|
10591 |
+
/******/ });
|
10592 |
+
//# sourceMappingURL=wsal-wizard.js.map
|
js/dist/wsal-wizard.min.js
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(r,i,function(t){return e[t]}.bind(null,i));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=1)}([function(e,t,n){var r;
|
2 |
+
/*!
|
3 |
+
* jQuery JavaScript Library v3.3.1
|
4 |
+
* https://jquery.com/
|
5 |
+
*
|
6 |
+
* Includes Sizzle.js
|
7 |
+
* https://sizzlejs.com/
|
8 |
+
*
|
9 |
+
* Copyright JS Foundation and other contributors
|
10 |
+
* Released under the MIT license
|
11 |
+
* https://jquery.org/license
|
12 |
+
*
|
13 |
+
* Date: 2018-01-20T17:24Z
|
14 |
+
*/
|
15 |
+
/*!
|
16 |
+
* jQuery JavaScript Library v3.3.1
|
17 |
+
* https://jquery.com/
|
18 |
+
*
|
19 |
+
* Includes Sizzle.js
|
20 |
+
* https://sizzlejs.com/
|
21 |
+
*
|
22 |
+
* Copyright JS Foundation and other contributors
|
23 |
+
* Released under the MIT license
|
24 |
+
* https://jquery.org/license
|
25 |
+
*
|
26 |
+
* Date: 2018-01-20T17:24Z
|
27 |
+
*/
|
28 |
+
!function(t,n){"use strict";"object"==typeof e&&"object"==typeof e.exports?e.exports=t.document?n(t,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return n(e)}:n(t)}("undefined"!=typeof window?window:this,function(n,i){"use strict";var o=[],a=n.document,s=Object.getPrototypeOf,u=o.slice,l=o.concat,c=o.push,f=o.indexOf,p={},d=p.toString,h=p.hasOwnProperty,g=h.toString,v=g.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},b={type:!0,src:!0,noModule:!0};function w(e,t,n){var r,i=(t=t||a).createElement("script");if(i.text=e,n)for(r in b)n[r]&&(i[r]=n[r]);t.head.appendChild(i).parentNode.removeChild(i)}function T(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?p[d.call(e)]||"object":typeof e}var C=function(e,t){return new C.fn.init(e,t)},k=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function E(e){var t=!!e&&"length"in e&&e.length,n=T(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e)}C.fn=C.prototype={jquery:"3.3.1",constructor:C,length:0,toArray:function(){return u.call(this)},get:function(e){return null==e?u.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=C.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return C.each(this,e)},map:function(e){return this.pushStack(C.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(u.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:c,sort:o.sort,splice:o.splice},C.extend=C.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)n=a[t],a!==(r=e[t])&&(l&&r&&(C.isPlainObject(r)||(i=Array.isArray(r)))?(i?(i=!1,o=n&&Array.isArray(n)?n:[]):o=n&&C.isPlainObject(n)?n:{},a[t]=C.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},C.extend({expando:"jQuery"+("3.3.1"+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==d.call(e))&&(!(t=s(e))||"function"==typeof(n=h.call(t,"constructor")&&t.constructor)&&g.call(n)===v)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e){w(e)},each:function(e,t){var n,r=0;if(E(e))for(n=e.length;r<n&&!1!==t.call(e[r],r,e[r]);r++);else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?"":(e+"").replace(k,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(E(Object(e))?C.merge(n,"string"==typeof e?[e]:e):c.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:f.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(E(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return l.apply([],a)},guid:1,support:y}),"function"==typeof Symbol&&(C.fn[Symbol.iterator]=o[Symbol.iterator]),C.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){p["[object "+t+"]"]=t.toLowerCase()});var S=
|
29 |
+
/*!
|
30 |
+
* Sizzle CSS Selector Engine v2.3.3
|
31 |
+
* https://sizzlejs.com/
|
32 |
+
*
|
33 |
+
* Copyright jQuery Foundation and other contributors
|
34 |
+
* Released under the MIT license
|
35 |
+
* http://jquery.org/license
|
36 |
+
*
|
37 |
+
* Date: 2016-08-08
|
38 |
+
*/
|
39 |
+
function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,v,y,m,x,b="sizzle"+1*new Date,w=e.document,T=0,C=0,k=ae(),E=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},j={}.hasOwnProperty,N=[],A=N.pop,q=N.push,L=N.push,H=N.slice,O=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},P="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\0-\\xa0])+",I="\\["+M+"*("+R+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+R+"))|)"+M+"*\\]",W=":("+R+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+I+")*)|.*)\\)|)",$=new RegExp(M+"+","g"),B=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),F=new RegExp("^"+M+"*,"+M+"*"),_=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),z=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),U=new RegExp(W),X=new RegExp("^"+R+"$"),V={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+P+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},G=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Q=/^[^{]+\{\s*\[native \w/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,K=/[+~]/,Z=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ee=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},te=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ne=function(e,t){return t?"\0"===e?"�":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},re=function(){p()},ie=me(function(e){return!0===e.disabled&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{L.apply(N=H.call(w.childNodes),w.childNodes),N[w.childNodes.length].nodeType}catch(e){L={apply:N.length?function(e,t){q.apply(e,H.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}function oe(e,t,r,i){var o,s,l,c,f,h,y,m=t&&t.ownerDocument,T=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==T&&9!==T&&11!==T)return r;if(!i&&((t?t.ownerDocument||t:w)!==d&&p(t),t=t||d,g)){if(11!==T&&(f=J.exec(e)))if(o=f[1]){if(9===T){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(m&&(l=m.getElementById(o))&&x(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return L.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return L.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!S[e+" "]&&(!v||!v.test(e))){if(1!==T)m=t,y=e;else if("object"!==t.nodeName.toLowerCase()){for((c=t.getAttribute("id"))?c=c.replace(te,ne):t.setAttribute("id",c=b),s=(h=a(e)).length;s--;)h[s]="#"+c+" "+ye(h[s]);y=h.join(","),m=K.test(e)&&ge(t.parentNode)||t}if(y)try{return L.apply(r,m.querySelectorAll(y)),r}catch(e){}finally{c===b&&t.removeAttribute("id")}}}return u(e.replace(B,"$1"),t,r,i)}function ae(){var e=[];return function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}}function se(e){return e[b]=!0,e}function ue(e){var t=d.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function le(e,t){for(var n=e.split("|"),i=n.length;i--;)r.attrHandle[n[i]]=t}function ce(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function fe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function pe(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function de(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ie(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function he(e){return se(function(t){return t=+t,se(function(n,r){for(var i,o=e([],n.length,t),a=o.length;a--;)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function ge(e){return e&&void 0!==e.getElementsByTagName&&e}for(t in n=oe.support={},o=oe.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},p=oe.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!==d&&9===a.nodeType&&a.documentElement?(h=(d=a).documentElement,g=!o(d),w!==d&&(i=d.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",re,!1):i.attachEvent&&i.attachEvent("onunload",re)),n.attributes=ue(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ue(function(e){return e.appendChild(d.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=Q.test(d.getElementsByClassName),n.getById=ue(function(e){return h.appendChild(e).id=b,!d.getElementsByName||!d.getElementsByName(b).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if(void 0!==t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){var n=void 0!==e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if(void 0!==t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];for(i=t.getElementsByName(e),r=0;o=i[r++];)if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return void 0!==t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){for(;n=o[i++];)1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if(void 0!==t.getElementsByClassName&&g)return t.getElementsByClassName(e)},y=[],v=[],(n.qsa=Q.test(d.querySelectorAll))&&(ue(function(e){h.appendChild(e).innerHTML="<a id='"+b+"'></a><select id='"+b+"-\r\\' msallowcapture=''><option selected=''></option></select>",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+P+")"),e.querySelectorAll("[id~="+b+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+b+"+*").length||v.push(".#.+[+~]")}),ue(function(e){e.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var t=d.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(n.matchesSelector=Q.test(m=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ue(function(e){n.disconnectedMatch=m.call(e,"*"),m.call(e,"[s!='']:x"),y.push("!=",W)}),v=v.length&&new RegExp(v.join("|")),y=y.length&&new RegExp(y.join("|")),t=Q.test(h.compareDocumentPosition),x=t||Q.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===d||e.ownerDocument===w&&x(w,e)?-1:t===d||t.ownerDocument===w&&x(w,t)?1:c?O(c,e)-O(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===d?-1:t===d?1:i?-1:o?1:c?O(c,e)-O(c,t):0;if(i===o)return ce(e,t);for(n=e;n=n.parentNode;)a.unshift(n);for(n=t;n=n.parentNode;)s.unshift(n);for(;a[r]===s[r];)r++;return r?ce(a[r],s[r]):a[r]===w?-1:s[r]===w?1:0},d):d},oe.matches=function(e,t){return oe(e,null,null,t)},oe.matchesSelector=function(e,t){if((e.ownerDocument||e)!==d&&p(e),t=t.replace(z,"='$1']"),n.matchesSelector&&g&&!S[t+" "]&&(!y||!y.test(t))&&(!v||!v.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return oe(t,d,null,[e]).length>0},oe.contains=function(e,t){return(e.ownerDocument||e)!==d&&p(e),x(e,t)},oe.attr=function(e,t){(e.ownerDocument||e)!==d&&p(e);var i=r.attrHandle[t.toLowerCase()],o=i&&j.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},oe.escape=function(e){return(e+"").replace(te,ne)},oe.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},oe.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(D),f){for(;t=e[o++];)t===e[o]&&(i=r.push(o));for(;i--;)e.splice(r[i],1)}return c=null,e},i=oe.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else for(;t=e[r++];)n+=i(t);return n},(r=oe.selectors={cacheLength:50,createPseudo:se,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(Z,ee),e[3]=(e[3]||e[4]||e[5]||"").replace(Z,ee),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||oe.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&oe.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return V.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&U.test(n)&&(t=a(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(Z,ee).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=k[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&k(e,function(e){return t.test("string"==typeof e.className&&e.className||void 0!==e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=oe.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace($," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",v=t.parentNode,y=s&&t.nodeName.toLowerCase(),m=!u&&!s,x=!1;if(v){if(o){for(;g;){for(p=t;p=p[g];)if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?v.firstChild:v.lastChild],a&&m){for(x=(d=(l=(c=(f=(p=v)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1])&&l[2],p=d&&v.childNodes[d];p=++d&&p&&p[g]||(x=d=0)||h.pop();)if(1===p.nodeType&&++x&&p===t){c[e]=[T,d,x];break}}else if(m&&(x=d=(l=(c=(f=(p=t)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1]),!1===x)for(;(p=++d&&p&&p[g]||(x=d=0)||h.pop())&&((s?p.nodeName.toLowerCase()!==y:1!==p.nodeType)||!++x||(m&&((c=(f=p[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]=[T,x]),p!==t)););return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||oe.error("unsupported pseudo: "+e);return i[b]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?se(function(e,n){for(var r,o=i(e,t),a=o.length;a--;)e[r=O(e,o[a])]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:se(function(e){var t=[],n=[],r=s(e.replace(B,"$1"));return r[b]?se(function(e,t,n,i){for(var o,a=r(e,null,i,[]),s=e.length;s--;)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}}),has:se(function(e){return function(t){return oe(e,t).length>0}}),contains:se(function(e){return e=e.replace(Z,ee),function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:se(function(e){return X.test(e||"")||oe.error("unsupported lang: "+e),e=e.replace(Z,ee).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:de(!1),disabled:de(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Y.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:he(function(){return[0]}),last:he(function(e,t){return[t-1]}),eq:he(function(e,t,n){return[n<0?n+t:n]}),even:he(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:he(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:he(function(e,t,n){for(var r=n<0?n+t:n;--r>=0;)e.push(r);return e}),gt:he(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=r.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})r.pseudos[t]=fe(t);for(t in{submit:!0,reset:!0})r.pseudos[t]=pe(t);function ve(){}function ye(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function me(e,t,n){var r=t.dir,i=t.next,o=i||r,a=n&&"parentNode"===o,s=C++;return t.first?function(t,n,i){for(;t=t[r];)if(1===t.nodeType||a)return e(t,n,i);return!1}:function(t,n,u){var l,c,f,p=[T,s];if(u){for(;t=t[r];)if((1===t.nodeType||a)&&e(t,n,u))return!0}else for(;t=t[r];)if(1===t.nodeType||a)if(c=(f=t[b]||(t[b]={}))[t.uniqueID]||(f[t.uniqueID]={}),i&&i===t.nodeName.toLowerCase())t=t[r]||t;else{if((l=c[o])&&l[0]===T&&l[1]===s)return p[2]=l[2];if(c[o]=p,p[2]=e(t,n,u))return!0}return!1}}function xe(e){return e.length>1?function(t,n,r){for(var i=e.length;i--;)if(!e[i](t,n,r))return!1;return!0}:e[0]}function be(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function we(e,t,n,r,i,o){return r&&!r[b]&&(r=we(r)),i&&!i[b]&&(i=we(i,o)),se(function(o,a,s,u){var l,c,f,p=[],d=[],h=a.length,g=o||function(e,t,n){for(var r=0,i=t.length;r<i;r++)oe(e,t[r],n);return n}(t||"*",s.nodeType?[s]:s,[]),v=!e||!o&&t?g:be(g,p,e,s,u),y=n?i||(o?e:h||r)?[]:a:v;if(n&&n(v,y,s,u),r)for(l=be(y,d),r(l,[],s,u),c=l.length;c--;)(f=l[c])&&(y[d[c]]=!(v[d[c]]=f));if(o){if(i||e){if(i){for(l=[],c=y.length;c--;)(f=y[c])&&l.push(v[c]=f);i(null,y=[],l,u)}for(c=y.length;c--;)(f=y[c])&&(l=i?O(o,f):p[c])>-1&&(o[l]=!(a[l]=f))}}else y=be(y===a?y.splice(h,y.length):y),i?i(null,a,y,u):L.apply(a,y)})}function Te(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],s=a||r.relative[" "],u=a?1:0,c=me(function(e){return e===t},s,!0),f=me(function(e){return O(t,e)>-1},s,!0),p=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u<o;u++)if(n=r.relative[e[u].type])p=[me(xe(p),n)];else{if((n=r.filter[e[u].type].apply(null,e[u].matches))[b]){for(i=++u;i<o&&!r.relative[e[i].type];i++);return we(u>1&&xe(p),u>1&&ye(e.slice(0,u-1).concat({value:" "===e[u-2].type?"*":""})).replace(B,"$1"),n,u<i&&Te(e.slice(u,i)),i<o&&Te(e=e.slice(i)),i<o&&ye(e))}p.push(n)}return xe(p)}return ve.prototype=r.filters=r.pseudos,r.setFilters=new ve,a=oe.tokenize=function(e,t){var n,i,o,a,s,u,l,c=E[e+" "];if(c)return t?0:c.slice(0);for(s=e,u=[],l=r.preFilter;s;){for(a in n&&!(i=F.exec(s))||(i&&(s=s.slice(i[0].length)||s),u.push(o=[])),n=!1,(i=_.exec(s))&&(n=i.shift(),o.push({value:n,type:i[0].replace(B," ")}),s=s.slice(n.length)),r.filter)!(i=V[a].exec(s))||l[a]&&!(i=l[a](i))||(n=i.shift(),o.push({value:n,type:a,matches:i}),s=s.slice(n.length));if(!n)break}return t?s.length:s?oe.error(e):E(e,u).slice(0)},s=oe.compile=function(e,t){var n,i=[],o=[],s=S[e+" "];if(!s){for(t||(t=a(e)),n=t.length;n--;)(s=Te(t[n]))[b]?i.push(s):o.push(s);(s=S(e,function(e,t){var n=t.length>0,i=e.length>0,o=function(o,a,s,u,c){var f,h,v,y=0,m="0",x=o&&[],b=[],w=l,C=o||i&&r.find.TAG("*",c),k=T+=null==w?1:Math.random()||.1,E=C.length;for(c&&(l=a===d||a||c);m!==E&&null!=(f=C[m]);m++){if(i&&f){for(h=0,a||f.ownerDocument===d||(p(f),s=!g);v=e[h++];)if(v(f,a||d,s)){u.push(f);break}c&&(T=k)}n&&((f=!v&&f)&&y--,o&&x.push(f))}if(y+=m,n&&m!==y){for(h=0;v=t[h++];)v(x,b,a,s);if(o){if(y>0)for(;m--;)x[m]||b[m]||(b[m]=A.call(u));b=be(b)}L.apply(u,b),c&&!o&&b.length>0&&y+t.length>1&&oe.uniqueSort(u)}return c&&(T=k,l=w),x};return n?se(o):o}(o,i))).selector=e}return s},u=oe.select=function(e,t,n,i){var o,u,l,c,f,p="function"==typeof e&&e,d=!i&&a(e=p.selector||e);if(n=n||[],1===d.length){if((u=d[0]=d[0].slice(0)).length>2&&"ID"===(l=u[0]).type&&9===t.nodeType&&g&&r.relative[u[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(Z,ee),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}for(o=V.needsContext.test(e)?0:u.length;o--&&(l=u[o],!r.relative[c=l.type]);)if((f=r.find[c])&&(i=f(l.matches[0].replace(Z,ee),K.test(u[0].type)&&ge(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&ye(u)))return L.apply(n,i),n;break}}return(p||s(e,d))(i,t,!g,n,!t||K.test(e)&&ge(t.parentNode)||t),n},n.sortStable=b.split("").sort(D).join("")===b,n.detectDuplicates=!!f,p(),n.sortDetached=ue(function(e){return 1&e.compareDocumentPosition(d.createElement("fieldset"))}),ue(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||le("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ue(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||le("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ue(function(e){return null==e.getAttribute("disabled")})||le(P,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),oe}(n);C.find=S,C.expr=S.selectors,C.expr[":"]=C.expr.pseudos,C.uniqueSort=C.unique=S.uniqueSort,C.text=S.getText,C.isXMLDoc=S.isXML,C.contains=S.contains,C.escapeSelector=S.escape;var D=function(e,t,n){for(var r=[],i=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(i&&C(e).is(n))break;r.push(e)}return r},j=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},N=C.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var q=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function L(e,t,n){return m(t)?C.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?C.grep(e,function(e){return e===t!==n}):"string"!=typeof t?C.grep(e,function(e){return f.call(t,e)>-1!==n}):C.filter(t,e,n)}C.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?C.find.matchesSelector(r,e)?[r]:[]:C.find.matches(e,C.grep(t,function(e){return 1===e.nodeType}))},C.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(C(e).filter(function(){for(t=0;t<r;t++)if(C.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)C.find(e,i[t],n);return r>1?C.uniqueSort(n):n},filter:function(e){return this.pushStack(L(this,e||[],!1))},not:function(e){return this.pushStack(L(this,e||[],!0))},is:function(e){return!!L(this,"string"==typeof e&&N.test(e)?C(e):e||[],!1).length}});var H,O=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(C.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||H,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:O.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof C?t[0]:t,C.merge(this,C.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:a,!0)),q.test(r[1])&&C.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=a.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(C):C.makeArray(e,this)}).prototype=C.fn,H=C(a);var P=/^(?:parents|prev(?:Until|All))/,M={children:!0,contents:!0,next:!0,prev:!0};function R(e,t){for(;(e=e[t])&&1!==e.nodeType;);return e}C.fn.extend({has:function(e){var t=C(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(C.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&C(e);if(!N.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?a.index(n)>-1:1===n.nodeType&&C.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?C.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?f.call(C(e),this[0]):f.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(C.uniqueSort(C.merge(this.get(),C(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),C.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return D(e,"parentNode")},parentsUntil:function(e,t,n){return D(e,"parentNode",n)},next:function(e){return R(e,"nextSibling")},prev:function(e){return R(e,"previousSibling")},nextAll:function(e){return D(e,"nextSibling")},prevAll:function(e){return D(e,"previousSibling")},nextUntil:function(e,t,n){return D(e,"nextSibling",n)},prevUntil:function(e,t,n){return D(e,"previousSibling",n)},siblings:function(e){return j((e.parentNode||{}).firstChild,e)},children:function(e){return j(e.firstChild)},contents:function(e){return A(e,"iframe")?e.contentDocument:(A(e,"template")&&(e=e.content||e),C.merge([],e.childNodes))}},function(e,t){C.fn[e]=function(n,r){var i=C.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=C.filter(r,i)),this.length>1&&(M[e]||C.uniqueSort(i),P.test(e)&&i.reverse()),this.pushStack(i)}});var I=/[^\x20\t\r\n\f]+/g;function W(e){return e}function $(e){throw e}function B(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}C.Callbacks=function(e){e="string"==typeof e?function(e){var t={};return C.each(e.match(I)||[],function(e,n){t[n]=!0}),t}(e):C.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1)for(n=a.shift();++s<o.length;)!1===o[s].apply(n[0],n[1])&&e.stopOnFalse&&(s=o.length,n=!1);e.memory||(n=!1),t=!1,i&&(o=n?[]:"")},l={add:function(){return o&&(n&&!t&&(s=o.length-1,a.push(n)),function t(n){C.each(n,function(n,r){m(r)?e.unique&&l.has(r)||o.push(r):r&&r.length&&"string"!==T(r)&&t(r)})}(arguments),n&&!t&&u()),this},remove:function(){return C.each(arguments,function(e,t){for(var n;(n=C.inArray(t,o,n))>-1;)o.splice(n,1),n<=s&&s--}),this},has:function(e){return e?C.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l},C.extend({Deferred:function(e){var t=[["notify","progress",C.Callbacks("memory"),C.Callbacks("memory"),2],["resolve","done",C.Callbacks("once memory"),C.Callbacks("once memory"),0,"resolved"],["reject","fail",C.Callbacks("once memory"),C.Callbacks("once memory"),1,"rejected"]],r="pending",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},catch:function(e){return i.then(null,e)},pipe:function(){var e=arguments;return C.Deferred(function(n){C.each(t,function(t,r){var i=m(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&m(e.promise)?e.promise().progress(n.notify).done(n.resolve).fail(n.reject):n[r[0]+"With"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(e,r,i){var o=0;function a(e,t,r,i){return function(){var s=this,u=arguments,l=function(){var n,l;if(!(e<o)){if((n=r.apply(s,u))===t.promise())throw new TypeError("Thenable self-resolution");l=n&&("object"==typeof n||"function"==typeof n)&&n.then,m(l)?i?l.call(n,a(o,t,W,i),a(o,t,$,i)):(o++,l.call(n,a(o,t,W,i),a(o,t,$,i),a(o,t,W,t.notifyWith))):(r!==W&&(s=void 0,u=[n]),(i||t.resolveWith)(s,u))}},c=i?l:function(){try{l()}catch(n){C.Deferred.exceptionHook&&C.Deferred.exceptionHook(n,c.stackTrace),e+1>=o&&(r!==$&&(s=void 0,u=[n]),t.rejectWith(s,u))}};e?c():(C.Deferred.getStackHook&&(c.stackTrace=C.Deferred.getStackHook()),n.setTimeout(c))}}return C.Deferred(function(n){t[0][3].add(a(0,n,m(i)?i:W,n.notifyWith)),t[1][3].add(a(0,n,m(e)?e:W)),t[2][3].add(a(0,n,m(r)?r:$))}).promise()},promise:function(e){return null!=e?C.extend(e,i):i}},o={};return C.each(t,function(e,n){var a=n[2],s=n[5];i[n[1]]=a.add,s&&a.add(function(){r=s},t[3-e][2].disable,t[3-e][3].disable,t[0][2].lock,t[0][3].lock),a.add(n[3].fire),o[n[0]]=function(){return o[n[0]+"With"](this===o?void 0:this,arguments),this},o[n[0]+"With"]=a.fireWith}),i.promise(o),e&&e.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=u.call(arguments),o=C.Deferred(),a=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?u.call(arguments):n,--t||o.resolveWith(r,i)}};if(t<=1&&(B(e,o.done(a(n)).resolve,o.reject,!t),"pending"===o.state()||m(i[n]&&i[n].then)))return o.then();for(;n--;)B(i[n],a(n),o.reject);return o.promise()}});var F=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;C.Deferred.exceptionHook=function(e,t){n.console&&n.console.warn&&e&&F.test(e.name)&&n.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},C.readyException=function(e){n.setTimeout(function(){throw e})};var _=C.Deferred();function z(){a.removeEventListener("DOMContentLoaded",z),n.removeEventListener("load",z),C.ready()}C.fn.ready=function(e){return _.then(e).catch(function(e){C.readyException(e)}),this},C.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--C.readyWait:C.isReady)||(C.isReady=!0,!0!==e&&--C.readyWait>0||_.resolveWith(a,[C]))}}),C.ready.then=_.then,"complete"===a.readyState||"loading"!==a.readyState&&!a.documentElement.doScroll?n.setTimeout(C.ready):(a.addEventListener("DOMContentLoaded",z),n.addEventListener("load",z));var U=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===T(n))for(s in i=!0,n)U(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(C(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},X=/^-ms-/,V=/-([a-z])/g;function G(e,t){return t.toUpperCase()}function Y(e){return e.replace(X,"ms-").replace(V,G)}var Q=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function J(){this.expando=C.expando+J.uid++}J.uid=1,J.prototype={cache:function(e){var t=e[this.expando];return t||(t={},Q(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if("string"==typeof t)i[Y(t)]=n;else for(r in t)i[Y(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][Y(t)]},access:function(e,t,n){return void 0===t||t&&"string"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(Y):(t=Y(t))in r?[t]:t.match(I)||[]).length;for(;n--;)delete r[t[n]]}(void 0===t||C.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!C.isEmptyObject(t)}};var K=new J,Z=new J,ee=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,te=/[A-Z]/g;function ne(e,t,n){var r;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(te,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n=function(e){return"true"===e||"false"!==e&&("null"===e?null:e===+e+""?+e:ee.test(e)?JSON.parse(e):e)}(n)}catch(e){}Z.set(e,t,n)}else n=void 0;return n}C.extend({hasData:function(e){return Z.hasData(e)||K.hasData(e)},data:function(e,t,n){return Z.access(e,t,n)},removeData:function(e,t){Z.remove(e,t)},_data:function(e,t,n){return K.access(e,t,n)},_removeData:function(e,t){K.remove(e,t)}}),C.fn.extend({data:function(e,t){var n,r,i,o=this[0],a=o&&o.attributes;if(void 0===e){if(this.length&&(i=Z.get(o),1===o.nodeType&&!K.get(o,"hasDataAttrs"))){for(n=a.length;n--;)a[n]&&0===(r=a[n].name).indexOf("data-")&&(r=Y(r.slice(5)),ne(o,r,i[r]));K.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof e?this.each(function(){Z.set(this,e)}):U(this,function(t){var n;if(o&&void 0===t)return void 0!==(n=Z.get(o,e))?n:void 0!==(n=ne(o,e))?n:void 0;this.each(function(){Z.set(this,e,t)})},null,t,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){Z.remove(this,e)})}}),C.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=K.get(e,t),n&&(!r||Array.isArray(n)?r=K.access(e,t,C.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=C.queue(e,t),r=n.length,i=n.shift(),o=C._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){C.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return K.get(e,n)||K.access(e,n,{empty:C.Callbacks("once memory").add(function(){K.remove(e,[t+"queue",n])})})}}),C.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length<n?C.queue(this[0],e):void 0===t?this:this.each(function(){var n=C.queue(this,e,t);C._queueHooks(this,e),"fx"===e&&"inprogress"!==n[0]&&C.dequeue(this,e)})},dequeue:function(e){return this.each(function(){C.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=C.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};for("string"!=typeof e&&(t=e,e=void 0),e=e||"fx";a--;)(n=K.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var re=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,ie=new RegExp("^(?:([+-])=|)("+re+")([a-z%]*)$","i"),oe=["Top","Right","Bottom","Left"],ae=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&C.contains(e.ownerDocument,e)&&"none"===C.css(e,"display")},se=function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];for(o in i=n.apply(e,r||[]),t)e.style[o]=a[o];return i};function ue(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return C.css(e,t,"")},u=s(),l=n&&n[3]||(C.cssNumber[t]?"":"px"),c=(C.cssNumber[t]||"px"!==l&&+u)&&ie.exec(C.css(e,t));if(c&&c[3]!==l){for(u/=2,l=l||c[3],c=+u||1;a--;)C.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,C.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var le={};function ce(e){var t,n=e.ownerDocument,r=e.nodeName,i=le[r];return i||(t=n.body.appendChild(n.createElement(r)),i=C.css(t,"display"),t.parentNode.removeChild(t),"none"===i&&(i="block"),le[r]=i,i)}function fe(e,t){for(var n,r,i=[],o=0,a=e.length;o<a;o++)(r=e[o]).style&&(n=r.style.display,t?("none"===n&&(i[o]=K.get(r,"display")||null,i[o]||(r.style.display="")),""===r.style.display&&ae(r)&&(i[o]=ce(r))):"none"!==n&&(i[o]="none",K.set(r,"display",n)));for(o=0;o<a;o++)null!=i[o]&&(e[o].style.display=i[o]);return e}C.fn.extend({show:function(){return fe(this,!0)},hide:function(){return fe(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){ae(this)?C(this).show():C(this).hide()})}});var pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\/\0>\x20\t\r\n\f]+)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};function ve(e,t){var n;return n=void 0!==e.getElementsByTagName?e.getElementsByTagName(t||"*"):void 0!==e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?C.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)K.set(e[n],"globalEval",!t||K.get(t[n],"globalEval"))}ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if("object"===T(o))C.merge(p,o.nodeType?[o]:o);else if(me.test(o)){for(a=a||f.appendChild(t.createElement("div")),s=(de.exec(o)||["",""])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+C.htmlPrefilter(o)+u[2],c=u[0];c--;)a=a.lastChild;C.merge(p,a.childNodes),(a=f.firstChild).textContent=""}else p.push(t.createTextNode(o));for(f.textContent="",d=0;o=p[d++];)if(r&&C.inArray(o,r)>-1)i&&i.push(o);else if(l=C.contains(o.ownerDocument,o),a=ve(f.appendChild(o),"script"),l&&ye(a),n)for(c=0;o=a[c++];)he.test(o.type||"")&&n.push(o);return f}!function(){var e=a.createDocumentFragment().appendChild(a.createElement("div")),t=a.createElement("input");t.setAttribute("type","radio"),t.setAttribute("checked","checked"),t.setAttribute("name","t"),e.appendChild(t),y.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,e.innerHTML="<textarea>x</textarea>",y.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var be=a.documentElement,we=/^key/,Te=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ce=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Ee(){return!1}function Se(){try{return a.activeElement}catch(e){}}function De(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)De(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Ee;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return C().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=C.guid++)),e.each(function(){C.event.add(this,t,i,r,n)})}C.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=K.get(e);if(v)for(n.handler&&(n=(o=n).handler,i=o.selector),i&&C.find.matchesSelector(be,i),n.guid||(n.guid=C.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(t){return void 0!==C&&C.event.triggered!==t.type?C.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(I)||[""]).length;l--;)d=g=(s=Ce.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=C.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=C.event.special[d]||{},c=C.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&C.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),C.event.global[d]=!0)},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=K.hasData(e)&&K.get(e);if(v&&(u=v.events)){for(l=(t=(t||"").match(I)||[""]).length;l--;)if(d=g=(s=Ce.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){for(f=C.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;o--;)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||C.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)C.event.remove(e,d+t[l],n,r,!0);C.isEmptyObject(u)&&K.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=C.event.fix(e),u=new Array(arguments.length),l=(K.get(this,"events")||{})[s.type]||[],c=C.event.special[s.type]||{};for(u[0]=s,t=1;t<arguments.length;t++)u[t]=arguments[t];if(s.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,s)){for(a=C.event.handlers.call(this,s,l),t=0;(i=a[t++])&&!s.isPropagationStopped();)for(s.currentTarget=i.elem,n=0;(o=i.handlers[n++])&&!s.isImmediatePropagationStopped();)s.rnamespace&&!s.rnamespace.test(o.namespace)||(s.handleObj=o,s.data=o.data,void 0!==(r=((C.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,u))&&!1===(s.result=r)&&(s.preventDefault(),s.stopPropagation()));return c.postDispatch&&c.postDispatch.call(this,s),s.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!("click"===e.type&&e.button>=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+" "]&&(a[i]=r.needsContext?C(i,this).index(l)>-1:C.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(e,t){Object.defineProperty(C.Event.prototype,e,{enumerable:!0,configurable:!0,get:m(t)?function(){if(this.originalEvent)return t(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[e]},set:function(t){Object.defineProperty(this,e,{enumerable:!0,configurable:!0,writable:!0,value:t})}})},fix:function(e){return e[C.expando]?e:new C.Event(e)},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==Se()&&this.focus)return this.focus(),!1},delegateType:"focusin"},blur:{trigger:function(){if(this===Se()&&this.blur)return this.blur(),!1},delegateType:"focusout"},click:{trigger:function(){if("checkbox"===this.type&&this.click&&A(this,"input"))return this.click(),!1},_default:function(e){return A(e.target,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},C.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},C.Event=function(e,t){if(!(this instanceof C.Event))return new C.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?ke:Ee,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&C.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[C.expando]=!0},C.Event.prototype={constructor:C.Event,isDefaultPrevented:Ee,isPropagationStopped:Ee,isImmediatePropagationStopped:Ee,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=ke,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=ke,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=ke,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},C.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,char:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(e){var t=e.button;return null==e.which&&we.test(e.type)?null!=e.charCode?e.charCode:e.keyCode:!e.which&&void 0!==t&&Te.test(e.type)?1&t?1:2&t?3:4&t?2:0:e.which}},C.event.addProp),C.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,t){C.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=e.relatedTarget,i=e.handleObj;return r&&(r===this||C.contains(this,r))||(e.type=i.origType,n=i.handler.apply(this,arguments),e.type=t),n}}}),C.fn.extend({on:function(e,t,n,r){return De(this,e,t,n,r)},one:function(e,t,n,r){return De(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,C(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=Ee),this.each(function(){C.event.remove(this,e,n,t)})}});var je=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,Ne=/<script|<style|<link/i,Ae=/checked\s*(?:[^=]|=\s*.checked.)/i,qe=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function Le(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&C(e).children("tbody")[0]||e}function He(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Oe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Pe(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(K.hasData(e)&&(o=K.access(e),a=K.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n<r;n++)C.event.add(t,i,l[i][n]);Z.hasData(e)&&(s=Z.access(e),u=C.extend({},s),Z.set(t,u))}}function Me(e,t){var n=t.nodeName.toLowerCase();"input"===n&&pe.test(e.type)?t.checked=e.checked:"input"!==n&&"textarea"!==n||(t.defaultValue=e.defaultValue)}function Re(e,t,n,r){t=l.apply([],t);var i,o,a,s,u,c,f=0,p=e.length,d=p-1,h=t[0],g=m(h);if(g||p>1&&"string"==typeof h&&!y.checkClone&&Ae.test(h))return e.each(function(i){var o=e.eq(i);g&&(t[0]=h.call(this,i,o.html())),Re(o,t,n,r)});if(p&&(o=(i=xe(t,e[0].ownerDocument,!1,e,r)).firstChild,1===i.childNodes.length&&(i=o),o||r)){for(s=(a=C.map(ve(i,"script"),He)).length;f<p;f++)u=i,f!==d&&(u=C.clone(u,!0,!0),s&&C.merge(a,ve(u,"script"))),n.call(e[f],u,f);if(s)for(c=a[a.length-1].ownerDocument,C.map(a,Oe),f=0;f<s;f++)u=a[f],he.test(u.type||"")&&!K.access(u,"globalEval")&&C.contains(c,u)&&(u.src&&"module"!==(u.type||"").toLowerCase()?C._evalUrl&&C._evalUrl(u.src):w(u.textContent.replace(qe,""),c,u))}return e}function Ie(e,t,n){for(var r,i=t?C.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||C.cleanData(ve(r)),r.parentNode&&(n&&C.contains(r.ownerDocument,r)&&ye(ve(r,"script")),r.parentNode.removeChild(r));return e}C.extend({htmlPrefilter:function(e){return e.replace(je,"<$1></$2>")},clone:function(e,t,n){var r,i,o,a,s=e.cloneNode(!0),u=C.contains(e.ownerDocument,e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||C.isXMLDoc(e)))for(a=ve(s),r=0,i=(o=ve(e)).length;r<i;r++)Me(o[r],a[r]);if(t)if(n)for(o=o||ve(e),a=a||ve(s),r=0,i=o.length;r<i;r++)Pe(o[r],a[r]);else Pe(e,s);return(a=ve(s,"script")).length>0&&ye(a,!u&&ve(e,"script")),s},cleanData:function(e){for(var t,n,r,i=C.event.special,o=0;void 0!==(n=e[o]);o++)if(Q(n)){if(t=n[K.expando]){if(t.events)for(r in t.events)i[r]?C.event.remove(n,r):C.removeEvent(n,r,t.handle);n[K.expando]=void 0}n[Z.expando]&&(n[Z.expando]=void 0)}}}),C.fn.extend({detach:function(e){return Ie(this,e,!0)},remove:function(e){return Ie(this,e)},text:function(e){return U(this,function(e){return void 0===e?C.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Re(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Le(this,e).appendChild(e)})},prepend:function(){return Re(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Le(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(C.cleanData(ve(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return C.clone(this,e,t)})},html:function(e){return U(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ne.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=C.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(C.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=[];return Re(this,arguments,function(t){var n=this.parentNode;C.inArray(this,e)<0&&(C.cleanData(ve(this)),n&&n.replaceChild(t,this))},e)}}),C.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){C.fn[e]=function(e){for(var n,r=[],i=C(e),o=i.length-1,a=0;a<=o;a++)n=a===o?this:this.clone(!0),C(i[a])[t](n),c.apply(r,n.get());return this.pushStack(r)}});var We=new RegExp("^("+re+")(?!px)[a-z%]+$","i"),$e=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=n),t.getComputedStyle(e)},Be=new RegExp(oe.join("|"),"i");function Fe(e,t,n){var r,i,o,a,s=e.style;return(n=n||$e(e))&&(""!==(a=n.getPropertyValue(t)||n[t])||C.contains(e.ownerDocument,e)||(a=C.style(e,t)),!y.pixelBoxStyles()&&We.test(a)&&Be.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+"":a}function _e(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(c){l.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",c.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",be.appendChild(l).appendChild(c);var e=n.getComputedStyle(c);r="1%"!==e.top,u=12===t(e.marginLeft),c.style.right="60%",s=36===t(e.right),i=36===t(e.width),c.style.position="absolute",o=36===c.offsetWidth||"absolute",be.removeChild(l),c=null}}function t(e){return Math.round(parseFloat(e))}var r,i,o,s,u,l=a.createElement("div"),c=a.createElement("div");c.style&&(c.style.backgroundClip="content-box",c.cloneNode(!0).style.backgroundClip="",y.clearCloneStyle="content-box"===c.style.backgroundClip,C.extend(y,{boxSizingReliable:function(){return e(),i},pixelBoxStyles:function(){return e(),s},pixelPosition:function(){return e(),r},reliableMarginLeft:function(){return e(),u},scrollboxSize:function(){return e(),o}}))}();var ze=/^(none|table(?!-c[ea]).+)/,Ue=/^--/,Xe={position:"absolute",visibility:"hidden",display:"block"},Ve={letterSpacing:"0",fontWeight:"400"},Ge=["Webkit","Moz","ms"],Ye=a.createElement("div").style;function Qe(e){var t=C.cssProps[e];return t||(t=C.cssProps[e]=function(e){if(e in Ye)return e;for(var t=e[0].toUpperCase()+e.slice(1),n=Ge.length;n--;)if((e=Ge[n]+t)in Ye)return e}(e)||e),t}function Je(e,t,n){var r=ie.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function Ke(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(u+=C.css(e,n+oe[a],!0,i)),r?("content"===n&&(u-=C.css(e,"padding"+oe[a],!0,i)),"margin"!==n&&(u-=C.css(e,"border"+oe[a]+"Width",!0,i))):(u+=C.css(e,"padding"+oe[a],!0,i),"padding"!==n?u+=C.css(e,"border"+oe[a]+"Width",!0,i):s+=C.css(e,"border"+oe[a]+"Width",!0,i));return!r&&o>=0&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))),u}function Ze(e,t,n){var r=$e(e),i=Fe(e,t,r),o="border-box"===C.css(e,"boxSizing",!1,r),a=o;if(We.test(i)){if(!n)return i;i="auto"}return a=a&&(y.boxSizingReliable()||i===e.style[t]),("auto"===i||!parseFloat(i)&&"inline"===C.css(e,"display",!1,r))&&(i=e["offset"+t[0].toUpperCase()+t.slice(1)],a=!0),(i=parseFloat(i)||0)+Ke(e,t,n||(o?"border":"content"),a,r,i)+"px"}function et(e,t,n,r,i){return new et.prototype.init(e,t,n,r,i)}C.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Fe(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=Y(t),u=Ue.test(t),l=e.style;if(u||(t=Qe(s)),a=C.cssHooks[t]||C.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"===(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ue(e,t,i),o="number"),null!=n&&n==n&&("number"===o&&(n+=i&&i[3]||(C.cssNumber[s]?"":"px")),y.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=Y(t);return Ue.test(t)||(t=Qe(s)),(a=C.cssHooks[t]||C.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Fe(e,t,r)),"normal"===i&&t in Ve&&(i=Ve[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),C.each(["height","width"],function(e,t){C.cssHooks[t]={get:function(e,n,r){if(n)return!ze.test(C.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?Ze(e,t,r):se(e,Xe,function(){return Ze(e,t,r)})},set:function(e,n,r){var i,o=$e(e),a="border-box"===C.css(e,"boxSizing",!1,o),s=r&&Ke(e,t,r,a,o);return a&&y.scrollboxSize()===o.position&&(s-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-Ke(e,t,"border",!1,o)-.5)),s&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=C.css(e,t)),Je(0,n,s)}}}),C.cssHooks.marginLeft=_e(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Fe(e,"marginLeft"))||e.getBoundingClientRect().left-se(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),C.each({margin:"",padding:"",border:"Width"},function(e,t){C.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(C.cssHooks[e+t].set=Je)}),C.fn.extend({css:function(e,t){return U(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=$e(e),i=t.length;a<i;a++)o[t[a]]=C.css(e,t[a],!1,r);return o}return void 0!==n?C.style(e,t,n):C.css(e,t)},e,t,arguments.length>1)}}),C.Tween=et,et.prototype={constructor:et,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||C.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(C.cssNumber[n]?"":"px")},cur:function(){var e=et.propHooks[this.prop];return e&&e.get?e.get(this):et.propHooks._default.get(this)},run:function(e){var t,n=et.propHooks[this.prop];return this.options.duration?this.pos=t=C.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):et.propHooks._default.set(this),this}},et.prototype.init.prototype=et.prototype,et.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=C.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){C.fx.step[e.prop]?C.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[C.cssProps[e.prop]]&&!C.cssHooks[e.prop]?e.elem[e.prop]=e.now:C.style(e.elem,e.prop,e.now+e.unit)}}},et.propHooks.scrollTop=et.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},C.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},C.fx=et.prototype.init,C.fx.step={};var tt,nt,rt=/^(?:toggle|show|hide)$/,it=/queueHooks$/;function ot(){nt&&(!1===a.hidden&&n.requestAnimationFrame?n.requestAnimationFrame(ot):n.setTimeout(ot,C.fx.interval),C.fx.tick())}function at(){return n.setTimeout(function(){tt=void 0}),tt=Date.now()}function st(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function ut(e,t,n){for(var r,i=(lt.tweeners[t]||[]).concat(lt.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function lt(e,t,n){var r,i,o=0,a=lt.prefilters.length,s=C.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;for(var t=tt||at(),n=Math.max(0,l.startTime+l.duration-t),r=1-(n/l.duration||0),o=0,a=l.tweens.length;o<a;o++)l.tweens[o].run(r);return s.notifyWith(e,[l,r,n]),r<1&&a?n:(a||s.notifyWith(e,[l,1,0]),s.resolveWith(e,[l]),!1)},l=s.promise({elem:e,props:C.extend({},t),opts:C.extend(!0,{specialEasing:{},easing:C.easing._default},n),originalProperties:t,originalOptions:n,startTime:tt||at(),duration:n.duration,tweens:[],createTween:function(t,n){var r=C.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;n<r;n++)l.tweens[n].run(1);return t?(s.notifyWith(e,[l,1,0]),s.resolveWith(e,[l,t])):s.rejectWith(e,[l,t]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=Y(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=C.cssHooks[r])&&"expand"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);o<a;o++)if(r=lt.prefilters[o].call(l,e,c,l.opts))return m(r.stop)&&(C._queueHooks(l.elem,l.opts.queue).stop=r.stop.bind(r)),r;return C.map(c,ut,l),m(l.opts.start)&&l.opts.start.call(e,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),C.fx.timer(C.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l}C.Animation=C.extend(lt,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return ue(n.elem,e,ie.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=["*"]):e=e.match(I);for(var n,r=0,i=e.length;r<i;r++)n=e[r],lt.tweeners[n]=lt.tweeners[n]||[],lt.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f="width"in t||"height"in t,p=this,d={},h=e.style,g=e.nodeType&&ae(e),v=K.get(e,"fxshow");for(r in n.queue||(null==(a=C._queueHooks(e,"fx")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,C.queue(e,"fx").length||a.empty.fire()})})),t)if(i=t[r],rt.test(i)){if(delete t[r],o=o||"toggle"===i,i===(g?"hide":"show")){if("show"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||C.style(e,r)}if((u=!C.isEmptyObject(t))||!C.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=K.get(e,"display")),"none"===(c=C.css(e,"display"))&&(l?c=l:(fe([e],!0),l=e.style.display||l,c=C.css(e,"display"),fe([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===C.css(e,"float")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l="none"===c?"":c)),h.display="inline-block")),n.overflow&&(h.overflow="hidden",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?"hidden"in v&&(g=v.hidden):v=K.access(e,"fxshow",{display:l}),o&&(v.hidden=!g),g&&fe([e],!0),p.done(function(){for(r in g||fe([e]),K.remove(e,"fxshow"),d)C.style(e,r,d[r])})),u=ut(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?lt.prefilters.unshift(e):lt.prefilters.push(e)}}),C.speed=function(e,t,n){var r=e&&"object"==typeof e?C.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return C.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in C.fx.speeds?r.duration=C.fx.speeds[r.duration]:r.duration=C.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&C.dequeue(this,r.queue)},r},C.fn.extend({fadeTo:function(e,t,n,r){return this.filter(ae).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=C.isEmptyObject(e),o=C.speed(t,n,r),a=function(){var t=lt(this,C.extend({},e),o);(i||K.get(this,"finish"))&&t.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(e,t,n){var r=function(e){var t=e.stop;delete e.stop,t(n)};return"string"!=typeof e&&(n=t,t=e,e=void 0),t&&!1!==e&&this.queue(e||"fx",[]),this.each(function(){var t=!0,i=null!=e&&e+"queueHooks",o=C.timers,a=K.get(this);if(i)a[i]&&a[i].stop&&r(a[i]);else for(i in a)a[i]&&a[i].stop&&it.test(i)&&r(a[i]);for(i=o.length;i--;)o[i].elem!==this||null!=e&&o[i].queue!==e||(o[i].anim.stop(n),t=!1,o.splice(i,1));!t&&n||C.dequeue(this,e)})},finish:function(e){return!1!==e&&(e=e||"fx"),this.each(function(){var t,n=K.get(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=C.timers,a=r?r.length:0;for(n.finish=!0,C.queue(this,e,[]),i&&i.stop&&i.stop.call(this,!0),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;t<a;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}}),C.each(["toggle","show","hide"],function(e,t){var n=C.fn[t];C.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(st(t,!0),e,r,i)}}),C.each({slideDown:st("show"),slideUp:st("hide"),slideToggle:st("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){C.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),C.timers=[],C.fx.tick=function(){var e,t=0,n=C.timers;for(tt=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||C.fx.stop(),tt=void 0},C.fx.timer=function(e){C.timers.push(e),C.fx.start()},C.fx.interval=13,C.fx.start=function(){nt||(nt=!0,ot())},C.fx.stop=function(){nt=null},C.fx.speeds={slow:600,fast:200,_default:400},C.fn.delay=function(e,t){return e=C.fx&&C.fx.speeds[e]||e,t=t||"fx",this.queue(t,function(t,r){var i=n.setTimeout(t,e);r.stop=function(){n.clearTimeout(i)}})},function(){var e=a.createElement("input"),t=a.createElement("select").appendChild(a.createElement("option"));e.type="checkbox",y.checkOn=""!==e.value,y.optSelected=t.selected,(e=a.createElement("input")).value="t",e.type="radio",y.radioValue="t"===e.value}();var ct,ft=C.expr.attrHandle;C.fn.extend({attr:function(e,t){return U(this,C.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){C.removeAttr(this,e)})}}),C.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return void 0===e.getAttribute?C.prop(e,t,n):(1===o&&C.isXMLDoc(e)||(i=C.attrHooks[t.toLowerCase()]||(C.expr.match.bool.test(t)?ct:void 0)),void 0!==n?null===n?void C.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=C.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&"radio"===t&&A(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(I);if(i&&1===e.nodeType)for(;n=i[r++];)e.removeAttribute(n)}}),ct={set:function(e,t,n){return!1===t?C.removeAttr(e,n):e.setAttribute(n,n),n}},C.each(C.expr.match.bool.source.match(/\w+/g),function(e,t){var n=ft[t]||C.find.attr;ft[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ft[a],ft[a]=i,i=null!=n(e,t,r)?a:null,ft[a]=o),i}});var pt=/^(?:input|select|textarea|button)$/i,dt=/^(?:a|area)$/i;function ht(e){return(e.match(I)||[]).join(" ")}function gt(e){return e.getAttribute&&e.getAttribute("class")||""}function vt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(I)||[]}C.fn.extend({prop:function(e,t){return U(this,C.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[C.propFix[e]||e]})}}),C.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&C.isXMLDoc(e)||(t=C.propFix[t]||t,i=C.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=C.find.attr(e,"tabindex");return t?parseInt(t,10):pt.test(e.nodeName)||dt.test(e.nodeName)&&e.href?0:-1}}},propFix:{for:"htmlFor",class:"className"}}),y.optSelected||(C.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),C.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){C.propFix[this.toLowerCase()]=this}),C.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(m(e))return this.each(function(t){C(this).addClass(e.call(this,t,gt(this)))});if((t=vt(e)).length)for(;n=this[u++];)if(i=gt(n),r=1===n.nodeType&&" "+ht(i)+" "){for(a=0;o=t[a++];)r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=ht(r))&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(m(e))return this.each(function(t){C(this).removeClass(e.call(this,t,gt(this)))});if(!arguments.length)return this.attr("class","");if((t=vt(e)).length)for(;n=this[u++];)if(i=gt(n),r=1===n.nodeType&&" "+ht(i)+" "){for(a=0;o=t[a++];)for(;r.indexOf(" "+o+" ")>-1;)r=r.replace(" "+o+" "," ");i!==(s=ht(r))&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):m(e)?this.each(function(n){C(this).toggleClass(e.call(this,n,gt(this),t),t)}):this.each(function(){var t,i,o,a;if(r)for(i=0,o=C(this),a=vt(e);t=a[i++];)o.hasClass(t)?o.removeClass(t):o.addClass(t);else void 0!==e&&"boolean"!==n||((t=gt(this))&&K.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":K.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;for(t=" "+e+" ";n=this[r++];)if(1===n.nodeType&&(" "+ht(gt(n))+" ").indexOf(t)>-1)return!0;return!1}});var yt=/\r/g;C.fn.extend({val:function(e){var t,n,r,i=this[0];return arguments.length?(r=m(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,C(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=C.map(i,function(e){return null==e?"":e+""})),(t=C.valHooks[this.type]||C.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))})):i?(t=C.valHooks[i.type]||C.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(yt,""):null==n?"":n:void 0}}),C.extend({valHooks:{option:{get:function(e){var t=C.find.attr(e,"value");return null!=t?t:ht(C.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,"optgroup"))){if(t=C(n).val(),a)return t;s.push(t)}return s},set:function(e,t){for(var n,r,i=e.options,o=C.makeArray(t),a=i.length;a--;)((r=i[a]).selected=C.inArray(C.valHooks.option.get(r),o)>-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),C.each(["radio","checkbox"],function(){C.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=C.inArray(C(e).val(),t)>-1}},y.checkOn||(C.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),y.focusin="onfocusin"in n;var mt=/^(?:focusinfocus|focusoutblur)$/,xt=function(e){e.stopPropagation()};C.extend(C.event,{trigger:function(e,t,r,i){var o,s,u,l,c,f,p,d,g=[r||a],v=h.call(e,"type")?e.type:e,y=h.call(e,"namespace")?e.namespace.split("."):[];if(s=d=u=r=r||a,3!==r.nodeType&&8!==r.nodeType&&!mt.test(v+C.event.triggered)&&(v.indexOf(".")>-1&&(v=(y=v.split(".")).shift(),y.sort()),c=v.indexOf(":")<0&&"on"+v,(e=e[C.expando]?e:new C.Event(v,"object"==typeof e&&e)).isTrigger=i?2:3,e.namespace=y.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+y.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=r),t=null==t?[e]:C.makeArray(t,[e]),p=C.event.special[v]||{},i||!p.trigger||!1!==p.trigger.apply(r,t))){if(!i&&!p.noBubble&&!x(r)){for(l=p.delegateType||v,mt.test(l+v)||(s=s.parentNode);s;s=s.parentNode)g.push(s),u=s;u===(r.ownerDocument||a)&&g.push(u.defaultView||u.parentWindow||n)}for(o=0;(s=g[o++])&&!e.isPropagationStopped();)d=s,e.type=o>1?l:p.bindType||v,(f=(K.get(s,"events")||{})[e.type]&&K.get(s,"handle"))&&f.apply(s,t),(f=c&&s[c])&&f.apply&&Q(s)&&(e.result=f.apply(s,t),!1===e.result&&e.preventDefault());return e.type=v,i||e.isDefaultPrevented()||p._default&&!1!==p._default.apply(g.pop(),t)||!Q(r)||c&&m(r[v])&&!x(r)&&((u=r[c])&&(r[c]=null),C.event.triggered=v,e.isPropagationStopped()&&d.addEventListener(v,xt),r[v](),e.isPropagationStopped()&&d.removeEventListener(v,xt),C.event.triggered=void 0,u&&(r[c]=u)),e.result}},simulate:function(e,t,n){var r=C.extend(new C.Event,n,{type:e,isSimulated:!0});C.event.trigger(r,null,t)}}),C.fn.extend({trigger:function(e,t){return this.each(function(){C.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return C.event.trigger(e,t,n,!0)}}),y.focusin||C.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){C.event.simulate(t,e.target,C.event.fix(e))};C.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=K.access(r,t);i||r.addEventListener(e,n,!0),K.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=K.access(r,t)-1;i?K.access(r,t,i):(r.removeEventListener(e,n,!0),K.remove(r,t))}}});var bt=n.location,wt=Date.now(),Tt=/\?/;C.parseXML=function(e){var t;if(!e||"string"!=typeof e)return null;try{t=(new n.DOMParser).parseFromString(e,"text/xml")}catch(e){t=void 0}return t&&!t.getElementsByTagName("parsererror").length||C.error("Invalid XML: "+e),t};var Ct=/\[\]$/,kt=/\r?\n/g,Et=/^(?:submit|button|image|reset|file)$/i,St=/^(?:input|select|textarea|keygen)/i;function Dt(e,t,n,r){var i;if(Array.isArray(t))C.each(t,function(t,i){n||Ct.test(e)?r(e,i):Dt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)});else if(n||"object"!==T(t))r(e,t);else for(i in t)Dt(e+"["+i+"]",t[i],n,r)}C.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(Array.isArray(e)||e.jquery&&!C.isPlainObject(e))C.each(e,function(){i(this.name,this.value)});else for(n in e)Dt(n,e[n],t,i);return r.join("&")},C.fn.extend({serialize:function(){return C.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=C.prop(this,"elements");return e?C.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!C(this).is(":disabled")&&St.test(this.nodeName)&&!Et.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=C(this).val();return null==n?null:Array.isArray(n)?C.map(n,function(e){return{name:t.name,value:e.replace(kt,"\r\n")}}):{name:t.name,value:n.replace(kt,"\r\n")}}).get()}});var jt=/%20/g,Nt=/#.*$/,At=/([?&])_=[^&]*/,qt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Lt=/^(?:GET|HEAD)$/,Ht=/^\/\//,Ot={},Pt={},Mt="*/".concat("*"),Rt=a.createElement("a");function It(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(I)||[];if(m(n))for(;r=o[i++];)"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function Wt(e,t,n,r){var i={},o=e===Pt;function a(s){var u;return i[s]=!0,C.each(e[s]||[],function(e,s){var l=s(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)}),u}return a(t.dataTypes[0])||!i["*"]&&a("*")}function $t(e,t){var n,r,i=C.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&C.extend(!0,e,r),e}Rt.href=bt.href,C.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:bt.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(bt.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Mt,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":C.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?$t($t(e,C.ajaxSettings),t):$t(C.ajaxSettings,e)},ajaxPrefilter:It(Ot),ajaxTransport:It(Pt),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var r,i,o,s,u,l,c,f,p,d,h=C.ajaxSetup({},t),g=h.context||h,v=h.context&&(g.nodeType||g.jquery)?C(g):C.event,y=C.Deferred(),m=C.Callbacks("once memory"),x=h.statusCode||{},b={},w={},T="canceled",k={readyState:0,getResponseHeader:function(e){var t;if(c){if(!s)for(s={};t=qt.exec(o);)s[t[1].toLowerCase()]=t[2];t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return c?o:null},setRequestHeader:function(e,t){return null==c&&(e=w[e.toLowerCase()]=w[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==c&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(c)k.always(e[k.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||T;return r&&r.abort(t),E(0,t),this}};if(y.promise(k),h.url=((e||h.url||bt.href)+"").replace(Ht,bt.protocol+"//"),h.type=t.method||t.type||h.method||h.type,h.dataTypes=(h.dataType||"*").toLowerCase().match(I)||[""],null==h.crossDomain){l=a.createElement("a");try{l.href=h.url,l.href=l.href,h.crossDomain=Rt.protocol+"//"+Rt.host!=l.protocol+"//"+l.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=C.param(h.data,h.traditional)),Wt(Ot,h,t,k),c)return k;for(p in(f=C.event&&h.global)&&0==C.active++&&C.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!Lt.test(h.type),i=h.url.replace(Nt,""),h.hasContent?h.data&&h.processData&&0===(h.contentType||"").indexOf("application/x-www-form-urlencoded")&&(h.data=h.data.replace(jt,"+")):(d=h.url.slice(i.length),h.data&&(h.processData||"string"==typeof h.data)&&(i+=(Tt.test(i)?"&":"?")+h.data,delete h.data),!1===h.cache&&(i=i.replace(At,"$1"),d=(Tt.test(i)?"&":"?")+"_="+wt+++d),h.url=i+d),h.ifModified&&(C.lastModified[i]&&k.setRequestHeader("If-Modified-Since",C.lastModified[i]),C.etag[i]&&k.setRequestHeader("If-None-Match",C.etag[i])),(h.data&&h.hasContent&&!1!==h.contentType||t.contentType)&&k.setRequestHeader("Content-Type",h.contentType),k.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+Mt+"; q=0.01":""):h.accepts["*"]),h.headers)k.setRequestHeader(p,h.headers[p]);if(h.beforeSend&&(!1===h.beforeSend.call(g,k,h)||c))return k.abort();if(T="abort",m.add(h.complete),k.done(h.success),k.fail(h.error),r=Wt(Pt,h,t,k)){if(k.readyState=1,f&&v.trigger("ajaxSend",[k,h]),c)return k;h.async&&h.timeout>0&&(u=n.setTimeout(function(){k.abort("timeout")},h.timeout));try{c=!1,r.send(b,E)}catch(e){if(c)throw e;E(-1,e)}}else E(-1,"No Transport");function E(e,t,a,s){var l,p,d,b,w,T=t;c||(c=!0,u&&n.clearTimeout(u),r=void 0,o=s||"",k.readyState=e>0?4:0,l=e>=200&&e<300||304===e,a&&(b=function(e,t,n){for(var r,i,o,a,s=e.contents,u=e.dataTypes;"*"===u[0];)u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(h,k,a)),b=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];for(o=c.shift();o;)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e.throws)t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}(h,b,k,l),l?(h.ifModified&&((w=k.getResponseHeader("Last-Modified"))&&(C.lastModified[i]=w),(w=k.getResponseHeader("etag"))&&(C.etag[i]=w)),204===e||"HEAD"===h.type?T="nocontent":304===e?T="notmodified":(T=b.state,p=b.data,l=!(d=b.error))):(d=T,!e&&T||(T="error",e<0&&(e=0))),k.status=e,k.statusText=(t||T)+"",l?y.resolveWith(g,[p,T,k]):y.rejectWith(g,[k,T,d]),k.statusCode(x),x=void 0,f&&v.trigger(l?"ajaxSuccess":"ajaxError",[k,h,l?p:d]),m.fireWith(g,[k,T]),f&&(v.trigger("ajaxComplete",[k,h]),--C.active||C.event.trigger("ajaxStop")))}return k},getJSON:function(e,t,n){return C.get(e,t,n,"json")},getScript:function(e,t){return C.get(e,void 0,t,"script")}}),C.each(["get","post"],function(e,t){C[t]=function(e,n,r,i){return m(n)&&(i=i||r,r=n,n=void 0),C.ajax(C.extend({url:e,type:t,dataType:i,data:n,success:r},C.isPlainObject(e)&&e))}}),C._evalUrl=function(e){return C.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,throws:!0})},C.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=C(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){for(var e=this;e.firstElementChild;)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return m(e)?this.each(function(t){C(this).wrapInner(e.call(this,t))}):this.each(function(){var t=C(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=m(e);return this.each(function(n){C(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){C(this).replaceWith(this.childNodes)}),this}}),C.expr.pseudos.hidden=function(e){return!C.expr.pseudos.visible(e)},C.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},C.ajaxSettings.xhr=function(){try{return new n.XMLHttpRequest}catch(e){}};var Bt={0:200,1223:204},Ft=C.ajaxSettings.xhr();y.cors=!!Ft&&"withCredentials"in Ft,y.ajax=Ft=!!Ft,C.ajaxTransport(function(e){var t,r;if(y.cors||Ft&&!e.crossDomain)return{send:function(i,o){var a,s=e.xhr();if(s.open(e.type,e.url,e.async,e.username,e.password),e.xhrFields)for(a in e.xhrFields)s[a]=e.xhrFields[a];for(a in e.mimeType&&s.overrideMimeType&&s.overrideMimeType(e.mimeType),e.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest"),i)s.setRequestHeader(a,i[a]);t=function(e){return function(){t&&(t=r=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?o(0,"error"):o(s.status,s.statusText):o(Bt[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=t(),r=s.onerror=s.ontimeout=t("error"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&n.setTimeout(function(){t&&r()})},t=t("abort");try{s.send(e.hasContent&&e.data||null)}catch(e){if(t)throw e}},abort:function(){t&&t()}}}),C.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),C.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return C.globalEval(e),e}}}),C.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),C.ajaxTransport("script",function(e){var t,n;if(e.crossDomain)return{send:function(r,i){t=C("<script>").prop({charset:e.scriptCharset,src:e.url}).on("load error",n=function(e){t.remove(),n=null,e&&i("error"===e.type?404:200,e.type)}),a.head.appendChild(t[0])},abort:function(){n&&n()}}});var _t=[],zt=/(=)\?(?=&|$)|\?\?/;C.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=_t.pop()||C.expando+"_"+wt++;return this[e]=!0,e}}),C.ajaxPrefilter("json jsonp",function(e,t,r){var i,o,a,s=!1!==e.jsonp&&(zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&zt.test(e.data)&&"data");if(s||"jsonp"===e.dataTypes[0])return i=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,s?e[s]=e[s].replace(zt,"$1"+i):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+i),e.converters["script json"]=function(){return a||C.error(i+" was not called"),a[0]},e.dataTypes[0]="json",o=n[i],n[i]=function(){a=arguments},r.always(function(){void 0===o?C(n).removeProp(i):n[i]=o,e[i]&&(e.jsonpCallback=t.jsonpCallback,_t.push(i)),a&&m(o)&&o(a[0]),a=o=void 0}),"script"}),y.createHTMLDocument=function(){var e=a.implementation.createHTMLDocument("").body;return e.innerHTML="<form></form><form></form>",2===e.childNodes.length}(),C.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=a.implementation.createHTMLDocument("")).createElement("base")).href=a.location.href,t.head.appendChild(r)):t=a),i=q.exec(e),o=!n&&[],i?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&C(o).remove(),C.merge([],i.childNodes)));var r,i,o},C.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return s>-1&&(r=ht(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),a.length>0&&C.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?C("<div>").append(C.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},C.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){C.fn[t]=function(e){return this.on(t,e)}}),C.expr.pseudos.animated=function(e){return C.grep(C.timers,function(t){return e===t.elem}).length},C.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=C.css(e,"position"),c=C(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=C.css(e,"top"),u=C.css(e,"left"),("absolute"===l||"fixed"===l)&&(o+u).indexOf("auto")>-1?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,C.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},C.fn.extend({offset:function(e){if(arguments.length)return void 0===e?this:this.each(function(t){C.offset.setOffset(this,e,t)});var t,n,r=this[0];return r?r.getClientRects().length?(t=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:t.top+n.pageYOffset,left:t.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===C.css(r,"position"))t=r.getBoundingClientRect();else{for(t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;e&&(e===n.body||e===n.documentElement)&&"static"===C.css(e,"position");)e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=C(e).offset()).top+=C.css(e,"borderTopWidth",!0),i.left+=C.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-C.css(r,"marginTop",!0),left:t.left-i.left-C.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){for(var e=this.offsetParent;e&&"static"===C.css(e,"position");)e=e.offsetParent;return e||be})}}),C.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,t){var n="pageYOffset"===t;C.fn[e]=function(r){return U(this,function(e,r,i){var o;if(x(e)?o=e:9===e.nodeType&&(o=e.defaultView),void 0===i)return o?o[t]:e[r];o?o.scrollTo(n?o.pageXOffset:i,n?i:o.pageYOffset):e[r]=i},e,r,arguments.length)}}),C.each(["top","left"],function(e,t){C.cssHooks[t]=_e(y.pixelPosition,function(e,n){if(n)return n=Fe(e,t),We.test(n)?C(e).position()[t]+"px":n})}),C.each({Height:"height",Width:"width"},function(e,t){C.each({padding:"inner"+e,content:t,"":"outer"+e},function(n,r){C.fn[r]=function(i,o){var a=arguments.length&&(n||"boolean"!=typeof i),s=n||(!0===i||!0===o?"margin":"border");return U(this,function(t,n,i){var o;return x(t)?0===r.indexOf("outer")?t["inner"+e]:t.document.documentElement["client"+e]:9===t.nodeType?(o=t.documentElement,Math.max(t.body["scroll"+e],o["scroll"+e],t.body["offset"+e],o["offset"+e],o["client"+e])):void 0===i?C.css(t,n,s):C.style(t,n,i,s)},t,a?i:void 0,a)}})}),C.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,t){C.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),C.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),C.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}}),C.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=u.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(u.call(arguments)))}).guid=e.guid=e.guid||C.guid++,i},C.holdReady=function(e){e?C.readyWait++:C.ready(!0)},C.isArray=Array.isArray,C.parseJSON=JSON.parse,C.nodeName=A,C.isFunction=m,C.isWindow=x,C.camelCase=Y,C.type=T,C.now=Date.now,C.isNumeric=function(e){var t=C.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},void 0===(r=function(){return C}.apply(t,[]))||(e.exports=r);var Ut=n.jQuery,Xt=n.$;return C.noConflict=function(e){return n.$===C&&(n.$=Xt),e&&n.jQuery===C&&(n.jQuery=Ut),C},i||(n.jQuery=n.$=C),C})},function(e,t,n){"use strict";n(2);var r=function(e){return e&&e.__esModule?e:{default:e}}(n(0));(0,r.default)(document).ready(function(){function e(){var e=(0,r.default)(this).parents("span:first");e.addClass("sectoken-del").fadeOut("fast",function(){e.remove()})}(0,r.default)("#editor-users-add, #editor-roles-add, #exuser-query-add, #exrole-query-add, #ipaddr-query-add").click(function(){var t=(0,r.default)(this).attr("id").substr(0,6),n=(0,r.default)(this).attr("id").substr(7,5),i=r.default.trim((0,r.default)("#"+t+"-"+n+"-box").val()),o=(0,r.default)("#"+t+"-list input").filter(function(){return this.value===i});i&&!o.length&&((0,r.default)("#"+t+"-"+n+"-box, #"+t+"-"+n+"-add").attr("disabled",!0),r.default.ajax({type:"POST",url:wsalData.ajaxURL,async:!0,data:{action:"setup_check_security_token",token:i,nonce:wsalData.nonce},dataType:"json",success:function(i){if((0,r.default)("#"+t+"-"+n+"-box, #"+t+"-"+n+"-add").removeAttr("disabled"),(0,r.default)("#"+t+"-"+n+"-box").val(""),i.success){if("other"===i.tokenType&&("users"===n||"exuser"===t))return void alert(wsalData.usersError);if("other"===i.tokenType&&("roles"===n||"exrole"===t))return void alert(wsalData.rolesError);if("other"===i.tokenType&&("ip"===n||"ipaddr"===t))return void alert(wsalData.ipError);(0,r.default)("#"+t+"-list").append((0,r.default)('<span class="sectoken-'+i.tokenType+'"/>').text(i.token).append((0,r.default)('<input type="hidden" name="'+t+'s[]"/>').val(i.token),(0,r.default)('<a href="javascript:;" title="Remove">×</a>').click(e)))}else alert(i.message)},error:function(e,t,n){console.log(e.statusText),console.log(t),console.log(n)}}))}),(0,r.default)("#editor-users-box, #editor-roles-box, #exuser-query-box, #exrole-query-box, #ipaddr-query-box").keydown(function(e){if(13===e.keyCode){var t=(0,r.default)(this).attr("id").substr(0,6),n=(0,r.default)(this).attr("id").substr(7,5);return(0,r.default)("#"+t+"-"+n+"-add").click(),!1}}),(0,r.default)("#editor-list>span>a, #exuser-list>span>a, #exrole-list>span>a, #ipaddr-list>span>a").click(e)})},function(e,t){}]);
|
js/settings.js
CHANGED
@@ -1,91 +1,106 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
|
|
|
|
|
|
|
|
|
|
5 |
$this.remove();
|
6 |
});
|
7 |
};
|
8 |
|
9 |
-
jQuery( '#ViewerQueryBox, #EditorQueryBox, #ExRoleQueryBox, #ExUserQueryBox, #CustomQueryBox, #IpAddrQueryBox, #ExCPTsQueryBox' ).keydown( function( event ) {
|
10 |
-
if ( event.keyCode
|
11 |
-
var type = jQuery(this).attr('id').substr(0, 6);
|
12 |
console.log( type );
|
13 |
-
jQuery('#'+type+'QueryAdd').click();
|
14 |
return false;
|
15 |
}
|
16 |
-
}
|
17 |
-
|
18 |
-
jQuery( '#ViewerQueryAdd, #EditorQueryAdd, #ExRoleQueryAdd, #ExUserQueryAdd, #CustomQueryAdd, #IpAddrQueryAdd, #ExCPTsQueryAdd, #ExURLsQueryAdd' ).click(function(){
|
19 |
-
var type = jQuery(this).attr('id').substr(0, 6);
|
20 |
-
var value = jQuery.trim( jQuery( '#'+type+'QueryBox' ).val() );
|
21 |
-
var existing = jQuery('#'+type+'List input').filter( function() {
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
return;
|
39 |
}
|
40 |
}
|
41 |
-
|
42 |
-
jQuery( '#'+type+'List' ).append( jQuery( '<span class="sectoken-'+data+'"/>' ).text(value).append(
|
43 |
-
jQuery( '<input type="hidden" name="'+type+'s[]"/>' ).val(value),
|
44 |
-
jQuery( '<a href="javascript:;" title="Remove">×</a>' ).click(RemoveSecToken)
|
45 |
-
) );
|
46 |
-
} );
|
47 |
});
|
48 |
|
49 |
jQuery( '#ViewerList>span>a, #EditorList>span>a, #ExRoleList>span>a, #ExUserList>span>a, #CustomList>span>a, #IpAddrList>span>a, #ExCPTsList>span>a, #ExURLsList>span>a' ).click( RemoveSecToken );
|
50 |
|
51 |
-
|
52 |
-
|
53 |
-
var fltr = function() { return this.value === user; };
|
54 |
-
if (this.checked) {
|
55 |
-
if (jQuery('#EditorList input').filter(fltr).length === 1) {
|
56 |
-
jQuery('#EditorList .sectoken-user').each(function(){
|
57 |
-
if (jQuery(this).find('input[type=hidden]').val() === user) {
|
58 |
-
jQuery(this).remove();
|
59 |
-
}
|
60 |
-
});
|
61 |
-
}
|
62 |
-
jQuery('#EditorList').append(jQuery('<span class="sectoken-user"/>').text(user).prepend(jQuery('<input type="hidden" name="Editors[]"/>').val(user)));
|
63 |
-
} else if (!this.checked){
|
64 |
-
jQuery('#EditorList .sectoken-user').each(function(){
|
65 |
-
if (jQuery(this).find('input[type=hidden]').val() === user) {
|
66 |
-
jQuery(this).remove();
|
67 |
-
}
|
68 |
-
});
|
69 |
-
}
|
70 |
-
});
|
71 |
-
|
72 |
-
var usersUrl = ajaxurl + "?action=AjaxGetAllUsers&wsal_nonce=" + wsal_data.wp_nonce;
|
73 |
-
jQuery("#ExUserQueryBox").autocomplete({
|
74 |
source: usersUrl,
|
75 |
-
minLength:1
|
76 |
});
|
77 |
|
78 |
-
var rolesUrl = ajaxurl +
|
79 |
-
jQuery(
|
80 |
source: rolesUrl,
|
81 |
-
minLength:1
|
82 |
});
|
83 |
|
84 |
-
var cptsUrl = ajaxurl +
|
85 |
-
jQuery( '#ExCPTsQueryBox' ).autocomplete(
|
86 |
source: cptsUrl,
|
87 |
-
minLength: 1
|
88 |
-
}
|
89 |
|
90 |
// Enable setting.
|
91 |
function wsal_enable_setting( setting ) {
|
@@ -118,7 +133,7 @@ jQuery(document).ready(function(){
|
|
118 |
jQuery( '#wsal_remove_exception_dir' ),
|
119 |
jQuery( '#wsal_files input[type=checkbox]' ),
|
120 |
jQuery( '#wsal_files_types input[type=checkbox]' ),
|
121 |
-
jQuery( '#wsal_dirs input[type=checkbox]' )
|
122 |
];
|
123 |
|
124 |
// Update settings of file changes on page load.
|
@@ -135,18 +150,18 @@ jQuery(document).ready(function(){
|
|
135 |
} else {
|
136 |
file_changes_settings.forEach( wsal_disable_setting ); // Disable the settings.
|
137 |
}
|
138 |
-
}
|
139 |
|
140 |
// Scan frequency.
|
141 |
var scan_frequency = jQuery( 'select[name=wsal-scan-frequency]' ); // Frequency.
|
142 |
-
var scan_days = jQuery( 'span#wsal-scan-day'); // Day of the week.
|
143 |
-
var scan_date = jQuery( 'span#wsal-scan-date'); // Date of the month.
|
144 |
wsal_update_scan_time( scan_frequency, scan_days, scan_date ); // Update on page load.
|
145 |
|
146 |
// Update when frequency is changed.
|
147 |
scan_frequency.change( function() {
|
148 |
wsal_update_scan_time( scan_frequency, scan_days, scan_date );
|
149 |
-
}
|
150 |
|
151 |
/**
|
152 |
* Updates the display of days and date option based on
|
@@ -157,10 +172,10 @@ jQuery(document).ready(function(){
|
|
157 |
* @param {object} date Date selector.
|
158 |
*/
|
159 |
function wsal_update_scan_time( frequency, days, date ) {
|
160 |
-
if ( frequency.val()
|
161 |
date.addClass( 'hide' );
|
162 |
days.removeClass( 'hide' );
|
163 |
-
} else if ( frequency.val()
|
164 |
days.addClass( 'hide' );
|
165 |
date.removeClass( 'hide' );
|
166 |
} else {
|
@@ -172,17 +187,17 @@ jQuery(document).ready(function(){
|
|
172 |
// Add directory to scan file exception list.
|
173 |
jQuery( '#wsal_add_dir' ).click( function() {
|
174 |
wsal_add_scan_exception( 'dir' );
|
175 |
-
}
|
176 |
|
177 |
// Add file to scan file exception list.
|
178 |
jQuery( '#wsal_add_file' ).click( function() {
|
179 |
wsal_add_scan_exception( 'file' );
|
180 |
-
}
|
181 |
|
182 |
// Add file extension to scan extension exception list.
|
183 |
jQuery( '#wsal_add_file_type' ).click( function() {
|
184 |
wsal_add_scan_exception( 'extension' );
|
185 |
-
}
|
186 |
|
187 |
/**
|
188 |
* Add exception for file changes scan.
|
@@ -190,7 +205,7 @@ jQuery(document).ready(function(){
|
|
190 |
* @param {string} type Type of exception added. For example, a `file` or an `extension`.
|
191 |
*/
|
192 |
function wsal_add_scan_exception( type ) {
|
193 |
-
if (
|
194 |
var setting_input = jQuery( '#wsal_add_file_name' );
|
195 |
var setting_value = setting_input.val();
|
196 |
var setting_container = jQuery( '#wsal_files' );
|
@@ -199,7 +214,7 @@ jQuery(document).ready(function(){
|
|
199 |
|
200 |
// Validate file name.
|
201 |
var pattern = /^\s*[a-z-._\d,\s]+\s*$/i;
|
202 |
-
} else if (
|
203 |
var setting_input = jQuery( '#wsal_add_file_type_name' );
|
204 |
var setting_value = setting_input.val();
|
205 |
var setting_container = jQuery( '#wsal_files_types' );
|
@@ -208,7 +223,7 @@ jQuery(document).ready(function(){
|
|
208 |
|
209 |
// Validate file name.
|
210 |
var pattern = /^\s*[a-z-._\d,\s]+\s*$/i;
|
211 |
-
} else if (
|
212 |
var setting_input = jQuery( '#wsal_add_dir_name' );
|
213 |
var setting_value = setting_input.val();
|
214 |
var setting_container = jQuery( '#wsal_dirs' );
|
@@ -221,8 +236,9 @@ jQuery(document).ready(function(){
|
|
221 |
setting_error.addClass( 'hide' );
|
222 |
|
223 |
if ( setting_value.match( pattern ) ) {
|
|
|
224 |
// Ajax request to add file to scan file exception list.
|
225 |
-
jQuery.ajax(
|
226 |
type: 'POST',
|
227 |
url: ajaxurl,
|
228 |
async: true,
|
@@ -231,7 +247,7 @@ jQuery(document).ready(function(){
|
|
231 |
action: 'wsal_scan_add_exception',
|
232 |
nonce: setting_nonce,
|
233 |
data_name: setting_value,
|
234 |
-
data_type: type
|
235 |
},
|
236 |
success: function( data ) {
|
237 |
if ( data.success ) {
|
@@ -261,14 +277,14 @@ jQuery(document).ready(function(){
|
|
261 |
console.log( textStatus );
|
262 |
console.log( error );
|
263 |
}
|
264 |
-
}
|
265 |
} else {
|
266 |
-
if (
|
267 |
-
alert(
|
268 |
-
} else if (
|
269 |
-
alert(
|
270 |
-
} else if (
|
271 |
-
alert(
|
272 |
}
|
273 |
}
|
274 |
}
|
@@ -276,17 +292,17 @@ jQuery(document).ready(function(){
|
|
276 |
// Remove directories from scan file exception list.
|
277 |
jQuery( '#wsal_remove_exception_dir' ).click( function() {
|
278 |
wsal_remove_scan_exception( 'dir' );
|
279 |
-
}
|
280 |
|
281 |
// Remove files from scan file exception list.
|
282 |
jQuery( '#wsal_remove_exception_file' ).click( function() {
|
283 |
wsal_remove_scan_exception( 'file' );
|
284 |
-
}
|
285 |
|
286 |
// Remove file extensions from scan file extensions exception list.
|
287 |
jQuery( '#wsal_remove_exception_file_type' ).click( function() {
|
288 |
wsal_remove_scan_exception( 'extension' );
|
289 |
-
}
|
290 |
|
291 |
/**
|
292 |
* Remove exception for changes scan.
|
@@ -294,13 +310,13 @@ jQuery(document).ready(function(){
|
|
294 |
* @param {string} type Type of exception removed. For example, a `file` or an `extension`.
|
295 |
*/
|
296 |
function wsal_remove_scan_exception( type ) {
|
297 |
-
if (
|
298 |
var setting_values = jQuery( '#wsal_files input[type=checkbox]' ); // Get files.
|
299 |
var setting_nonce = jQuery( '#wsal_scan_remove_exception_file' ).val(); // Nonce.
|
300 |
-
} else if (
|
301 |
var setting_values = jQuery( '#wsal_files_types input[type=checkbox]' ); // Get files.
|
302 |
var setting_nonce = jQuery( '#wsal_scan_remove_exception_file_type' ).val(); // Nonce.
|
303 |
-
} else if (
|
304 |
var setting_values = jQuery( '#wsal_dirs input[type=checkbox]' ); // Get files.
|
305 |
var setting_nonce = jQuery( '#wsal_scan_remove_exception_dir' ).val(); // Nonce.
|
306 |
}
|
@@ -308,13 +324,13 @@ jQuery(document).ready(function(){
|
|
308 |
// Make array of files which are checked.
|
309 |
var removed_values = [];
|
310 |
for ( var index = 0; index < setting_values.length; index++ ) {
|
311 |
-
if ( jQuery( setting_values[ index ]
|
312 |
-
removed_values.push( jQuery( setting_values[ index ]
|
313 |
}
|
314 |
}
|
315 |
|
316 |
// Ajax request to remove array of files from file exception list.
|
317 |
-
jQuery.ajax(
|
318 |
type: 'POST',
|
319 |
url: ajaxurl,
|
320 |
async: true,
|
@@ -323,10 +339,11 @@ jQuery(document).ready(function(){
|
|
323 |
action: 'wsal_scan_remove_exception',
|
324 |
nonce: setting_nonce,
|
325 |
data_type: type,
|
326 |
-
data_removed: removed_values
|
327 |
},
|
328 |
success: function( data ) {
|
329 |
if ( data.success ) {
|
|
|
330 |
// Remove files from list on the page.
|
331 |
for ( index = 0; index < removed_values.length; index++ ) {
|
332 |
var setting_value = jQuery( 'input[value="' + removed_values[ index ] + '"]' );
|
@@ -343,7 +360,7 @@ jQuery(document).ready(function(){
|
|
343 |
console.log( textStatus );
|
344 |
console.log( error );
|
345 |
}
|
346 |
-
}
|
347 |
}
|
348 |
|
349 |
// Scan now start button.
|
@@ -353,7 +370,7 @@ jQuery(document).ready(function(){
|
|
353 |
// Change button text.
|
354 |
var scan_btn = jQuery( this );
|
355 |
scan_btn.attr( 'disabled', 'disabled' );
|
356 |
-
scan_btn.text(
|
357 |
|
358 |
// Stop scan button.
|
359 |
var stop_scan_btn = jQuery( '#wsal-stop-scan' );
|
@@ -364,23 +381,24 @@ jQuery(document).ready(function(){
|
|
364 |
var manual_scan_nonce = jQuery( '#wsal-scan-now-nonce' ).val();
|
365 |
|
366 |
// Ajax request to remove array of files from file exception list.
|
367 |
-
jQuery.ajax(
|
368 |
type: 'POST',
|
369 |
url: ajaxurl,
|
370 |
async: true,
|
371 |
dataType: 'json',
|
372 |
data: {
|
373 |
action: 'wsal_manual_scan_now',
|
374 |
-
nonce: manual_scan_nonce
|
375 |
},
|
376 |
success: function( data ) {
|
377 |
if ( data.success ) {
|
|
|
378 |
// Change button text.
|
379 |
-
scan_btn.text(
|
380 |
scan_btn.removeAttr( 'disabled' );
|
381 |
stop_scan_btn.attr( 'disabled', 'disabled' );
|
382 |
} else {
|
383 |
-
scan_btn.text(
|
384 |
console.log( data.message );
|
385 |
}
|
386 |
},
|
@@ -389,8 +407,8 @@ jQuery(document).ready(function(){
|
|
389 |
console.log( textStatus );
|
390 |
console.log( error );
|
391 |
}
|
392 |
-
}
|
393 |
-
}
|
394 |
|
395 |
// Stop scan start button.
|
396 |
jQuery( '#wsal-stop-scan' ).click( function( event ) {
|
@@ -401,17 +419,18 @@ jQuery(document).ready(function(){
|
|
401 |
stop_scan_btn.attr( 'disabled', 'disabled' );
|
402 |
|
403 |
// Ajax request to remove array of files from file exception list.
|
404 |
-
jQuery.ajax(
|
405 |
type: 'POST',
|
406 |
url: ajaxurl,
|
407 |
async: true,
|
408 |
dataType: 'json',
|
409 |
data: {
|
410 |
action: 'wsal_stop_file_changes_scan',
|
411 |
-
nonce: jQuery( '#wsal-stop-scan-nonce' ).val()
|
412 |
},
|
413 |
success: function( data ) {
|
414 |
if ( data.success ) {
|
|
|
415 |
// Change button text.
|
416 |
// stop_scan_btn.removeAttr( 'disabled' );
|
417 |
} else {
|
@@ -423,6 +442,44 @@ jQuery(document).ready(function(){
|
|
423 |
console.log( textStatus );
|
424 |
console.log( error );
|
425 |
}
|
426 |
-
}
|
427 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
428 |
});
|
1 |
+
/**
|
2 |
+
* Settings Page Script
|
3 |
+
*
|
4 |
+
* @since 1.0.0
|
5 |
+
*/
|
6 |
+
jQuery( document ).ready( function() {
|
7 |
+
var RemoveSecToken = function() {
|
8 |
+
var $this = jQuery( this ).parents( 'span:first' );
|
9 |
+
$this.addClass( 'sectoken-del' ).fadeOut( 'fast', function() {
|
10 |
$this.remove();
|
11 |
});
|
12 |
};
|
13 |
|
14 |
+
jQuery( '#ViewerQueryBox, #EditorQueryBox, #ExRoleQueryBox, #ExUserQueryBox, #CustomQueryBox, #IpAddrQueryBox, #ExCPTsQueryBox, #ExURLsQueryBox' ).keydown( function( event ) {
|
15 |
+
if ( 13 === event.keyCode ) {
|
16 |
+
var type = jQuery( this ).attr( 'id' ).substr( 0, 6 );
|
17 |
console.log( type );
|
18 |
+
jQuery( '#' + type + 'QueryAdd' ).click();
|
19 |
return false;
|
20 |
}
|
21 |
+
});
|
22 |
+
|
23 |
+
jQuery( '#ViewerQueryAdd, #EditorQueryAdd, #ExRoleQueryAdd, #ExUserQueryAdd, #CustomQueryAdd, #IpAddrQueryAdd, #ExCPTsQueryAdd, #ExURLsQueryAdd' ).click( function() {
|
24 |
+
var type = jQuery( this ).attr( 'id' ).substr( 0, 6 );
|
25 |
+
var value = jQuery.trim( jQuery( '#' + type + 'QueryBox' ).val() );
|
26 |
+
var existing = jQuery( '#' + type + 'List input' ).filter( function() {
|
27 |
+
return this.value === value;
|
28 |
+
});
|
29 |
+
|
30 |
+
if ( ! value || existing.length ) {
|
31 |
+
return;
|
32 |
+
} // if value is empty or already used, stop here
|
33 |
+
|
34 |
+
jQuery( '#' + type + 'QueryBox, #' + type + 'QueryAdd' ).attr( 'disabled', true );
|
35 |
+
jQuery.post(
|
36 |
+
jQuery( '#ajaxurl' ).val(),
|
37 |
+
{
|
38 |
+
action: 'AjaxCheckSecurityToken',
|
39 |
+
token: value,
|
40 |
+
nonce: wsal_data.wp_nonce
|
41 |
+
},
|
42 |
+
function( data ) {
|
43 |
+
data = JSON.parse( data );
|
44 |
+
jQuery( '#' + type + 'QueryBox, #' + type + 'QueryAdd' ).attr( 'disabled', false );
|
45 |
+
if ( data.success ) {
|
46 |
+
if ( 'ExURLs' === type ) {
|
47 |
+
if ( 'other' === data.tokenType ) {
|
48 |
+
alert( wsal_data.invalidURL );
|
49 |
+
jQuery( '#' + type + 'QueryBox' ).val( '' );
|
50 |
+
return;
|
51 |
+
}
|
52 |
+
} else if ( 'ExCPTs' === type ) {
|
53 |
+
if ( 'other' === data.tokenType ) {
|
54 |
+
alert( wsal_data.invalidCPT );
|
55 |
+
jQuery( '#' + type + 'QueryBox' ).val( '' );
|
56 |
+
return;
|
57 |
+
}
|
58 |
+
} else if ( 'IpAddr' === type ) {
|
59 |
+
if ( 'other' === data.tokenType ) {
|
60 |
+
alert( wsal_data.invalidIP );
|
61 |
+
jQuery( '#' + type + 'QueryBox' ).val( '' );
|
62 |
+
return;
|
63 |
+
}
|
64 |
+
} else if ( 'Custom' != type && 'IpAddr' != type ) {
|
65 |
+
if ( 'other' === data.tokenType ) {
|
66 |
+
alert( wsal_data.invalidUser );
|
67 |
+
jQuery( '#' + type + 'QueryBox' ).val( '' );
|
68 |
+
return;
|
69 |
+
}
|
70 |
+
}
|
71 |
+
jQuery( '#' + type + 'QueryBox' ).val( '' );
|
72 |
+
jQuery( '#' + type + 'List' ).append( jQuery( '<span class="sectoken-' + data.tokenType + '"/>' ).text( data.token ).append(
|
73 |
+
jQuery( '<input type="hidden" name="' + type + 's[]"/>' ).val( data.token ),
|
74 |
+
jQuery( '<a href="javascript:;" title="Remove">×</a>' ).click( RemoveSecToken )
|
75 |
+
) );
|
76 |
+
} else {
|
77 |
+
alert( data.message );
|
78 |
+
jQuery( '#' + type + 'QueryBox' ).val( '' );
|
79 |
return;
|
80 |
}
|
81 |
}
|
82 |
+
);
|
|
|
|
|
|
|
|
|
|
|
83 |
});
|
84 |
|
85 |
jQuery( '#ViewerList>span>a, #EditorList>span>a, #ExRoleList>span>a, #ExUserList>span>a, #CustomList>span>a, #IpAddrList>span>a, #ExCPTsList>span>a, #ExURLsList>span>a' ).click( RemoveSecToken );
|
86 |
|
87 |
+
var usersUrl = ajaxurl + '?action=AjaxGetAllUsers&wsal_nonce=' + wsal_data.wp_nonce;
|
88 |
+
jQuery( '#ExUserQueryBox' ).autocomplete({
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
source: usersUrl,
|
90 |
+
minLength: 1
|
91 |
});
|
92 |
|
93 |
+
var rolesUrl = ajaxurl + '?action=AjaxGetAllRoles&wsal_nonce=' + wsal_data.wp_nonce;
|
94 |
+
jQuery( '#ExRoleQueryBox' ).autocomplete({
|
95 |
source: rolesUrl,
|
96 |
+
minLength: 1
|
97 |
});
|
98 |
|
99 |
+
var cptsUrl = ajaxurl + '?action=AjaxGetAllCPT&wsal_nonce=' + wsal_data.wp_nonce;
|
100 |
+
jQuery( '#ExCPTsQueryBox' ).autocomplete({
|
101 |
source: cptsUrl,
|
102 |
+
minLength: 1
|
103 |
+
});
|
104 |
|
105 |
// Enable setting.
|
106 |
function wsal_enable_setting( setting ) {
|
133 |
jQuery( '#wsal_remove_exception_dir' ),
|
134 |
jQuery( '#wsal_files input[type=checkbox]' ),
|
135 |
jQuery( '#wsal_files_types input[type=checkbox]' ),
|
136 |
+
jQuery( '#wsal_dirs input[type=checkbox]' )
|
137 |
];
|
138 |
|
139 |
// Update settings of file changes on page load.
|
150 |
} else {
|
151 |
file_changes_settings.forEach( wsal_disable_setting ); // Disable the settings.
|
152 |
}
|
153 |
+
});
|
154 |
|
155 |
// Scan frequency.
|
156 |
var scan_frequency = jQuery( 'select[name=wsal-scan-frequency]' ); // Frequency.
|
157 |
+
var scan_days = jQuery( 'span#wsal-scan-day' ); // Day of the week.
|
158 |
+
var scan_date = jQuery( 'span#wsal-scan-date' ); // Date of the month.
|
159 |
wsal_update_scan_time( scan_frequency, scan_days, scan_date ); // Update on page load.
|
160 |
|
161 |
// Update when frequency is changed.
|
162 |
scan_frequency.change( function() {
|
163 |
wsal_update_scan_time( scan_frequency, scan_days, scan_date );
|
164 |
+
});
|
165 |
|
166 |
/**
|
167 |
* Updates the display of days and date option based on
|
172 |
* @param {object} date Date selector.
|
173 |
*/
|
174 |
function wsal_update_scan_time( frequency, days, date ) {
|
175 |
+
if ( 'weekly' === frequency.val() ) {
|
176 |
date.addClass( 'hide' );
|
177 |
days.removeClass( 'hide' );
|
178 |
+
} else if ( 'monthly' === frequency.val() ) {
|
179 |
days.addClass( 'hide' );
|
180 |
date.removeClass( 'hide' );
|
181 |
} else {
|
187 |
// Add directory to scan file exception list.
|
188 |
jQuery( '#wsal_add_dir' ).click( function() {
|
189 |
wsal_add_scan_exception( 'dir' );
|
190 |
+
});
|
191 |
|
192 |
// Add file to scan file exception list.
|
193 |
jQuery( '#wsal_add_file' ).click( function() {
|
194 |
wsal_add_scan_exception( 'file' );
|
195 |
+
});
|
196 |
|
197 |
// Add file extension to scan extension exception list.
|
198 |
jQuery( '#wsal_add_file_type' ).click( function() {
|
199 |
wsal_add_scan_exception( 'extension' );
|
200 |
+
});
|
201 |
|
202 |
/**
|
203 |
* Add exception for file changes scan.
|
205 |
* @param {string} type Type of exception added. For example, a `file` or an `extension`.
|
206 |
*/
|
207 |
function wsal_add_scan_exception( type ) {
|
208 |
+
if ( 'file' === type ) {
|
209 |
var setting_input = jQuery( '#wsal_add_file_name' );
|
210 |
var setting_value = setting_input.val();
|
211 |
var setting_container = jQuery( '#wsal_files' );
|
214 |
|
215 |
// Validate file name.
|
216 |
var pattern = /^\s*[a-z-._\d,\s]+\s*$/i;
|
217 |
+
} else if ( 'extension' === type ) {
|
218 |
var setting_input = jQuery( '#wsal_add_file_type_name' );
|
219 |
var setting_value = setting_input.val();
|
220 |
var setting_container = jQuery( '#wsal_files_types' );
|
223 |
|
224 |
// Validate file name.
|
225 |
var pattern = /^\s*[a-z-._\d,\s]+\s*$/i;
|
226 |
+
} else if ( 'dir' === type ) {
|
227 |
var setting_input = jQuery( '#wsal_add_dir_name' );
|
228 |
var setting_value = setting_input.val();
|
229 |
var setting_container = jQuery( '#wsal_dirs' );
|
236 |
setting_error.addClass( 'hide' );
|
237 |
|
238 |
if ( setting_value.match( pattern ) ) {
|
239 |
+
|
240 |
// Ajax request to add file to scan file exception list.
|
241 |
+
jQuery.ajax({
|
242 |
type: 'POST',
|
243 |
url: ajaxurl,
|
244 |
async: true,
|
247 |
action: 'wsal_scan_add_exception',
|
248 |
nonce: setting_nonce,
|
249 |
data_name: setting_value,
|
250 |
+
data_type: type
|
251 |
},
|
252 |
success: function( data ) {
|
253 |
if ( data.success ) {
|
277 |
console.log( textStatus );
|
278 |
console.log( error );
|
279 |
}
|
280 |
+
});
|
281 |
} else {
|
282 |
+
if ( 'file' === type ) {
|
283 |
+
alert( wsal_data.invalidFile );
|
284 |
+
} else if ( 'extension' === type ) {
|
285 |
+
alert( wsal_data.invalidFileExt );
|
286 |
+
} else if ( 'dir' === type ) {
|
287 |
+
alert( wsal_data.invalidDir );
|
288 |
}
|
289 |
}
|
290 |
}
|
292 |
// Remove directories from scan file exception list.
|
293 |
jQuery( '#wsal_remove_exception_dir' ).click( function() {
|
294 |
wsal_remove_scan_exception( 'dir' );
|
295 |
+
});
|
296 |
|
297 |
// Remove files from scan file exception list.
|
298 |
jQuery( '#wsal_remove_exception_file' ).click( function() {
|
299 |
wsal_remove_scan_exception( 'file' );
|
300 |
+
});
|
301 |
|
302 |
// Remove file extensions from scan file extensions exception list.
|
303 |
jQuery( '#wsal_remove_exception_file_type' ).click( function() {
|
304 |
wsal_remove_scan_exception( 'extension' );
|
305 |
+
});
|
306 |
|
307 |
/**
|
308 |
* Remove exception for changes scan.
|
310 |
* @param {string} type Type of exception removed. For example, a `file` or an `extension`.
|
311 |
*/
|
312 |
function wsal_remove_scan_exception( type ) {
|
313 |
+
if ( 'file' === type ) {
|
314 |
var setting_values = jQuery( '#wsal_files input[type=checkbox]' ); // Get files.
|
315 |
var setting_nonce = jQuery( '#wsal_scan_remove_exception_file' ).val(); // Nonce.
|
316 |
+
} else if ( 'extension' === type ) {
|
317 |
var setting_values = jQuery( '#wsal_files_types input[type=checkbox]' ); // Get files.
|
318 |
var setting_nonce = jQuery( '#wsal_scan_remove_exception_file_type' ).val(); // Nonce.
|
319 |
+
} else if ( 'dir' === type ) {
|
320 |
var setting_values = jQuery( '#wsal_dirs input[type=checkbox]' ); // Get files.
|
321 |
var setting_nonce = jQuery( '#wsal_scan_remove_exception_dir' ).val(); // Nonce.
|
322 |
}
|
324 |
// Make array of files which are checked.
|
325 |
var removed_values = [];
|
326 |
for ( var index = 0; index < setting_values.length; index++ ) {
|
327 |
+
if ( jQuery( setting_values[ index ]).is( ':checked' ) ) {
|
328 |
+
removed_values.push( jQuery( setting_values[ index ]).val() );
|
329 |
}
|
330 |
}
|
331 |
|
332 |
// Ajax request to remove array of files from file exception list.
|
333 |
+
jQuery.ajax({
|
334 |
type: 'POST',
|
335 |
url: ajaxurl,
|
336 |
async: true,
|
339 |
action: 'wsal_scan_remove_exception',
|
340 |
nonce: setting_nonce,
|
341 |
data_type: type,
|
342 |
+
data_removed: removed_values
|
343 |
},
|
344 |
success: function( data ) {
|
345 |
if ( data.success ) {
|
346 |
+
|
347 |
// Remove files from list on the page.
|
348 |
for ( index = 0; index < removed_values.length; index++ ) {
|
349 |
var setting_value = jQuery( 'input[value="' + removed_values[ index ] + '"]' );
|
360 |
console.log( textStatus );
|
361 |
console.log( error );
|
362 |
}
|
363 |
+
});
|
364 |
}
|
365 |
|
366 |
// Scan now start button.
|
370 |
// Change button text.
|
371 |
var scan_btn = jQuery( this );
|
372 |
scan_btn.attr( 'disabled', 'disabled' );
|
373 |
+
scan_btn.text( wsal_data.scanInProgress );
|
374 |
|
375 |
// Stop scan button.
|
376 |
var stop_scan_btn = jQuery( '#wsal-stop-scan' );
|
381 |
var manual_scan_nonce = jQuery( '#wsal-scan-now-nonce' ).val();
|
382 |
|
383 |
// Ajax request to remove array of files from file exception list.
|
384 |
+
jQuery.ajax({
|
385 |
type: 'POST',
|
386 |
url: ajaxurl,
|
387 |
async: true,
|
388 |
dataType: 'json',
|
389 |
data: {
|
390 |
action: 'wsal_manual_scan_now',
|
391 |
+
nonce: manual_scan_nonce
|
392 |
},
|
393 |
success: function( data ) {
|
394 |
if ( data.success ) {
|
395 |
+
|
396 |
// Change button text.
|
397 |
+
scan_btn.text( wsal_data.scanNow );
|
398 |
scan_btn.removeAttr( 'disabled' );
|
399 |
stop_scan_btn.attr( 'disabled', 'disabled' );
|
400 |
} else {
|
401 |
+
scan_btn.text( wsal_data.scanFailed );
|
402 |
console.log( data.message );
|
403 |
}
|
404 |
},
|
407 |
console.log( textStatus );
|
408 |
console.log( error );
|
409 |
}
|
410 |
+
});
|
411 |
+
});
|
412 |
|
413 |
// Stop scan start button.
|
414 |
jQuery( '#wsal-stop-scan' ).click( function( event ) {
|
419 |
stop_scan_btn.attr( 'disabled', 'disabled' );
|
420 |
|
421 |
// Ajax request to remove array of files from file exception list.
|
422 |
+
jQuery.ajax({
|
423 |
type: 'POST',
|
424 |
url: ajaxurl,
|
425 |
async: true,
|
426 |
dataType: 'json',
|
427 |
data: {
|
428 |
action: 'wsal_stop_file_changes_scan',
|
429 |
+
nonce: jQuery( '#wsal-stop-scan-nonce' ).val()
|
430 |
},
|
431 |
success: function( data ) {
|
432 |
if ( data.success ) {
|
433 |
+
|
434 |
// Change button text.
|
435 |
// stop_scan_btn.removeAttr( 'disabled' );
|
436 |
} else {
|
442 |
console.log( textStatus );
|
443 |
console.log( error );
|
444 |
}
|
445 |
+
});
|
446 |
+
});
|
447 |
+
|
448 |
+
// Reset settings handler.
|
449 |
+
var resetSettings = jQuery( '[data-remodal-id=wsal_reset_settings] button[data-remodal-action=confirm]' );
|
450 |
+
resetSettings.click( function() {
|
451 |
+
resetWSAL( 'wsal_reset_settings', jQuery( '#wsal-reset-settings-nonce' ).val() );
|
452 |
+
});
|
453 |
+
|
454 |
+
// Purge activity handler.
|
455 |
+
var purgeActivity = jQuery( '[data-remodal-id=wsal_purge_activity] button[data-remodal-action=confirm]' );
|
456 |
+
purgeActivity.click( function() {
|
457 |
+
resetWSAL( 'wsal_purge_activity', jQuery( '#wsal-purge-activity-nonce' ).val() );
|
458 |
+
});
|
459 |
+
|
460 |
+
/**
|
461 |
+
* Reset ajax function.
|
462 |
+
*
|
463 |
+
* @param {string} action – Ajax action hook.
|
464 |
+
* @param {string} nonce – Nonce for security.
|
465 |
+
*/
|
466 |
+
function resetWSAL( action, nonce ) {
|
467 |
+
jQuery.ajax({
|
468 |
+
type: 'POST',
|
469 |
+
url: ajaxurl,
|
470 |
+
async: true,
|
471 |
+
data: {
|
472 |
+
action: action,
|
473 |
+
nonce: nonce
|
474 |
+
},
|
475 |
+
success: function( data ) {
|
476 |
+
console.log( data );
|
477 |
+
},
|
478 |
+
error: function( xhr, textStatus, error ) {
|
479 |
+
console.log( xhr.statusText );
|
480 |
+
console.log( textStatus );
|
481 |
+
console.log( error );
|
482 |
+
}
|
483 |
+
});
|
484 |
+
}
|
485 |
});
|
js/src/wsal-wizard.js
ADDED
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* WSAL Wizard
|
3 |
+
*
|
4 |
+
* Entry file for webpack.
|
5 |
+
*
|
6 |
+
* @since 3.2.3
|
7 |
+
*/
|
8 |
+
|
9 |
+
// Wizard styles.
|
10 |
+
import '../../css/src/wsal-wizard.scss';
|
11 |
+
|
12 |
+
import jQuery from 'jquery';
|
13 |
+
|
14 |
+
jQuery( document ).ready( function() {
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Step: `Access`
|
18 |
+
*
|
19 |
+
* Usernames & roles access setting.
|
20 |
+
*/
|
21 |
+
jQuery( '#editor-users-add, #editor-roles-add, #exuser-query-add, #exrole-query-add, #ipaddr-query-add' ).click( function() {
|
22 |
+
const type = jQuery( this ).attr( 'id' ).substr( 0, 6 );
|
23 |
+
const tokenType = jQuery( this ).attr( 'id' ).substr( 7, 5 );
|
24 |
+
const tokenValue = jQuery.trim( jQuery( `#${type}-${tokenType}-box` ).val() );
|
25 |
+
const existing = jQuery( `#${type}-list input` ).filter( function() {
|
26 |
+
return this.value === tokenValue;
|
27 |
+
});
|
28 |
+
|
29 |
+
if ( ! tokenValue || existing.length ) {
|
30 |
+
return;
|
31 |
+
} // if value is empty or already used, stop here
|
32 |
+
|
33 |
+
// checkDataToken( 'user' );
|
34 |
+
jQuery( `#${type}-${tokenType}-box, #${type}-${tokenType}-add` ).attr( 'disabled', true );
|
35 |
+
|
36 |
+
jQuery.ajax({
|
37 |
+
type: 'POST',
|
38 |
+
url: wsalData.ajaxURL,
|
39 |
+
async: true,
|
40 |
+
data: {
|
41 |
+
action: 'setup_check_security_token',
|
42 |
+
token: tokenValue,
|
43 |
+
nonce: wsalData.nonce
|
44 |
+
},
|
45 |
+
dataType: 'json',
|
46 |
+
success: function( data ) {
|
47 |
+
|
48 |
+
// Remove disabled attribute.
|
49 |
+
jQuery( `#${type}-${tokenType}-box, #${type}-${tokenType}-add` ).removeAttr( 'disabled' );
|
50 |
+
jQuery( `#${type}-${tokenType}-box` ).val( '' );
|
51 |
+
|
52 |
+
if ( data.success ) {
|
53 |
+
|
54 |
+
// Error handling.
|
55 |
+
if ( 'other' === data.tokenType && ( 'users' === tokenType || 'exuser' === type ) ) {
|
56 |
+
alert( wsalData.usersError );
|
57 |
+
return;
|
58 |
+
} else if ( 'other' === data.tokenType && ( 'roles' === tokenType || 'exrole' === type ) ) {
|
59 |
+
alert( wsalData.rolesError );
|
60 |
+
return;
|
61 |
+
} else if ( 'other' === data.tokenType && ( 'ip' === tokenType || 'ipaddr' === type ) ) {
|
62 |
+
alert( wsalData.ipError );
|
63 |
+
return;
|
64 |
+
}
|
65 |
+
|
66 |
+
jQuery( `#${type}-list` ).append( jQuery( `<span class="sectoken-${data.tokenType}"/>` ).text( data.token ).append(
|
67 |
+
jQuery( `<input type="hidden" name="${type}s[]"/>` ).val( data.token ),
|
68 |
+
jQuery( '<a href="javascript:;" title="Remove">×</a>' ).click( removeSecToken )
|
69 |
+
) );
|
70 |
+
} else {
|
71 |
+
alert( data.message );
|
72 |
+
}
|
73 |
+
},
|
74 |
+
error: function( xhr, textStatus, error ) {
|
75 |
+
console.log( xhr.statusText );
|
76 |
+
console.log( textStatus );
|
77 |
+
console.log( error );
|
78 |
+
}
|
79 |
+
});
|
80 |
+
});
|
81 |
+
|
82 |
+
jQuery( '#editor-users-box, #editor-roles-box, #exuser-query-box, #exrole-query-box, #ipaddr-query-box' ).keydown( function( event ) {
|
83 |
+
if ( 13 === event.keyCode ) {
|
84 |
+
const type = jQuery( this ).attr( 'id' ).substr( 0, 6 );
|
85 |
+
const tokenType = jQuery( this ).attr( 'id' ).substr( 7, 5 );
|
86 |
+
jQuery( `#${type}-${tokenType}-add` ).click();
|
87 |
+
return false;
|
88 |
+
}
|
89 |
+
});
|
90 |
+
|
91 |
+
/**
|
92 |
+
* Remove access settings token.
|
93 |
+
*/
|
94 |
+
jQuery( '#editor-list>span>a, #exuser-list>span>a, #exrole-list>span>a, #ipaddr-list>span>a' ).click( removeSecToken );
|
95 |
+
function removeSecToken() {
|
96 |
+
const token = jQuery( this ).parents( 'span:first' );
|
97 |
+
token.addClass( 'sectoken-del' ).fadeOut( 'fast', function() {
|
98 |
+
token.remove();
|
99 |
+
});
|
100 |
+
};
|
101 |
+
});
|
102 |
+
|
readme.txt
CHANGED
@@ -6,14 +6,14 @@ License URI: http://www.gnu.org/licenses/gpl.html
|
|
6 |
Tags: wordpress security plugin, wordpress security audit log, audit log, event log wordpress, wordpress user tracking, wordpress activity log, wordpress audit, security event log, audit trail, wordpress security monitor, wordpress admin, wordpress admin monitoring, user activity, admin, multisite, dashboard, notification, wordpress monitoring, email notification, wordpress email alerts, tracking, user tracking, user activity report, wordpress audit trail
|
7 |
Requires at least: 3.6
|
8 |
Tested up to: 4.9.7
|
9 |
-
Stable tag: 3.2.
|
10 |
Requires PHP: 5.4.43
|
11 |
|
12 |
-
An easy to use
|
13 |
|
14 |
== Description ==
|
15 |
|
16 |
-
<strong>THE MOST COMPREHENSIVE
|
17 |
|
18 |
Keep an audit log of everything that happens on your WordPress and [WordPress multisite](http://www.wpsecurityauditlog.com/documentation/wordpress-multisite-plugin-features-support/) with the WP Security Audit Log plugin to ensure user productivity, easily spot suspicious behavior before it becomes a WordPress security problem and have an organized website.
|
19 |
|
@@ -179,45 +179,29 @@ Please refer to our [Support & Documentation pages](https://www.wpsecurityauditl
|
|
179 |
|
180 |
== Changelog ==
|
181 |
|
182 |
-
= 3.2.
|
183 |
|
184 |
-
|
185 |
-
* fixed an issue with an incorrect opt-in prompt from the SDK
|
186 |
-
|
187 |
-
= 3.2.2.1 (2018-07-18) =
|
188 |
-
|
189 |
-
* **Bug fix**
|
190 |
-
* fixed issues related to SDK path
|
191 |
-
|
192 |
-
= 3.2.2(2018-07-17) =
|
193 |
-
|
194 |
-
Release Notes: [click here](https://www.wpsecurityauditlog.com/releases/3-2-2-mainwp-integration/)
|
195 |
-
|
196 |
-
* **New Events**
|
197 |
-
* Event ID 9072: User opened WooCommerce product in editor
|
198 |
-
* Event ID 9073: User viewed WooCommernce product
|
199 |
|
200 |
* **New Features**
|
201 |
-
*
|
202 |
-
*
|
203 |
-
*
|
204 |
-
*
|
205 |
-
*
|
206 |
-
|
207 |
-
* System info module that captures diagnostic data required by support.
|
208 |
-
|
209 |
* **Improvements**
|
210 |
-
*
|
211 |
-
*
|
212 |
-
*
|
213 |
-
*
|
214 |
-
*
|
215 |
-
*
|
216 |
-
*
|
217 |
-
*
|
218 |
-
|
|
|
|
|
219 |
* **Bug Fixes**
|
220 |
-
*
|
221 |
-
*
|
222 |
-
* Fixed issue in which database selection (archive or live DB) was not stored properly.
|
223 |
-
* Fixed issue where audit log viewer was auto refreshing to page one automatically when browsing other pages.
|
6 |
Tags: wordpress security plugin, wordpress security audit log, audit log, event log wordpress, wordpress user tracking, wordpress activity log, wordpress audit, security event log, audit trail, wordpress security monitor, wordpress admin, wordpress admin monitoring, user activity, admin, multisite, dashboard, notification, wordpress monitoring, email notification, wordpress email alerts, tracking, user tracking, user activity report, wordpress audit trail
|
7 |
Requires at least: 3.6
|
8 |
Tested up to: 4.9.7
|
9 |
+
Stable tag: 3.2.3
|
10 |
Requires PHP: 5.4.43
|
11 |
|
12 |
+
An easy to use & comprehensive WordPress activity log plugin to log all changes on WordPress sites & multisite networks.
|
13 |
|
14 |
== Description ==
|
15 |
|
16 |
+
<strong>THE MOST COMPREHENSIVE & EASY TO USE WORDPRESS ACTIVITY LOG PLUGIN</strong><br />
|
17 |
|
18 |
Keep an audit log of everything that happens on your WordPress and [WordPress multisite](http://www.wpsecurityauditlog.com/documentation/wordpress-multisite-plugin-features-support/) with the WP Security Audit Log plugin to ensure user productivity, easily spot suspicious behavior before it becomes a WordPress security problem and have an organized website.
|
19 |
|
179 |
|
180 |
== Changelog ==
|
181 |
|
182 |
+
= 3.2.3 (2018-08-16) =
|
183 |
|
184 |
+
Release Notes: [click here](https://www.wpsecurityauditlog.com/releases/3-2-3-setup-wizard-ease-of-use/)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
185 |
|
186 |
* **New Features**
|
187 |
+
* Added a startup wizard to assist new users with new installs.
|
188 |
+
* Introduced the [WordPress activity log levels](https://www.wpsecurityauditlog.com/support-documentation/default-wordpress-activity-log-levels/).
|
189 |
+
* New search filters in the WordPress activity log viewer.
|
190 |
+
* Added a new test button to all external database connections, including those for [WordPress activity log archiving](https://www.wpsecurityauditlog.com/support-documentation/archive-alerts-wordpress-audit-trail/) and mirroring.
|
191 |
+
* Added several new settings to [purge the WordPress activity log](https://www.wpsecurityauditlog.com/support-documentation/wordpress-activity-log-deleted-plugin-uninstall-option/) and reset plugin settings to default.
|
192 |
+
|
|
|
|
|
193 |
* **Improvements**
|
194 |
+
* Performance improvement: optimized the logic of the plugin sensors to load only required ones during user action.
|
195 |
+
* Redesigned all the settings pages and included more help text, making them more user friendly.
|
196 |
+
* Added links to [plugin knowledge base](https://www.wpsecurityauditlog.com/support-documentation/) where possible in the plugin settings.
|
197 |
+
* Improved the [WordPress activity log pruning setting](https://www.wpsecurityauditlog.com/support-documentation/can-prune-alerts-audit-trail/) so now it is possible to configure retention based on a period of time.
|
198 |
+
* Database improvement: changed the option_value column in the plugin tables to long text.
|
199 |
+
* [WordPress website file changes](https://www.wpsecurityauditlog.com/support-documentation/wordpress-files-changes-warning-activity-logs/) results are now stored in the plugin's options table.
|
200 |
+
* Improved the list of excluded file extensions in the WordPress file changes scanner.
|
201 |
+
* Added sorting in the [logged in WordPress users](https://www.wpsecurityauditlog.com/support-documentation/getting-started-wordpress-users-sessions-management/#who-logged-in-wordpress) view.
|
202 |
+
* Added more checks to ensure opt-in and other plugin messages are shown when needed only.
|
203 |
+
* Removed affiliate network message in plugin.
|
204 |
+
|
205 |
* **Bug Fixes**
|
206 |
+
* Fixed an issue where stored passwords might have been changed because of change from Mcrypt to OpenSSL.
|
207 |
+
* Fixed an issue in which retention settings were reset when moved to archiving settings.
|
|
|
|
sdk/freemius/assets/css/admin/common.css
CHANGED
@@ -1,2 +1,2 @@
|
|
1 |
.theme-browser .theme .fs-premium-theme-badge{position:absolute;top:10px;right:0;background:#71ae00;color:#fff;text-transform:uppercase;padding:5px 10px;-moz-border-radius:3px 0 0 3px;-webkit-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;font-weight:bold;border-right:0;-moz-box-shadow:0 2px 1px -1px rgba(0,0,0,0.3);-webkit-box-shadow:0 2px 1px -1px rgba(0,0,0,0.3);box-shadow:0 2px 1px -1px rgba(0,0,0,0.3);font-size:1.1em}#iframe{line-height:0;font-size:0}.fs-full-size-wrapper{margin:40px 0 -65px -20px}@media (max-width: 600px){.fs-full-size-wrapper{margin:0 0 -65px -10px}}
|
2 |
-
.fs-notice{position:relative}.fs-notice.fs-has-title{margin-bottom:30px !important}.fs-notice.success{color:green}.fs-notice.promotion{border-color:#00a0d2 !important;background-color:#f2fcff !important}.fs-notice .fs-notice-body{margin:.5em 0;padding:2px}.fs-notice .fs-close{cursor:pointer;color:#aaa;float:right}.fs-notice .fs-close:hover{color:#666}.fs-notice .fs-close>*{margin-top:7px;display:inline-block}.fs-notice label.fs-plugin-title{background:rgba(0,0,0,0.3);color:#fff;padding:2px 10px;position:absolute;top:100%;bottom:auto;right:auto;-moz-border-radius:0 0 3px 3px;-webkit-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;left:10px;font-size:12px;font-weight:bold;cursor:auto}div.fs-notice.updated,div.fs-notice.success,div.fs-notice.promotion{display:block !important}.rtl .fs-notice .fs-close{float:left}.fs-secure-notice{position:fixed;top:32px;left:160px;right:0;background:#ebfdeb;padding:10px 20px;color:green;z-index:9999;-moz-box-shadow:0 2px 2px rgba(6,113,6,0.3);-webkit-box-shadow:0 2px 2px rgba(6,113,6,0.3);box-shadow:0 2px 2px rgba(6,113,6,0.3);opacity:0.95;filter:alpha(opacity=95)}.fs-secure-notice:hover{opacity:1;filter:alpha(opacity=100)}.fs-secure-notice a.fs-security-proof{color:green;text-decoration:none}@media screen and (max-width: 960px){.fs-secure-notice{left:36px}}@media screen and (max-width: 600px){.fs-secure-notice{display:none}}@media screen and (max-width: 500px){#fs_promo_tab{display:none}}@media screen and (max-width: 782px){.fs-secure-notice{left:0;top:46px;text-align:center}}span.fs-submenu-item.fs-sub:before{content:'\21B3';padding:0 5px}.rtl span.fs-submenu-item.fs-sub:before{content:'\21B2'}.fs-submenu-item.pricing.upgrade-mode{color:greenyellow}.fs-submenu-item.pricing.trial-mode{color:#83e2ff}#adminmenu .update-plugins.fs-trial{background-color:#00b9eb}.fs-ajax-spinner{border:0;width:20px;height:20px;margin-right:5px;vertical-align:sub;display:inline-block;background:url("
|
1 |
.theme-browser .theme .fs-premium-theme-badge{position:absolute;top:10px;right:0;background:#71ae00;color:#fff;text-transform:uppercase;padding:5px 10px;-moz-border-radius:3px 0 0 3px;-webkit-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;font-weight:bold;border-right:0;-moz-box-shadow:0 2px 1px -1px rgba(0,0,0,0.3);-webkit-box-shadow:0 2px 1px -1px rgba(0,0,0,0.3);box-shadow:0 2px 1px -1px rgba(0,0,0,0.3);font-size:1.1em}#iframe{line-height:0;font-size:0}.fs-full-size-wrapper{margin:40px 0 -65px -20px}@media (max-width: 600px){.fs-full-size-wrapper{margin:0 0 -65px -10px}}
|
2 |
+
.fs-notice{position:relative}.fs-notice.fs-has-title{margin-bottom:30px !important}.fs-notice.success{color:green}.fs-notice.promotion{border-color:#00a0d2 !important;background-color:#f2fcff !important}.fs-notice .fs-notice-body{margin:.5em 0;padding:2px}.fs-notice .fs-close{cursor:pointer;color:#aaa;float:right}.fs-notice .fs-close:hover{color:#666}.fs-notice .fs-close>*{margin-top:7px;display:inline-block}.fs-notice label.fs-plugin-title{background:rgba(0,0,0,0.3);color:#fff;padding:2px 10px;position:absolute;top:100%;bottom:auto;right:auto;-moz-border-radius:0 0 3px 3px;-webkit-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;left:10px;font-size:12px;font-weight:bold;cursor:auto}div.fs-notice.updated,div.fs-notice.success,div.fs-notice.promotion{display:block !important}.rtl .fs-notice .fs-close{float:left}.fs-secure-notice{position:fixed;top:32px;left:160px;right:0;background:#ebfdeb;padding:10px 20px;color:green;z-index:9999;-moz-box-shadow:0 2px 2px rgba(6,113,6,0.3);-webkit-box-shadow:0 2px 2px rgba(6,113,6,0.3);box-shadow:0 2px 2px rgba(6,113,6,0.3);opacity:0.95;filter:alpha(opacity=95)}.fs-secure-notice:hover{opacity:1;filter:alpha(opacity=100)}.fs-secure-notice a.fs-security-proof{color:green;text-decoration:none}@media screen and (max-width: 960px){.fs-secure-notice{left:36px}}@media screen and (max-width: 600px){.fs-secure-notice{display:none}}@media screen and (max-width: 500px){#fs_promo_tab{display:none}}@media screen and (max-width: 782px){.fs-secure-notice{left:0;top:46px;text-align:center}}span.fs-submenu-item.fs-sub:before{content:'\21B3';padding:0 5px}.rtl span.fs-submenu-item.fs-sub:before{content:'\21B2'}.fs-submenu-item.pricing.upgrade-mode{color:greenyellow}.fs-submenu-item.pricing.trial-mode{color:#83e2ff}#adminmenu .update-plugins.fs-trial{background-color:#00b9eb}.fs-ajax-spinner{border:0;width:20px;height:20px;margin-right:5px;vertical-align:sub;display:inline-block;background:url("/wp-admin/images/wpspin_light-2x.gif");background-size:contain}.wrap.fs-section h2{text-align:left}
|
sdk/freemius/assets/scss/admin/common.scss
CHANGED
@@ -207,7 +207,7 @@ span.fs-submenu-item.fs-sub:before
|
|
207 |
margin-right: 5px;
|
208 |
vertical-align: sub;
|
209 |
display: inline-block;
|
210 |
-
background: url('
|
211 |
background-size: contain;
|
212 |
}
|
213 |
|
207 |
margin-right: 5px;
|
208 |
vertical-align: sub;
|
209 |
display: inline-block;
|
210 |
+
background: url('/wp-admin/images/wpspin_light-2x.gif');
|
211 |
background-size: contain;
|
212 |
}
|
213 |
|
sdk/freemius/includes/class-freemius.php
CHANGED
@@ -1348,7 +1348,10 @@
|
|
1348 |
add_action( 'make_ham_blog', array( &$this, '_after_site_reactivated_callback' ) );
|
1349 |
}
|
1350 |
|
1351 |
-
if ( $this->is_theme() &&
|
|
|
|
|
|
|
1352 |
// Register customizer upsell.
|
1353 |
add_action( 'customize_register', array( &$this, '_customizer_register' ) );
|
1354 |
}
|
@@ -1488,13 +1491,6 @@
|
|
1488 |
array( &$this, '_submit_uninstall_reason_action' )
|
1489 |
);
|
1490 |
|
1491 |
-
if ( $this->is_theme() && $this->is_premium() && ! $this->has_active_valid_license() ) {
|
1492 |
-
$this->add_ajax_action(
|
1493 |
-
'delete_theme_update_data',
|
1494 |
-
array( &$this, '_delete_theme_update_data_action' )
|
1495 |
-
);
|
1496 |
-
}
|
1497 |
-
|
1498 |
if ( ! $this->is_addon() || $this->is_parent_plugin_installed() ) {
|
1499 |
if ( ( $this->is_plugin() && self::is_plugins_page() ) ||
|
1500 |
( $this->is_theme() && self::is_themes_page() )
|
@@ -3145,7 +3141,7 @@
|
|
3145 |
if ( $is_connected ) {
|
3146 |
FS_GDPR_Manager::instance()->store_is_required( $pong->is_gdpr_required );
|
3147 |
}
|
3148 |
-
|
3149 |
$this->store_connectivity_info( $pong, $is_connected );
|
3150 |
|
3151 |
return $this->_has_api_connection;
|
@@ -3264,6 +3260,7 @@
|
|
3264 |
static function _get_current_wp_user() {
|
3265 |
self::require_pluggable_essentials();
|
3266 |
self::wp_cookie_constants();
|
|
|
3267 |
return wp_get_current_user();
|
3268 |
}
|
3269 |
|
@@ -3279,7 +3276,7 @@
|
|
3279 |
*/
|
3280 |
private static function wp_cookie_constants() {
|
3281 |
if ( defined( 'LOGGED_IN_COOKIE' ) &&
|
3282 |
-
|
3283 |
) {
|
3284 |
return;
|
3285 |
}
|
@@ -3960,6 +3957,13 @@
|
|
3960 |
|
3961 |
$this->parse_settings( $plugin_info );
|
3962 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3963 |
if ( ! self::is_ajax() ) {
|
3964 |
if ( ! $this->is_addon() || $this->is_only_premium() ) {
|
3965 |
add_action(
|
@@ -6191,19 +6195,21 @@
|
|
6191 |
}
|
6192 |
|
6193 |
if ( $this->is_plugin_new_install() || $this->is_only_premium() ) {
|
6194 |
-
|
6195 |
-
|
6196 |
-
|
6197 |
-
|
6198 |
-
|
6199 |
-
|
6200 |
-
|
6201 |
-
|
6202 |
-
|
6203 |
-
|
6204 |
-
|
6205 |
-
|
6206 |
-
|
|
|
|
|
6207 |
} else {
|
6208 |
if ( $this->should_add_sticky_optin_notice() ) {
|
6209 |
$this->add_sticky_optin_admin_notice();
|
@@ -10586,7 +10592,7 @@
|
|
10586 |
*/
|
10587 |
function _activate_license_ajax_action() {
|
10588 |
$this->_logger->entrance();
|
10589 |
-
|
10590 |
$this->check_ajax_referer( 'activate_license' );
|
10591 |
|
10592 |
$license_key = trim( fs_request_get( 'license_key' ) );
|
@@ -10855,7 +10861,7 @@
|
|
10855 |
$next_page = $this->get_after_activation_url( 'after_network_activation_url' );
|
10856 |
}
|
10857 |
} else {
|
10858 |
-
$error = $this->get_text_inline( '
|
10859 |
}
|
10860 |
|
10861 |
$result = array(
|
@@ -14381,16 +14387,17 @@
|
|
14381 |
unset( $parent_fs->_storage->is_pending_activation );
|
14382 |
}
|
14383 |
|
|
|
|
|
|
|
14384 |
// First of all, set site info - otherwise we won't
|
14385 |
// be able to invoke API calls.
|
14386 |
$parent_fs->_site = new FS_Site( $parent_install );
|
|
|
14387 |
|
14388 |
// Sync add-on plans.
|
14389 |
$parent_fs->_sync_plans();
|
14390 |
|
14391 |
-
// Get user information based on parent's plugin.
|
14392 |
-
$user = $this->get_user();
|
14393 |
-
|
14394 |
$parent_fs->_set_account( $user, $parent_fs->_site );
|
14395 |
}
|
14396 |
|
@@ -14754,13 +14761,15 @@
|
|
14754 |
private function add_submenu_items() {
|
14755 |
$this->_logger->entrance();
|
14756 |
|
|
|
|
|
14757 |
if ( $this->is_addon() ) {
|
14758 |
// No submenu items for add-ons.
|
14759 |
$add_submenu_items = false;
|
14760 |
} else if ( $this->is_free_wp_org_theme() && ! fs_is_network_admin() ) {
|
14761 |
// Also add submenu items when running in a free .org theme so the tabs will be visible.
|
14762 |
$add_submenu_items = true;
|
14763 |
-
} else if ( $
|
14764 |
$add_submenu_items = false;
|
14765 |
} else if ( fs_is_network_admin() ) {
|
14766 |
/**
|
@@ -14791,7 +14800,15 @@
|
|
14791 |
$this->is_submenu_item_visible( 'affiliation' )
|
14792 |
);
|
14793 |
}
|
|
|
14794 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14795 |
if ( ! WP_FS__DEMO_MODE && $this->is_registered() ) {
|
14796 |
$show_account = (
|
14797 |
$this->is_submenu_item_visible( 'account' ) &&
|
@@ -14810,10 +14827,12 @@
|
|
14810 |
'account',
|
14811 |
array( &$this, '_account_page_load' ),
|
14812 |
WP_FS__DEFAULT_PRIORITY,
|
14813 |
-
$show_account
|
14814 |
);
|
14815 |
}
|
|
|
14816 |
|
|
|
14817 |
// Add contact page.
|
14818 |
$this->add_submenu_item(
|
14819 |
$this->get_text_inline( 'Contact Us', 'contact-us' ),
|
@@ -14838,7 +14857,11 @@
|
|
14838 |
$this->is_submenu_item_visible( 'addons' )
|
14839 |
);
|
14840 |
}
|
|
|
14841 |
|
|
|
|
|
|
|
14842 |
if ( ! WP_FS__DEMO_MODE ) {
|
14843 |
$show_pricing = (
|
14844 |
$this->is_submenu_item_visible( 'pricing' ) &&
|
@@ -14860,14 +14883,14 @@
|
|
14860 |
|
14861 |
// Add upgrade/pricing page.
|
14862 |
$this->add_submenu_item(
|
14863 |
-
$pricing_cta_text . ' ' . ( is_rtl() ? '←' : '➤' ),
|
14864 |
array( &$this, '_pricing_page_render' ),
|
14865 |
$this->get_plugin_name() . ' – ' . $this->get_text_x_inline( 'Pricing', 'noun', 'pricing' ),
|
14866 |
'manage_options',
|
14867 |
'pricing',
|
14868 |
'Freemius::_clean_admin_content_section',
|
14869 |
WP_FS__LOWEST_PRIORITY,
|
14870 |
-
$show_pricing,
|
14871 |
$pricing_class
|
14872 |
);
|
14873 |
}
|
@@ -15935,7 +15958,7 @@
|
|
15935 |
/**
|
15936 |
* @since 1.2.3 When running in DEV mode, retrieve pending plans as well.
|
15937 |
*/
|
15938 |
-
$result = $api->get( "/plugins/{$this->_module_id}/plans.json
|
15939 |
|
15940 |
if ( $this->is_api_result_object( $result, 'plans' ) && is_array( $result->plans ) ) {
|
15941 |
for ( $i = 0, $len = count( $result->plans ); $i < $len; $i ++ ) {
|
@@ -16403,7 +16426,7 @@
|
|
16403 |
$this->_update_licenses( $licenses, $addon->id );
|
16404 |
|
16405 |
if ( ! $this->is_addon_installed( $addon->id ) && FS_License_Manager::has_premium_license( $licenses ) ) {
|
16406 |
-
$plans_result = $this->get_api_site_or_plugin_scope()->get( "/addons/{$addon_id}/plans.json" );
|
16407 |
|
16408 |
if ( ! isset( $plans_result->error ) ) {
|
16409 |
$plans = array();
|
@@ -16731,6 +16754,7 @@
|
|
16731 |
'trial_promotion',
|
16732 |
'trial_expired',
|
16733 |
'activation_complete',
|
|
|
16734 |
) );
|
16735 |
break;
|
16736 |
case 'changed':
|
@@ -17285,9 +17309,10 @@
|
|
17285 |
|
17286 |
$is_premium = null;
|
17287 |
if ( ! $is_addon ) {
|
17288 |
-
$is_premium = $this->is_premium();
|
17289 |
} else if ( $this->is_addon_activated( $addon_id ) ) {
|
17290 |
-
$
|
|
|
17291 |
}
|
17292 |
|
17293 |
// If add-on, then append add-on ID.
|
@@ -17483,9 +17508,15 @@
|
|
17483 |
|
17484 |
if ( ! empty( $plugin_id ) ) {
|
17485 |
$params['plugin_id'] = $plugin_id;
|
|
|
|
|
17486 |
}
|
17487 |
|
17488 |
-
|
|
|
|
|
|
|
|
|
17489 |
}
|
17490 |
|
17491 |
#endregion Download Plugin ------------------------------------------------------------------
|
@@ -17561,19 +17592,21 @@
|
|
17561 |
|
17562 |
$api = $this->get_api_site_or_plugin_scope();
|
17563 |
|
|
|
|
|
17564 |
/**
|
17565 |
* @since 1.2.1
|
17566 |
*
|
17567 |
* If there's a cached version of the add-ons and not asking
|
17568 |
* for a flush, just use the currently stored add-ons.
|
17569 |
*/
|
17570 |
-
if ( ! $flush && $api->is_cached(
|
17571 |
$addons = self::get_all_addons();
|
17572 |
|
17573 |
return $addons[ $this->_plugin->id ];
|
17574 |
}
|
17575 |
|
17576 |
-
$result = $api->get(
|
17577 |
|
17578 |
$addons = array();
|
17579 |
if ( $this->is_api_result_object( $result, 'plugins' ) &&
|
@@ -18389,9 +18422,9 @@
|
|
18389 |
$vars = array( 'id' => $this->_module_id );
|
18390 |
|
18391 |
if ( 'true' === fs_request_get( 'checkout', false ) ) {
|
18392 |
-
|
18393 |
} else {
|
18394 |
-
|
18395 |
}
|
18396 |
}
|
18397 |
|
@@ -18506,7 +18539,9 @@
|
|
18506 |
* @return FS_Api
|
18507 |
*/
|
18508 |
private function get_current_or_network_user_api_scope( $flush = false ) {
|
18509 |
-
if ( ! $this->_is_network_active ||
|
|
|
|
|
18510 |
return $this->get_api_user_scope( $flush );
|
18511 |
}
|
18512 |
|
@@ -18594,9 +18629,19 @@
|
|
18594 |
* @author Vova Feldman (@svovaf)
|
18595 |
* @since 1.0.9
|
18596 |
*
|
18597 |
-
* @param $plans
|
18598 |
*/
|
18599 |
function _check_for_trial_plans( $plans ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18600 |
$this->_storage->has_trial_plan = FS_Plan_Manager::instance()->has_trial_plan( $plans );
|
18601 |
}
|
18602 |
|
@@ -18703,14 +18748,14 @@
|
|
18703 |
|
18704 |
// Show promotion if never shown before and 24 hours after initial activation with FS.
|
18705 |
if ( ! $was_promotion_shown_before &&
|
18706 |
-
$this->_storage->install_timestamp > ( time() - WP_FS__TIME_24_HOURS_IN_SEC )
|
18707 |
) {
|
18708 |
return false;
|
18709 |
}
|
18710 |
|
18711 |
// OR if promotion was shown before, try showing it every 30 days.
|
18712 |
if ( $was_promotion_shown_before &&
|
18713 |
-
30 * WP_FS__TIME_24_HOURS_IN_SEC > time() - $last_time_trial_promotion_shown
|
18714 |
) {
|
18715 |
return false;
|
18716 |
}
|
@@ -19335,14 +19380,16 @@
|
|
19335 |
* @param array $request
|
19336 |
* @param int $success_cache_expiration
|
19337 |
* @param int $failure_cache_expiration
|
|
|
19338 |
*
|
19339 |
* @return WP_Error|array
|
19340 |
*/
|
19341 |
-
|
19342 |
&$url,
|
19343 |
$request,
|
19344 |
$success_cache_expiration = 0,
|
19345 |
-
$failure_cache_expiration = 0
|
|
|
19346 |
) {
|
19347 |
$should_cache = ($success_cache_expiration + $failure_cache_expiration > 0);
|
19348 |
|
@@ -19353,7 +19400,9 @@
|
|
19353 |
false;
|
19354 |
|
19355 |
if ( false === $response ) {
|
19356 |
-
|
|
|
|
|
19357 |
|
19358 |
$response = wp_remote_post( $url, $request );
|
19359 |
|
@@ -20108,6 +20157,10 @@
|
|
20108 |
$icon_found = false;
|
20109 |
$local_path = fs_normalize_path( "{$img_dir}/{$this->_slug}.png" );
|
20110 |
|
|
|
|
|
|
|
|
|
20111 |
$have_write_permissions = ( 'direct' === get_filesystem_method( array(), fs_normalize_path( $img_dir ) ) );
|
20112 |
|
20113 |
/**
|
@@ -20624,9 +20677,7 @@
|
|
20624 |
* @since 2.1.0
|
20625 |
*/
|
20626 |
function _maybe_add_gdpr_optin_ajax_handler() {
|
20627 |
-
|
20628 |
-
$this->add_ajax_action( 'fetch_is_marketing_required_flag_value', array( &$this, '_fetch_is_marketing_required_flag_value_ajax_action' ) );
|
20629 |
-
}
|
20630 |
|
20631 |
if ( FS_GDPR_Manager::instance()->is_opt_in_notice_shown() ) {
|
20632 |
$this->add_gdpr_optin_ajax_handler_and_style();
|
@@ -20810,4 +20861,28 @@
|
|
20810 |
}
|
20811 |
|
20812 |
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20813 |
}
|
1348 |
add_action( 'make_ham_blog', array( &$this, '_after_site_reactivated_callback' ) );
|
1349 |
}
|
1350 |
|
1351 |
+
if ( $this->is_theme() &&
|
1352 |
+
self::is_customizer() &&
|
1353 |
+
$this->apply_filters( 'show_customizer_upsell', true )
|
1354 |
+
) {
|
1355 |
// Register customizer upsell.
|
1356 |
add_action( 'customize_register', array( &$this, '_customizer_register' ) );
|
1357 |
}
|
1491 |
array( &$this, '_submit_uninstall_reason_action' )
|
1492 |
);
|
1493 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1494 |
if ( ! $this->is_addon() || $this->is_parent_plugin_installed() ) {
|
1495 |
if ( ( $this->is_plugin() && self::is_plugins_page() ) ||
|
1496 |
( $this->is_theme() && self::is_themes_page() )
|
3141 |
if ( $is_connected ) {
|
3142 |
FS_GDPR_Manager::instance()->store_is_required( $pong->is_gdpr_required );
|
3143 |
}
|
3144 |
+
|
3145 |
$this->store_connectivity_info( $pong, $is_connected );
|
3146 |
|
3147 |
return $this->_has_api_connection;
|
3260 |
static function _get_current_wp_user() {
|
3261 |
self::require_pluggable_essentials();
|
3262 |
self::wp_cookie_constants();
|
3263 |
+
|
3264 |
return wp_get_current_user();
|
3265 |
}
|
3266 |
|
3276 |
*/
|
3277 |
private static function wp_cookie_constants() {
|
3278 |
if ( defined( 'LOGGED_IN_COOKIE' ) &&
|
3279 |
+
( defined( 'AUTH_COOKIE' ) || defined( 'SECURE_AUTH_COOKIE' ) )
|
3280 |
) {
|
3281 |
return;
|
3282 |
}
|
3957 |
|
3958 |
$this->parse_settings( $plugin_info );
|
3959 |
|
3960 |
+
if ( is_admin() && $this->is_theme() && $this->is_premium() && ! $this->has_active_valid_license() ) {
|
3961 |
+
$this->add_ajax_action(
|
3962 |
+
'delete_theme_update_data',
|
3963 |
+
array( &$this, '_delete_theme_update_data_action' )
|
3964 |
+
);
|
3965 |
+
}
|
3966 |
+
|
3967 |
if ( ! self::is_ajax() ) {
|
3968 |
if ( ! $this->is_addon() || $this->is_only_premium() ) {
|
3969 |
add_action(
|
6195 |
}
|
6196 |
|
6197 |
if ( $this->is_plugin_new_install() || $this->is_only_premium() ) {
|
6198 |
+
if ( ! $this->_anonymous_mode ) {
|
6199 |
+
// Show notice for new plugin installations.
|
6200 |
+
$this->_admin_notices->add(
|
6201 |
+
sprintf(
|
6202 |
+
$this->get_text_inline( 'You are just one step away - %s', 'you-are-step-away' ),
|
6203 |
+
sprintf( '<b><a href="%s">%s</a></b>',
|
6204 |
+
$this->get_activation_url( array(), ! $this->is_delegated_connection() ),
|
6205 |
+
sprintf( $this->get_text_x_inline( 'Complete "%s" Activation Now',
|
6206 |
+
'%s - plugin name. As complete "PluginX" activation now', 'activate-x-now' ), $this->get_plugin_name() )
|
6207 |
+
)
|
6208 |
+
),
|
6209 |
+
'',
|
6210 |
+
'update-nag'
|
6211 |
+
);
|
6212 |
+
}
|
6213 |
} else {
|
6214 |
if ( $this->should_add_sticky_optin_notice() ) {
|
6215 |
$this->add_sticky_optin_admin_notice();
|
10592 |
*/
|
10593 |
function _activate_license_ajax_action() {
|
10594 |
$this->_logger->entrance();
|
10595 |
+
|
10596 |
$this->check_ajax_referer( 'activate_license' );
|
10597 |
|
10598 |
$license_key = trim( fs_request_get( 'license_key' ) );
|
10861 |
$next_page = $this->get_after_activation_url( 'after_network_activation_url' );
|
10862 |
}
|
10863 |
} else {
|
10864 |
+
$error = $this->get_text_inline( 'Invalid site details collection.', 'invalid_site_details_collection' );
|
10865 |
}
|
10866 |
|
10867 |
$result = array(
|
14387 |
unset( $parent_fs->_storage->is_pending_activation );
|
14388 |
}
|
14389 |
|
14390 |
+
// Get user information based on parent's plugin.
|
14391 |
+
$user = $this->get_user();
|
14392 |
+
|
14393 |
// First of all, set site info - otherwise we won't
|
14394 |
// be able to invoke API calls.
|
14395 |
$parent_fs->_site = new FS_Site( $parent_install );
|
14396 |
+
$parent_fs->_user = $user;
|
14397 |
|
14398 |
// Sync add-on plans.
|
14399 |
$parent_fs->_sync_plans();
|
14400 |
|
|
|
|
|
|
|
14401 |
$parent_fs->_set_account( $user, $parent_fs->_site );
|
14402 |
}
|
14403 |
|
14761 |
private function add_submenu_items() {
|
14762 |
$this->_logger->entrance();
|
14763 |
|
14764 |
+
$is_activation_mode = $this->is_activation_mode();
|
14765 |
+
|
14766 |
if ( $this->is_addon() ) {
|
14767 |
// No submenu items for add-ons.
|
14768 |
$add_submenu_items = false;
|
14769 |
} else if ( $this->is_free_wp_org_theme() && ! fs_is_network_admin() ) {
|
14770 |
// Also add submenu items when running in a free .org theme so the tabs will be visible.
|
14771 |
$add_submenu_items = true;
|
14772 |
+
} else if ( $is_activation_mode && ! $this->is_free_wp_org_theme() ) {
|
14773 |
$add_submenu_items = false;
|
14774 |
} else if ( fs_is_network_admin() ) {
|
14775 |
/**
|
14800 |
$this->is_submenu_item_visible( 'affiliation' )
|
14801 |
);
|
14802 |
}
|
14803 |
+
}
|
14804 |
|
14805 |
+
if ( $add_submenu_items ||
|
14806 |
+
( $is_activation_mode &&
|
14807 |
+
$this->is_only_premium() &&
|
14808 |
+
$this->is_admin_page( 'account' ) &&
|
14809 |
+
fs_request_is_action( $this->get_unique_affix() . '_sync_license' )
|
14810 |
+
)
|
14811 |
+
) {
|
14812 |
if ( ! WP_FS__DEMO_MODE && $this->is_registered() ) {
|
14813 |
$show_account = (
|
14814 |
$this->is_submenu_item_visible( 'account' ) &&
|
14827 |
'account',
|
14828 |
array( &$this, '_account_page_load' ),
|
14829 |
WP_FS__DEFAULT_PRIORITY,
|
14830 |
+
( $add_submenu_items && $show_account )
|
14831 |
);
|
14832 |
}
|
14833 |
+
}
|
14834 |
|
14835 |
+
if ( $add_submenu_items ) {
|
14836 |
// Add contact page.
|
14837 |
$this->add_submenu_item(
|
14838 |
$this->get_text_inline( 'Contact Us', 'contact-us' ),
|
14857 |
$this->is_submenu_item_visible( 'addons' )
|
14858 |
);
|
14859 |
}
|
14860 |
+
}
|
14861 |
|
14862 |
+
if ( $add_submenu_items ||
|
14863 |
+
( $is_activation_mode && $this->is_only_premium() && $this->is_admin_page( 'pricing' ) )
|
14864 |
+
) {
|
14865 |
if ( ! WP_FS__DEMO_MODE ) {
|
14866 |
$show_pricing = (
|
14867 |
$this->is_submenu_item_visible( 'pricing' ) &&
|
14883 |
|
14884 |
// Add upgrade/pricing page.
|
14885 |
$this->add_submenu_item(
|
14886 |
+
$pricing_cta_text . ' ' . ( is_rtl() ? $this->get_text_x_inline( '←', 'ASCII arrow left icon', 'symbol_arrow-left' ) : $this->get_text_x_inline( '➤', 'ASCII arrow right icon', 'symbol_arrow-right' ) ),
|
14887 |
array( &$this, '_pricing_page_render' ),
|
14888 |
$this->get_plugin_name() . ' – ' . $this->get_text_x_inline( 'Pricing', 'noun', 'pricing' ),
|
14889 |
'manage_options',
|
14890 |
'pricing',
|
14891 |
'Freemius::_clean_admin_content_section',
|
14892 |
WP_FS__LOWEST_PRIORITY,
|
14893 |
+
( $add_submenu_items && $show_pricing ),
|
14894 |
$pricing_class
|
14895 |
);
|
14896 |
}
|
15958 |
/**
|
15959 |
* @since 1.2.3 When running in DEV mode, retrieve pending plans as well.
|
15960 |
*/
|
15961 |
+
$result = $api->get( $this->add_show_pending( "/plugins/{$this->_module_id}/plans.json" ), true );
|
15962 |
|
15963 |
if ( $this->is_api_result_object( $result, 'plans' ) && is_array( $result->plans ) ) {
|
15964 |
for ( $i = 0, $len = count( $result->plans ); $i < $len; $i ++ ) {
|
16426 |
$this->_update_licenses( $licenses, $addon->id );
|
16427 |
|
16428 |
if ( ! $this->is_addon_installed( $addon->id ) && FS_License_Manager::has_premium_license( $licenses ) ) {
|
16429 |
+
$plans_result = $this->get_api_site_or_plugin_scope()->get( $this->add_show_pending( "/addons/{$addon_id}/plans.json" ) );
|
16430 |
|
16431 |
if ( ! isset( $plans_result->error ) ) {
|
16432 |
$plans = array();
|
16754 |
'trial_promotion',
|
16755 |
'trial_expired',
|
16756 |
'activation_complete',
|
16757 |
+
'license_expired',
|
16758 |
) );
|
16759 |
break;
|
16760 |
case 'changed':
|
17309 |
|
17310 |
$is_premium = null;
|
17311 |
if ( ! $is_addon ) {
|
17312 |
+
$is_premium = ( $this->is_premium() || $this->_can_download_premium() );
|
17313 |
} else if ( $this->is_addon_activated( $addon_id ) ) {
|
17314 |
+
$fs_addon = self::get_instance_by_id( $addon_id );
|
17315 |
+
$is_premium = ( $fs_addon->is_premium() || $fs_addon->_can_download_premium() );
|
17316 |
}
|
17317 |
|
17318 |
// If add-on, then append add-on ID.
|
17508 |
|
17509 |
if ( ! empty( $plugin_id ) ) {
|
17510 |
$params['plugin_id'] = $plugin_id;
|
17511 |
+
} else if ( $this->is_addon() ) {
|
17512 |
+
$params['plugin_id'] = $this->get_id();
|
17513 |
}
|
17514 |
|
17515 |
+
$fs = $this->is_addon() ?
|
17516 |
+
$this->get_parent_instance() :
|
17517 |
+
$this;
|
17518 |
+
|
17519 |
+
return $fs->get_account_url( 'download_latest', $params );
|
17520 |
}
|
17521 |
|
17522 |
#endregion Download Plugin ------------------------------------------------------------------
|
17592 |
|
17593 |
$api = $this->get_api_site_or_plugin_scope();
|
17594 |
|
17595 |
+
$path = $this->add_show_pending( '/addons.json?enriched=true' );
|
17596 |
+
|
17597 |
/**
|
17598 |
* @since 1.2.1
|
17599 |
*
|
17600 |
* If there's a cached version of the add-ons and not asking
|
17601 |
* for a flush, just use the currently stored add-ons.
|
17602 |
*/
|
17603 |
+
if ( ! $flush && $api->is_cached( $path ) ) {
|
17604 |
$addons = self::get_all_addons();
|
17605 |
|
17606 |
return $addons[ $this->_plugin->id ];
|
17607 |
}
|
17608 |
|
17609 |
+
$result = $api->get( $path, $flush );
|
17610 |
|
17611 |
$addons = array();
|
17612 |
if ( $this->is_api_result_object( $result, 'plugins' ) &&
|
18422 |
$vars = array( 'id' => $this->_module_id );
|
18423 |
|
18424 |
if ( 'true' === fs_request_get( 'checkout', false ) ) {
|
18425 |
+
echo $this->apply_filters( 'templates/checkout.php', fs_get_template( 'checkout.php', $vars ) );
|
18426 |
} else {
|
18427 |
+
echo $this->apply_filters( 'templates/pricing.php', fs_get_template( 'pricing.php', $vars ) );
|
18428 |
}
|
18429 |
}
|
18430 |
|
18539 |
* @return FS_Api
|
18540 |
*/
|
18541 |
private function get_current_or_network_user_api_scope( $flush = false ) {
|
18542 |
+
if ( ! $this->_is_network_active ||
|
18543 |
+
( isset( $this->_user ) && $this->_user instanceof FS_User )
|
18544 |
+
) {
|
18545 |
return $this->get_api_user_scope( $flush );
|
18546 |
}
|
18547 |
|
18629 |
* @author Vova Feldman (@svovaf)
|
18630 |
* @since 1.0.9
|
18631 |
*
|
18632 |
+
* @param FS_Plugin_Plan[] $plans
|
18633 |
*/
|
18634 |
function _check_for_trial_plans( $plans ) {
|
18635 |
+
/**
|
18636 |
+
* For some reason core's do_action() flattens arrays when it has a single object item. Therefore, we need to restructure the array as expected.
|
18637 |
+
*
|
18638 |
+
* @author Vova Feldman (@svovaf)
|
18639 |
+
* @since 2.1.2
|
18640 |
+
*/
|
18641 |
+
if ( ! is_array( $plans ) && is_object( $plans ) ) {
|
18642 |
+
$plans = array( $plans );
|
18643 |
+
}
|
18644 |
+
|
18645 |
$this->_storage->has_trial_plan = FS_Plan_Manager::instance()->has_trial_plan( $plans );
|
18646 |
}
|
18647 |
|
18748 |
|
18749 |
// Show promotion if never shown before and 24 hours after initial activation with FS.
|
18750 |
if ( ! $was_promotion_shown_before &&
|
18751 |
+
$this->_storage->install_timestamp > ( time() - $this->apply_filters( 'show_first_trial_after_n_sec', WP_FS__TIME_24_HOURS_IN_SEC ) )
|
18752 |
) {
|
18753 |
return false;
|
18754 |
}
|
18755 |
|
18756 |
// OR if promotion was shown before, try showing it every 30 days.
|
18757 |
if ( $was_promotion_shown_before &&
|
18758 |
+
$this->apply_filters( 'reshow_trial_after_every_n_sec', 30 * WP_FS__TIME_24_HOURS_IN_SEC ) > time() - $last_time_trial_promotion_shown
|
18759 |
) {
|
18760 |
return false;
|
18761 |
}
|
19380 |
* @param array $request
|
19381 |
* @param int $success_cache_expiration
|
19382 |
* @param int $failure_cache_expiration
|
19383 |
+
* @param bool $maybe_enrich_request_for_debug
|
19384 |
*
|
19385 |
* @return WP_Error|array
|
19386 |
*/
|
19387 |
+
static function safe_remote_post(
|
19388 |
&$url,
|
19389 |
$request,
|
19390 |
$success_cache_expiration = 0,
|
19391 |
+
$failure_cache_expiration = 0,
|
19392 |
+
$maybe_enrich_request_for_debug = true
|
19393 |
) {
|
19394 |
$should_cache = ($success_cache_expiration + $failure_cache_expiration > 0);
|
19395 |
|
19400 |
false;
|
19401 |
|
19402 |
if ( false === $response ) {
|
19403 |
+
if ( $maybe_enrich_request_for_debug ) {
|
19404 |
+
self::enrich_request_for_debug( $url, $request );
|
19405 |
+
}
|
19406 |
|
19407 |
$response = wp_remote_post( $url, $request );
|
19408 |
|
20157 |
$icon_found = false;
|
20158 |
$local_path = fs_normalize_path( "{$img_dir}/{$this->_slug}.png" );
|
20159 |
|
20160 |
+
if ( ! function_exists( 'get_filesystem_method' ) ) {
|
20161 |
+
require_once ABSPATH . 'wp-admin/includes/file.php';
|
20162 |
+
}
|
20163 |
+
|
20164 |
$have_write_permissions = ( 'direct' === get_filesystem_method( array(), fs_normalize_path( $img_dir ) ) );
|
20165 |
|
20166 |
/**
|
20677 |
* @since 2.1.0
|
20678 |
*/
|
20679 |
function _maybe_add_gdpr_optin_ajax_handler() {
|
20680 |
+
$this->add_ajax_action( 'fetch_is_marketing_required_flag_value', array( &$this, '_fetch_is_marketing_required_flag_value_ajax_action' ) );
|
|
|
|
|
20681 |
|
20682 |
if ( FS_GDPR_Manager::instance()->is_opt_in_notice_shown() ) {
|
20683 |
$this->add_gdpr_optin_ajax_handler_and_style();
|
20861 |
}
|
20862 |
|
20863 |
#endregion
|
20864 |
+
|
20865 |
+
#----------------------------------------------------------------------------------
|
20866 |
+
#region Helper
|
20867 |
+
#----------------------------------------------------------------------------------
|
20868 |
+
|
20869 |
+
/**
|
20870 |
+
* If running with a secret key, assume it's the developer and show pending plans as well.
|
20871 |
+
*
|
20872 |
+
* @author Vova Feldman (@svovaf)
|
20873 |
+
* @since 2.1.2
|
20874 |
+
*
|
20875 |
+
* @param string $path
|
20876 |
+
*
|
20877 |
+
* @return string
|
20878 |
+
*/
|
20879 |
+
function add_show_pending( $path ) {
|
20880 |
+
if ( ! $this->has_secret_key() ) {
|
20881 |
+
return $path;
|
20882 |
+
}
|
20883 |
+
|
20884 |
+
return $path . ( false !== strpos( $path, '?' ) ? '&' : '?' ) . 'show_pending=true';
|
20885 |
+
}
|
20886 |
+
|
20887 |
+
#endregion
|
20888 |
}
|
sdk/freemius/includes/class-fs-api.php
CHANGED
@@ -551,7 +551,7 @@
|
|
551 |
return (
|
552 |
is_object( $result ) &&
|
553 |
isset( $result->error ) &&
|
554 |
-
isset( $result->message )
|
555 |
);
|
556 |
}
|
557 |
|
551 |
return (
|
552 |
is_object( $result ) &&
|
553 |
isset( $result->error ) &&
|
554 |
+
isset( $result->error->message )
|
555 |
);
|
556 |
}
|
557 |
|
sdk/freemius/includes/class-fs-plugin-updater.php
CHANGED
@@ -29,6 +29,11 @@
|
|
29 |
* @since 1.1.8.1
|
30 |
*/
|
31 |
private $_update_details;
|
|
|
|
|
|
|
|
|
|
|
32 |
|
33 |
#--------------------------------------------------------------------------------
|
34 |
#region Singleton
|
@@ -324,6 +329,46 @@
|
|
324 |
(array) $this->_update_details;
|
325 |
}
|
326 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
327 |
return $transient_data;
|
328 |
}
|
329 |
|
@@ -508,6 +553,138 @@
|
|
508 |
return $res;
|
509 |
}
|
510 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
511 |
/**
|
512 |
* Updates information on the "View version x.x details" page with custom data.
|
513 |
*
|
29 |
* @since 1.1.8.1
|
30 |
*/
|
31 |
private $_update_details;
|
32 |
+
/**
|
33 |
+
* @var array
|
34 |
+
* @since 2.1.2
|
35 |
+
*/
|
36 |
+
private $_translation_updates;
|
37 |
|
38 |
#--------------------------------------------------------------------------------
|
39 |
#region Singleton
|
329 |
(array) $this->_update_details;
|
330 |
}
|
331 |
|
332 |
+
$slug = $this->_fs->get_slug();
|
333 |
+
|
334 |
+
if ( $this->_fs->is_org_repo_compliant() && $this->_fs->is_freemium() ) {
|
335 |
+
if ( ! isset( $this->_translation_updates ) ) {
|
336 |
+
$this->_translation_updates = array();
|
337 |
+
|
338 |
+
if ( current_user_can( 'update_languages' ) ) {
|
339 |
+
$translation_updates = $this->fetch_wp_org_module_translation_updates( $module_type, $slug );
|
340 |
+
if ( ! empty( $translation_updates ) ) {
|
341 |
+
$this->_translation_updates = $translation_updates;
|
342 |
+
}
|
343 |
+
}
|
344 |
+
}
|
345 |
+
|
346 |
+
if ( ! empty( $this->_translation_updates ) ) {
|
347 |
+
$all_translation_updates = ( isset( $transient_data->translations ) && is_array( $transient_data->translations ) ) ?
|
348 |
+
$transient_data->translations :
|
349 |
+
array();
|
350 |
+
|
351 |
+
$current_plugin_translation_updates_map = array();
|
352 |
+
foreach ( $all_translation_updates as $key => $translation_update ) {
|
353 |
+
if ( $module_type === ( $translation_update['type'] . 's' ) && $slug === $translation_update['slug'] ) {
|
354 |
+
$current_plugin_translation_updates_map[ $translation_update['language'] ] = $translation_update;
|
355 |
+
unset( $all_translation_updates[ $key ] );
|
356 |
+
}
|
357 |
+
}
|
358 |
+
|
359 |
+
foreach ( $this->_translation_updates as $translation_update ) {
|
360 |
+
$lang = $translation_update['language'];
|
361 |
+
if ( ! isset( $current_plugin_translation_updates_map[ $lang ] ) ||
|
362 |
+
version_compare( $translation_update['version'], $current_plugin_translation_updates_map[ $lang ]['version'], '>' )
|
363 |
+
) {
|
364 |
+
$current_plugin_translation_updates_map[ $lang ] = $translation_update;
|
365 |
+
}
|
366 |
+
}
|
367 |
+
|
368 |
+
$transient_data->translations = array_merge( $all_translation_updates, array_values( $current_plugin_translation_updates_map ) );
|
369 |
+
}
|
370 |
+
}
|
371 |
+
|
372 |
return $transient_data;
|
373 |
}
|
374 |
|
553 |
return $res;
|
554 |
}
|
555 |
|
556 |
+
/**
|
557 |
+
* Fetches module translation updates from wordpress.org.
|
558 |
+
*
|
559 |
+
* @author Leo Fajardo (@leorw)
|
560 |
+
* @since 2.1.2
|
561 |
+
*
|
562 |
+
* @param string $module_type
|
563 |
+
* @param string $slug
|
564 |
+
*
|
565 |
+
* @return array|null
|
566 |
+
*/
|
567 |
+
private function fetch_wp_org_module_translation_updates( $module_type, $slug ) {
|
568 |
+
$plugin_data = $this->_fs->get_plugin_data();
|
569 |
+
|
570 |
+
$locales = array_values( get_available_languages() );
|
571 |
+
$locales = apply_filters( "{$module_type}_update_check_locales", $locales );
|
572 |
+
$locales = array_unique( $locales );
|
573 |
+
|
574 |
+
$plugin_basename = $this->_fs->get_plugin_basename();
|
575 |
+
if ( 'themes' === $module_type ) {
|
576 |
+
$plugin_basename = str_replace( '-premium', '', $plugin_basename );
|
577 |
+
}
|
578 |
+
|
579 |
+
global $wp_version;
|
580 |
+
|
581 |
+
$request_args = array(
|
582 |
+
'timeout' => 15,
|
583 |
+
'body' => array(
|
584 |
+
"{$module_type}" => json_encode(
|
585 |
+
array(
|
586 |
+
"{$module_type}" => array(
|
587 |
+
$plugin_basename => array(
|
588 |
+
'Name' => trim( str_replace( '(Premium)', '', $plugin_data['Name'] ) ),
|
589 |
+
'Author' => $plugin_data['Author'],
|
590 |
+
)
|
591 |
+
)
|
592 |
+
)
|
593 |
+
),
|
594 |
+
'translations' => json_encode( $this->get_installed_translations( $module_type, $slug ) ),
|
595 |
+
'locale' => json_encode( $locales )
|
596 |
+
),
|
597 |
+
'user-agent' => ( 'WordPress/' . $wp_version . '; ' . home_url( '/' ) )
|
598 |
+
);
|
599 |
+
|
600 |
+
$url = "http://api.wordpress.org/{$module_type}/update-check/1.1/";
|
601 |
+
if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) {
|
602 |
+
$url = set_url_scheme( $url, 'https' );
|
603 |
+
}
|
604 |
+
|
605 |
+
$raw_response = Freemius::safe_remote_post(
|
606 |
+
$url,
|
607 |
+
$request_args,
|
608 |
+
WP_FS__TIME_24_HOURS_IN_SEC,
|
609 |
+
WP_FS__TIME_12_HOURS_IN_SEC,
|
610 |
+
false
|
611 |
+
);
|
612 |
+
|
613 |
+
if ( is_wp_error( $raw_response ) ) {
|
614 |
+
return null;
|
615 |
+
}
|
616 |
+
|
617 |
+
$response = json_decode( wp_remote_retrieve_body( $raw_response ), true );
|
618 |
+
|
619 |
+
if ( ! is_array( $response ) ) {
|
620 |
+
return null;
|
621 |
+
}
|
622 |
+
|
623 |
+
if ( ! isset( $response['translations'] ) || empty( $response['translations'] ) ) {
|
624 |
+
return null;
|
625 |
+
}
|
626 |
+
|
627 |
+
return $response['translations'];
|
628 |
+
}
|
629 |
+
|
630 |
+
/**
|
631 |
+
* @author Leo Fajardo (@leorw)
|
632 |
+
* @since 2.1.2
|
633 |
+
*
|
634 |
+
* @param string $module_type
|
635 |
+
* @param string $slug
|
636 |
+
*
|
637 |
+
* @return array
|
638 |
+
*/
|
639 |
+
private function get_installed_translations( $module_type, $slug ) {
|
640 |
+
if ( function_exists( 'wp_get_installed_translations' ) ) {
|
641 |
+
return wp_get_installed_translations( $module_type );
|
642 |
+
}
|
643 |
+
|
644 |
+
$dir = "/{$module_type}";
|
645 |
+
|
646 |
+
if ( ! is_dir( WP_LANG_DIR . $dir ) )
|
647 |
+
return array();
|
648 |
+
|
649 |
+
$files = scandir( WP_LANG_DIR . $dir );
|
650 |
+
if ( ! $files )
|
651 |
+
return array();
|
652 |
+
|
653 |
+
$language_data = array();
|
654 |
+
|
655 |
+
foreach ( $files as $file ) {
|
656 |
+
if ( 0 !== strpos( $file, $slug ) ) {
|
657 |
+
continue;
|
658 |
+
}
|
659 |
+
|
660 |
+
if ( '.' === $file[0] || is_dir( WP_LANG_DIR . "{$dir}/{$file}" ) ) {
|
661 |
+
continue;
|
662 |
+
}
|
663 |
+
|
664 |
+
if ( substr( $file, -3 ) !== '.po' ) {
|
665 |
+
continue;
|
666 |
+
}
|
667 |
+
|
668 |
+
if ( ! preg_match( '/(?:(.+)-)?([a-z]{2,3}(?:_[A-Z]{2})?(?:_[a-z0-9]+)?).po/', $file, $match ) ) {
|
669 |
+
continue;
|
670 |
+
}
|
671 |
+
|
672 |
+
if ( ! in_array( substr( $file, 0, -3 ) . '.mo', $files ) ) {
|
673 |
+
continue;
|
674 |
+
}
|
675 |
+
|
676 |
+
list( , $textdomain, $language ) = $match;
|
677 |
+
|
678 |
+
if ( '' === $textdomain ) {
|
679 |
+
$textdomain = 'default';
|
680 |
+
}
|
681 |
+
|
682 |
+
$language_data[ $textdomain ][ $language ] = wp_get_pomo_file_data( WP_LANG_DIR . "{$dir}/{$file}" );
|
683 |
+
}
|
684 |
+
|
685 |
+
return $language_data;
|
686 |
+
}
|
687 |
+
|
688 |
/**
|
689 |
* Updates information on the "View version x.x details" page with custom data.
|
690 |
*
|
sdk/freemius/includes/customizer/class-fs-customizer-upsell-control.php
CHANGED
@@ -59,7 +59,7 @@
|
|
59 |
$this->fs->get_upgrade_url();
|
60 |
|
61 |
// Load features.
|
62 |
-
$pricing = $this->fs->get_api_plugin_scope()->get(
|
63 |
|
64 |
if ( $this->fs->is_api_result_object( $pricing, 'plans' ) ) {
|
65 |
// Add support features.
|
59 |
$this->fs->get_upgrade_url();
|
60 |
|
61 |
// Load features.
|
62 |
+
$pricing = $this->fs->get_api_plugin_scope()->get( $this->fs->add_show_pending( "pricing.json" ) );
|
63 |
|
64 |
if ( $this->fs->is_api_result_object( $pricing, 'plans' ) ) {
|
65 |
// Add support features.
|
sdk/freemius/includes/fs-plugin-info-dialog.php
CHANGED
@@ -101,7 +101,7 @@
|
|
101 |
$has_features = false;
|
102 |
$plans = false;
|
103 |
|
104 |
-
$result = $this->_fs->get_api_plugin_scope()->get( "/addons/{$selected_addon->id}/pricing.json?type=visible" );
|
105 |
|
106 |
if ( ! isset( $result->error ) ) {
|
107 |
$plans = $result->plans;
|
@@ -165,6 +165,8 @@
|
|
165 |
// Plugin is missing, not on Freemius nor WP.org.
|
166 |
$data->wp_org_missing = true;
|
167 |
}
|
|
|
|
|
168 |
} else {
|
169 |
$data->wp_org_missing = false;
|
170 |
|
@@ -183,12 +185,7 @@
|
|
183 |
|
184 |
// Fetch as much as possible info from local files.
|
185 |
$plugin_local_data = $this->_fs->get_plugin_data();
|
186 |
-
$data->name = $selected_addon->title;
|
187 |
$data->author = $plugin_local_data['Author'];
|
188 |
-
$view_vars = array( 'plugin' => $selected_addon );
|
189 |
-
$data->sections = array(
|
190 |
-
'description' => fs_get_template( '/plugin-info/description.php', $view_vars ),
|
191 |
-
);
|
192 |
|
193 |
if ( ! empty( $selected_addon->info->banner_url ) ) {
|
194 |
$data->banners = array(
|
@@ -217,6 +214,12 @@
|
|
217 |
}
|
218 |
}
|
219 |
|
|
|
|
|
|
|
|
|
|
|
|
|
220 |
if ( $has_pricing ) {
|
221 |
// Add plans to data.
|
222 |
$data->plans = $plans;
|
@@ -950,7 +953,7 @@
|
|
950 |
</li>
|
951 |
<?php
|
952 |
}
|
953 |
-
if ( ! empty( $api->slug ) &&
|
954 |
?>
|
955 |
<li><a target="_blank"
|
956 |
href="https://wordpress.org/plugins/<?php echo $api->slug; ?>/"><?php fs_esc_html_echo_inline( 'WordPress.org Plugin Page', 'wp-org-plugin-page', $api->slug ) ?>
|
@@ -1094,7 +1097,7 @@
|
|
1094 |
echo "</div>\n"; // #plugin-information-scrollable
|
1095 |
echo "<div id='$tab-footer'>\n";
|
1096 |
|
1097 |
-
if ( ! empty( $api->checkout_link ) ) {
|
1098 |
echo $this->get_checkout_cta( $api );
|
1099 |
}
|
1100 |
|
101 |
$has_features = false;
|
102 |
$plans = false;
|
103 |
|
104 |
+
$result = $this->_fs->get_api_plugin_scope()->get( $this->_fs->add_show_pending( "/addons/{$selected_addon->id}/pricing.json?type=visible" ) );
|
105 |
|
106 |
if ( ! isset( $result->error ) ) {
|
107 |
$plans = $result->plans;
|
165 |
// Plugin is missing, not on Freemius nor WP.org.
|
166 |
$data->wp_org_missing = true;
|
167 |
}
|
168 |
+
|
169 |
+
$data->fs_missing = ( ! $has_free_plan || $data->wp_org_missing );
|
170 |
} else {
|
171 |
$data->wp_org_missing = false;
|
172 |
|
185 |
|
186 |
// Fetch as much as possible info from local files.
|
187 |
$plugin_local_data = $this->_fs->get_plugin_data();
|
|
|
188 |
$data->author = $plugin_local_data['Author'];
|
|
|
|
|
|
|
|
|
189 |
|
190 |
if ( ! empty( $selected_addon->info->banner_url ) ) {
|
191 |
$data->banners = array(
|
214 |
}
|
215 |
}
|
216 |
|
217 |
+
$data->name = $selected_addon->title;
|
218 |
+
$view_vars = array( 'plugin' => $selected_addon );
|
219 |
+
$data->sections = array(
|
220 |
+
'description' => fs_get_template( '/plugin-info/description.php', $view_vars ),
|
221 |
+
);
|
222 |
+
|
223 |
if ( $has_pricing ) {
|
224 |
// Add plans to data.
|
225 |
$data->plans = $plans;
|
953 |
</li>
|
954 |
<?php
|
955 |
}
|
956 |
+
if ( ! empty( $api->slug ) && true == $api->is_wp_org_compliant ) {
|
957 |
?>
|
958 |
<li><a target="_blank"
|
959 |
href="https://wordpress.org/plugins/<?php echo $api->slug; ?>/"><?php fs_esc_html_echo_inline( 'WordPress.org Plugin Page', 'wp-org-plugin-page', $api->slug ) ?>
|
1097 |
echo "</div>\n"; // #plugin-information-scrollable
|
1098 |
echo "<div id='$tab-footer'>\n";
|
1099 |
|
1100 |
+
if ( $api->has_paid_plan && ! empty( $api->checkout_link ) ) {
|
1101 |
echo $this->get_checkout_cta( $api );
|
1102 |
}
|
1103 |
|
sdk/freemius/languages/freemius-da_DK.mo
CHANGED
Binary file
|
sdk/freemius/languages/freemius-da_DK.po
CHANGED
@@ -1,2299 +1,12 @@
|
|
1 |
-
# Copyright (C) 2018 freemius
|
2 |
-
# This file is distributed under the same license as the freemius package.
|
3 |
-
# Translators:
|
4 |
-
# Joachim Jensen, 2016-2018
|
5 |
msgid ""
|
6 |
msgstr ""
|
7 |
-
"Project-Id-Version:
|
8 |
-
"Report-Msgid-Bugs-To:
|
9 |
"POT-Creation-Date: \n"
|
10 |
-
"PO-Revision-Date:
|
11 |
-
"Last-Translator:
|
12 |
-
"Language:
|
13 |
-
"Language-Team:
|
14 |
-
"Content-Type:
|
15 |
-
"Content-Transfer-Encoding:
|
16 |
-
"Plural-Forms:
|
17 |
-
"MIME-Version: 1.0\n"
|
18 |
-
"X-Poedit-Basepath: ..\n"
|
19 |
-
"X-Poedit-KeywordsList: get_text_inline;fs_text_inline;fs_echo_inline;fs_esc_js_inline;fs_esc_attr_inline;fs_esc_attr_echo_inline;fs_esc_html_inline;fs_esc_html_echo_inline;get_text_x_inline:1,2c;fs_text_x_inline:1,2c;fs_echo_x_inline:1,2c;fs_esc_attr_x_inline:1,2c;fs_esc_js_x_inline:1,2c;fs_esc_js_echo_x_inline:1,2c;fs_esc_html_x_inline:1,2c;fs_esc_html_echo_x_inline:1,2c\n"
|
20 |
-
"X-Poedit-SearchPath-0: .\n"
|
21 |
-
"X-Poedit-SearchPathExcluded-0: *.js\n"
|
22 |
-
"X-Poedit-SourceCharset: UTF-8\n"
|
23 |
-
|
24 |
-
#: includes/class-freemius.php:1551
|
25 |
-
msgid "Freemius SDK couldn't find the plugin's main file. Please contact sdk@freemius.com with the current error."
|
26 |
-
msgstr "Freemius SDK couldn't find the plugin's main file. Please contact sdk@freemius.com with the current error."
|
27 |
-
|
28 |
-
#: includes/class-freemius.php:1553
|
29 |
-
msgid "Error"
|
30 |
-
msgstr "Fejl"
|
31 |
-
|
32 |
-
#: includes/class-freemius.php:1871
|
33 |
-
msgid "I found a better %s"
|
34 |
-
msgstr "Jeg fandt et bedre %s"
|
35 |
-
|
36 |
-
#: includes/class-freemius.php:1873
|
37 |
-
msgid "What's the %s's name?"
|
38 |
-
msgstr "What's the %s's name?"
|
39 |
-
|
40 |
-
#: includes/class-freemius.php:1879
|
41 |
-
msgid "It's a temporary %s. I'm just debugging an issue."
|
42 |
-
msgstr "It's a temporary %s. I'm just debugging an issue."
|
43 |
-
|
44 |
-
#: includes/class-freemius.php:1881
|
45 |
-
msgid "Deactivation"
|
46 |
-
msgstr "Deaktivering"
|
47 |
-
|
48 |
-
#: includes/class-freemius.php:1882
|
49 |
-
msgid "Theme Switch"
|
50 |
-
msgstr "Temaskift"
|
51 |
-
|
52 |
-
#: includes/class-freemius.php1891, templates/forms/resend-key.php:24
|
53 |
-
msgid "Other"
|
54 |
-
msgstr "Andet"
|
55 |
-
|
56 |
-
#: includes/class-freemius.php:1899
|
57 |
-
msgid "I no longer need the %s"
|
58 |
-
msgstr "Jeg har ikke længere brug for %s"
|
59 |
-
|
60 |
-
#: includes/class-freemius.php:1906
|
61 |
-
msgid "I only needed the %s for a short period"
|
62 |
-
msgstr "Jeg behøvede kun %s i en kort periode"
|
63 |
-
|
64 |
-
#: includes/class-freemius.php:1912
|
65 |
-
msgid "The %s broke my site"
|
66 |
-
msgstr "%s ødelagde min webside"
|
67 |
-
|
68 |
-
#: includes/class-freemius.php:1919
|
69 |
-
msgid "The %s suddenly stopped working"
|
70 |
-
msgstr "%s stoppede pludseligt med at virke"
|
71 |
-
|
72 |
-
#: includes/class-freemius.php:1929
|
73 |
-
msgid "I can't pay for it anymore"
|
74 |
-
msgstr "Jeg kan ikke længere betale for det"
|
75 |
-
|
76 |
-
#: includes/class-freemius.php:1931
|
77 |
-
msgid "What price would you feel comfortable paying?"
|
78 |
-
msgstr "Hvilken pris ville du foretrække at betale?"
|
79 |
-
|
80 |
-
#: includes/class-freemius.php:1937
|
81 |
-
msgid "I don't like to share my information with you"
|
82 |
-
msgstr "Jeg har ikke lyst til at dele mine informationer med jer"
|
83 |
-
|
84 |
-
#: includes/class-freemius.php:1958
|
85 |
-
msgid "The %s didn't work"
|
86 |
-
msgstr "%s virkede ikke"
|
87 |
-
|
88 |
-
#: includes/class-freemius.php:1968
|
89 |
-
msgid "I couldn't understand how to make it work"
|
90 |
-
msgstr "Jeg forstod ikke, hvordan jeg skulle få det til at fungere."
|
91 |
-
|
92 |
-
#: includes/class-freemius.php:1976
|
93 |
-
msgid "The %s is great, but I need specific feature that you don't support"
|
94 |
-
msgstr "%s er godt, men jeg har brug for en specifik feature, som ikke understøttes"
|
95 |
-
|
96 |
-
#: includes/class-freemius.php:1978
|
97 |
-
msgid "What feature?"
|
98 |
-
msgstr "Hvilken feature?"
|
99 |
-
|
100 |
-
#: includes/class-freemius.php:1982
|
101 |
-
msgid "The %s is not working"
|
102 |
-
msgstr "%s virker ikke"
|
103 |
-
|
104 |
-
#: includes/class-freemius.php:1984
|
105 |
-
msgid "Kindly share what didn't work so we can fix it for future users..."
|
106 |
-
msgstr "Kindly share what didn't work so we can fix it for future users..."
|
107 |
-
|
108 |
-
#: includes/class-freemius.php:1988
|
109 |
-
msgid "It's not what I was looking for"
|
110 |
-
msgstr "Det er ikke, hvad jeg søgte"
|
111 |
-
|
112 |
-
#: includes/class-freemius.php:1990
|
113 |
-
msgid "What you've been looking for?"
|
114 |
-
msgstr "What you've been looking for?"
|
115 |
-
|
116 |
-
#: includes/class-freemius.php:1994
|
117 |
-
msgid "The %s didn't work as expected"
|
118 |
-
msgstr "%s virkede ikke som forventet"
|
119 |
-
|
120 |
-
#: includes/class-freemius.php:1996
|
121 |
-
msgid "What did you expect?"
|
122 |
-
msgstr "Hvad forventede du?"
|
123 |
-
|
124 |
-
#: includes/class-freemius.php2729, templates/debug.php:20
|
125 |
-
msgid "Freemius Debug"
|
126 |
-
msgstr "Freemius Debug"
|
127 |
-
|
128 |
-
#: includes/class-freemius.php:3402
|
129 |
-
msgid "I don't know what is cURL or how to install it, help me!"
|
130 |
-
msgstr "Jeg ved ikke hvad cURL er, eller hvordan jeg installerer det. Hjælp mig!"
|
131 |
-
|
132 |
-
#: includes/class-freemius.php:3404
|
133 |
-
msgid "We'll make sure to contact your hosting company and resolve the issue. You will get a follow-up email to %s once we have an update."
|
134 |
-
msgstr "Vi vil kontakte din udbyder og løse problemet. Når vi har opdatinger i sagen, vil vi følge op med en email til dig på %s."
|
135 |
-
|
136 |
-
#: includes/class-freemius.php:3411
|
137 |
-
msgid "Great, please install cURL and enable it in your php.ini file. In addition, search for the 'disable_functions' directive in your php.ini file and remove any disabled methods starting with 'curl_'. To make sure it was successfully activated, use 'phpinfo()'. Once activated, deactivate the %s and reactivate it back again."
|
138 |
-
msgstr "Great, please install cURL and enable it in your php.ini file. In addition, search for the 'disable_functions' directive in your php.ini file and remove any disabled methods starting with 'curl_'. To make sure it was successfully activated, use 'phpinfo()'. Once activated, deactivate the %s and reactivate it back again."
|
139 |
-
|
140 |
-
#: includes/class-freemius.php:3516
|
141 |
-
msgid "Yes - do your thing"
|
142 |
-
msgstr "Yes - do your thing"
|
143 |
-
|
144 |
-
#: includes/class-freemius.php:3521
|
145 |
-
msgid "No - just deactivate"
|
146 |
-
msgstr "Nej - bare deaktiver"
|
147 |
-
|
148 |
-
#: includes/class-freemius.php3566, includes/class-freemius.php4066,
|
149 |
-
#: includes/class-freemius.php5127, includes/class-freemius.php10941,
|
150 |
-
#: includes/class-freemius.php14205, includes/class-freemius.php14257,
|
151 |
-
#: includes/class-freemius.php14319, includes/class-freemius.php16448,
|
152 |
-
#: includes/class-freemius.php16458, includes/class-freemius.php17014,
|
153 |
-
#: includes/class-freemius.php17032, includes/class-freemius.php17130,
|
154 |
-
#: includes/class-freemius.php17866, templates/add-ons.php:43
|
155 |
-
msgctxt "exclamation"
|
156 |
-
msgid "Oops"
|
157 |
-
msgstr "Ups"
|
158 |
-
|
159 |
-
#: includes/class-freemius.php:3635
|
160 |
-
msgid "Thank for giving us the chance to fix it! A message was just sent to our technical staff. We will get back to you as soon as we have an update to %s. Appreciate your patience."
|
161 |
-
msgstr "Thank for giving us the chance to fix it! A message was just sent to our technical staff. We will get back to you as soon as we have an update to %s. Appreciate your patience."
|
162 |
-
|
163 |
-
#: includes/class-freemius.php:4063
|
164 |
-
msgctxt "addonX cannot run without pluginY"
|
165 |
-
msgid "%s cannot run without %s."
|
166 |
-
msgstr "%s virker ikke uden %s."
|
167 |
-
|
168 |
-
#: includes/class-freemius.php:4064
|
169 |
-
msgctxt "addonX cannot run..."
|
170 |
-
msgid "%s cannot run without the plugin."
|
171 |
-
msgstr "%s virker ikke uden pluginnet."
|
172 |
-
|
173 |
-
#: includes/class-freemius.php4176, includes/class-freemius.php4201,
|
174 |
-
#: includes/class-freemius.php:17103
|
175 |
-
msgid "Unexpected API error. Please contact the %s's author with the following error."
|
176 |
-
msgstr "Unexpected API error. Please contact the %s's author with the following error."
|
177 |
-
|
178 |
-
#: includes/class-freemius.php:4815
|
179 |
-
msgid "Premium %s version was successfully activated."
|
180 |
-
msgstr "Premium %s version was successfully activated."
|
181 |
-
|
182 |
-
#: includes/class-freemius.php4827, includes/class-freemius.php:6660
|
183 |
-
msgctxt ""
|
184 |
-
msgid "W00t"
|
185 |
-
msgstr "W00t"
|
186 |
-
|
187 |
-
#: includes/class-freemius.php:4842
|
188 |
-
msgid "You have a %s license."
|
189 |
-
msgstr "Du har en %s licens."
|
190 |
-
|
191 |
-
#: includes/class-freemius.php4846, includes/class-freemius.php13626,
|
192 |
-
#: includes/class-freemius.php13637, includes/class-freemius.php16376,
|
193 |
-
#: includes/class-freemius.php16676, includes/class-freemius.php16741,
|
194 |
-
#: includes/class-freemius.php:16891
|
195 |
-
msgctxt "interjection expressing joy or exuberance"
|
196 |
-
msgid "Yee-haw"
|
197 |
-
msgstr "Yee-haw"
|
198 |
-
|
199 |
-
#: includes/class-freemius.php:5110
|
200 |
-
msgid "%s free trial was successfully cancelled. Since the add-on is premium only it was automatically deactivated. If you like to use it in the future, you'll have to purchase a license."
|
201 |
-
msgstr "%s free trial was successfully cancelled. Since the add-on is premium only it was automatically deactivated. If you like to use it in the future, you'll have to purchase a license."
|
202 |
-
|
203 |
-
#: includes/class-freemius.php:5114
|
204 |
-
msgid "%s is a premium only add-on. You have to purchase a license first before activating the plugin."
|
205 |
-
msgstr "%s is a premium only add-on. You have to purchase a license first before activating the plugin."
|
206 |
-
|
207 |
-
#: includes/class-freemius.php5123, templates/add-ons.php99,
|
208 |
-
#: templates/account/partials/addon.php:283
|
209 |
-
msgid "More information about %s"
|
210 |
-
msgstr "Mere information om %s"
|
211 |
-
|
212 |
-
#: includes/class-freemius.php:5124
|
213 |
-
msgid "Purchase License"
|
214 |
-
msgstr "Køb licens"
|
215 |
-
|
216 |
-
#: includes/class-freemius.php6035, templates/connect.php:161
|
217 |
-
msgid "You should receive an activation email for %s to your mailbox at %s. Please make sure you click the activation button in that email to %s."
|
218 |
-
msgstr "You should receive an activation email for %s to your mailbox at %s. Please make sure you click the activation button in that email to %s."
|
219 |
-
|
220 |
-
#: includes/class-freemius.php:6039
|
221 |
-
msgid "start the trial"
|
222 |
-
msgstr "start prøveperioden"
|
223 |
-
|
224 |
-
#: includes/class-freemius.php6040, templates/connect.php:165
|
225 |
-
msgid "complete the install"
|
226 |
-
msgstr "færdiggør installeringen"
|
227 |
-
|
228 |
-
#: includes/class-freemius.php:6147
|
229 |
-
msgid "You are just one step away - %s"
|
230 |
-
msgstr "Du mangler kun ét skridt - %s"
|
231 |
-
|
232 |
-
#: includes/class-freemius.php:6150
|
233 |
-
msgctxt "%s - plugin name. As complete \"PluginX\" activation now"
|
234 |
-
msgid "Complete \"%s\" Activation Now"
|
235 |
-
msgstr "Færdiggør aktivering af \"%s\" nu"
|
236 |
-
|
237 |
-
#: includes/class-freemius.php:6227
|
238 |
-
msgid "We made a few tweaks to the %s, %s"
|
239 |
-
msgstr "We made a few tweaks to the %s, %s"
|
240 |
-
|
241 |
-
#: includes/class-freemius.php:6231
|
242 |
-
msgid "Opt in to make \"%s\" Better!"
|
243 |
-
msgstr "Opt in to make \"%s\" Better!"
|
244 |
-
|
245 |
-
#: includes/class-freemius.php:6659
|
246 |
-
msgid "The upgrade of %s was successfully completed."
|
247 |
-
msgstr "Opgraderingen af %s blev fuldendt."
|
248 |
-
|
249 |
-
#: includes/class-freemius.php8384, includes/class-fs-plugin-updater.php581,
|
250 |
-
#: includes/class-fs-plugin-updater.php733,
|
251 |
-
#: includes/class-fs-plugin-updater.php739, templates/auto-installation.php:32
|
252 |
-
msgid "Add-On"
|
253 |
-
msgstr "Tilføjelse"
|
254 |
-
|
255 |
-
#: includes/class-freemius.php8386, templates/debug.php349,
|
256 |
-
#: templates/debug.php:510
|
257 |
-
msgid "Plugin"
|
258 |
-
msgstr "Plugin"
|
259 |
-
|
260 |
-
#: includes/class-freemius.php8387, templates/debug.php349,
|
261 |
-
#: templates/debug.php510, templates/forms/deactivation/form.php:64
|
262 |
-
msgid "Theme"
|
263 |
-
msgstr "Tema"
|
264 |
-
|
265 |
-
#: includes/class-freemius.php:10808
|
266 |
-
msgid "invalid_site_details_collection"
|
267 |
-
msgstr "invalid_site_details_collection"
|
268 |
-
|
269 |
-
#: includes/class-freemius.php:10928
|
270 |
-
msgid "We couldn't find your email address in the system, are you sure it's the right address?"
|
271 |
-
msgstr "We couldn't find your email address in the system, are you sure it's the right address?"
|
272 |
-
|
273 |
-
#: includes/class-freemius.php:10930
|
274 |
-
msgid "We can't see any active licenses associated with that email address, are you sure it's the right address?"
|
275 |
-
msgstr "We can't see any active licenses associated with that email address, are you sure it's the right address?"
|
276 |
-
|
277 |
-
#: includes/class-freemius.php:11166
|
278 |
-
msgid "Account is pending activation."
|
279 |
-
msgstr "Account is pending activation."
|
280 |
-
|
281 |
-
#: includes/class-freemius.php:13608
|
282 |
-
msgid "%s activation was successfully completed."
|
283 |
-
msgstr "Aktivering af %s blev gennemført."
|
284 |
-
|
285 |
-
#: includes/class-freemius.php:13622
|
286 |
-
msgid "Your account was successfully activated with the %s plan."
|
287 |
-
msgstr "Din konto blev aktiveret med planen %s."
|
288 |
-
|
289 |
-
#: includes/class-freemius.php13633, includes/class-freemius.php:16737
|
290 |
-
msgid "Your trial has been successfully started."
|
291 |
-
msgstr "Din prøveperiode er begyndt."
|
292 |
-
|
293 |
-
#: includes/class-freemius.php14203, includes/class-freemius.php14255,
|
294 |
-
#: includes/class-freemius.php:14317
|
295 |
-
msgid "Couldn't activate %s."
|
296 |
-
msgstr "Kunne ikke aktivere %s."
|
297 |
-
|
298 |
-
#: includes/class-freemius.php14204, includes/class-freemius.php14256,
|
299 |
-
#: includes/class-freemius.php:14318
|
300 |
-
msgid "Please contact us with the following message:"
|
301 |
-
msgstr "Kontakt os venligst med følgende besked:"
|
302 |
-
|
303 |
-
#: includes/class-freemius.php14666, includes/class-freemius.php:18929
|
304 |
-
msgid "Upgrade"
|
305 |
-
msgstr "Opgrader"
|
306 |
-
|
307 |
-
#: includes/class-freemius.php:14672
|
308 |
-
msgid "Start Trial"
|
309 |
-
msgstr "Start prøveperiode"
|
310 |
-
|
311 |
-
#: includes/class-freemius.php:14674
|
312 |
-
msgid "Pricing"
|
313 |
-
msgstr "Priser"
|
314 |
-
|
315 |
-
#: includes/class-freemius.php14734, includes/class-freemius.php:14736
|
316 |
-
msgid "Affiliation"
|
317 |
-
msgstr "Affiliation"
|
318 |
-
|
319 |
-
#: includes/class-freemius.php14756, includes/class-freemius.php14758,
|
320 |
-
#: templates/account.php146, templates/debug.php:314
|
321 |
-
msgid "Account"
|
322 |
-
msgstr "Konto"
|
323 |
-
|
324 |
-
#: includes/class-freemius.php14769, includes/class-freemius.php14771,
|
325 |
-
#: includes/customizer/class-fs-customizer-support-section.php:60
|
326 |
-
msgid "Contact Us"
|
327 |
-
msgstr "Kontakt os"
|
328 |
-
|
329 |
-
#: includes/class-freemius.php14781, includes/class-freemius.php14783,
|
330 |
-
#: includes/class-freemius.php18939, templates/account.php96,
|
331 |
-
#: templates/account/partials/addon.php:37
|
332 |
-
msgid "Add-Ons"
|
333 |
-
msgstr "Tilføjelser"
|
334 |
-
|
335 |
-
#: includes/class-freemius.php14815, templates/pricing.php:97
|
336 |
-
msgctxt "noun"
|
337 |
-
msgid "Pricing"
|
338 |
-
msgstr "Priser"
|
339 |
-
|
340 |
-
#: includes/class-freemius.php15009,
|
341 |
-
#: includes/customizer/class-fs-customizer-support-section.php:67
|
342 |
-
msgid "Support Forum"
|
343 |
-
msgstr "Supportforum"
|
344 |
-
|
345 |
-
#: includes/class-freemius.php:15794
|
346 |
-
msgid "Your email has been successfully verified - you are AWESOME!"
|
347 |
-
msgstr "Din e-mailadresse er blevet verificeret - du er FOR SEJ!"
|
348 |
-
|
349 |
-
#: includes/class-freemius.php:15795
|
350 |
-
msgctxt "a positive response"
|
351 |
-
msgid "Right on"
|
352 |
-
msgstr "Sådan"
|
353 |
-
|
354 |
-
#: includes/class-freemius.php:16367
|
355 |
-
msgid "Your %s Add-on plan was successfully upgraded."
|
356 |
-
msgstr "Your %s Add-on plan was successfully upgraded."
|
357 |
-
|
358 |
-
#: includes/class-freemius.php:16369
|
359 |
-
msgid "%s Add-on was successfully purchased."
|
360 |
-
msgstr "Betalingen for tilføjelsen %s blev gennemført."
|
361 |
-
|
362 |
-
#: includes/class-freemius.php:16372
|
363 |
-
msgid "Download the latest version"
|
364 |
-
msgstr "Download den seneste version"
|
365 |
-
|
366 |
-
#: includes/class-freemius.php:16444
|
367 |
-
msgctxt "%1s - plugin title, %2s - API domain"
|
368 |
-
msgid "Your server is blocking the access to Freemius' API, which is crucial for %1s synchronization. Please contact your host to whitelist %2s"
|
369 |
-
msgstr "Your server is blocking the access to Freemius' API, which is crucial for %1s synchronization. Please contact your host to whitelist %2s"
|
370 |
-
|
371 |
-
#: includes/class-freemius.php16447, includes/class-freemius.php16862,
|
372 |
-
#: includes/class-freemius.php:16927
|
373 |
-
msgid "Error received from the server:"
|
374 |
-
msgstr "Fejl modtager fra serveren:"
|
375 |
-
|
376 |
-
#: includes/class-freemius.php:16457
|
377 |
-
msgid "It seems like one of the authentication parameters is wrong. Update your Public Key, Secret Key & User ID, and try again."
|
378 |
-
msgstr "It seems like one of the authentication parameters is wrong. Update your Public Key, Secret Key & User ID, and try again."
|
379 |
-
|
380 |
-
#: includes/class-freemius.php16639, includes/class-freemius.php16867,
|
381 |
-
#: includes/class-freemius.php:16910
|
382 |
-
msgctxt ""
|
383 |
-
msgid "Hmm"
|
384 |
-
msgstr "Hmm"
|
385 |
-
|
386 |
-
#: includes/class-freemius.php:16652
|
387 |
-
msgid "It looks like you are still on the %s plan. If you did upgrade or change your plan, it's probably an issue on our side - sorry."
|
388 |
-
msgstr "It looks like you are still on the %s plan. If you did upgrade or change your plan, it's probably an issue on our side - sorry."
|
389 |
-
|
390 |
-
#: includes/class-freemius.php16653, templates/account.php98,
|
391 |
-
#: templates/add-ons.php130, templates/account/partials/addon.php:39
|
392 |
-
msgctxt "trial period"
|
393 |
-
msgid "Trial"
|
394 |
-
msgstr "Prøveperiode"
|
395 |
-
|
396 |
-
#: includes/class-freemius.php:16658
|
397 |
-
msgid "I have upgraded my account but when I try to Sync the License, the plan remains %s."
|
398 |
-
msgstr "I have upgraded my account but when I try to Sync the License, the plan remains %s."
|
399 |
-
|
400 |
-
#: includes/class-freemius.php16662, includes/class-freemius.php:16719
|
401 |
-
msgid "Please contact us here"
|
402 |
-
msgstr "Kontakt os her"
|
403 |
-
|
404 |
-
#: includes/class-freemius.php:16672
|
405 |
-
msgid "Your plan was successfully upgraded."
|
406 |
-
msgstr "Din plan er blevet opgraderet."
|
407 |
-
|
408 |
-
#: includes/class-freemius.php:16689
|
409 |
-
msgid "Your plan was successfully changed to %s."
|
410 |
-
msgstr "Din plan er blevet ændret til %s."
|
411 |
-
|
412 |
-
#: includes/class-freemius.php:16705
|
413 |
-
msgid "Your license has expired. You can still continue using the free %s forever."
|
414 |
-
msgstr "Your license has expired. You can still continue using the free %s forever."
|
415 |
-
|
416 |
-
#: includes/class-freemius.php:16707
|
417 |
-
msgid "Your license has expired. %1$sUpgrade now%2$s to continue using the %3$s without interruptions."
|
418 |
-
msgstr "Your license has expired. %1$sUpgrade now%2$s to continue using the %3$s without interruptions."
|
419 |
-
|
420 |
-
#: includes/class-freemius.php:16715
|
421 |
-
msgid "Your license has been cancelled. If you think it's a mistake, please contact support."
|
422 |
-
msgstr "Din licens er blevet annulleret. Hvis du mener, dette er en fejl, så kontakt venligst support."
|
423 |
-
|
424 |
-
#: includes/class-freemius.php:16728
|
425 |
-
msgid "Your license has expired. You can still continue using all the %s features, but you'll need to renew your license to continue getting updates and support."
|
426 |
-
msgstr "Din licens er udløbet. Du kan stadig benytte alle funktionerne i %s, men du bliver nødt til at fornye din licens for at få opdateringer og support."
|
427 |
-
|
428 |
-
#: includes/class-freemius.php:16751
|
429 |
-
msgid "Your free trial has expired. You can still continue using all our free features."
|
430 |
-
msgstr "Your free trial has expired. You can still continue using all our free features."
|
431 |
-
|
432 |
-
#: includes/class-freemius.php:16753
|
433 |
-
msgid "Your free trial has expired. %1$sUpgrade now%2$s to continue using the %3$s without interruptions."
|
434 |
-
msgstr "Your free trial has expired. %1$sUpgrade now%2$s to continue using the %3$s without interruptions."
|
435 |
-
|
436 |
-
#: includes/class-freemius.php:16858
|
437 |
-
msgid "It looks like the license could not be activated."
|
438 |
-
msgstr "Det ser ud til, at licensen ikke kunne aktiveres."
|
439 |
-
|
440 |
-
#: includes/class-freemius.php:16888
|
441 |
-
msgid "Your license was successfully activated."
|
442 |
-
msgstr "Din licens er blevet aktiveret."
|
443 |
-
|
444 |
-
#: includes/class-freemius.php:16914
|
445 |
-
msgid "It looks like your site currently doesn't have an active license."
|
446 |
-
msgstr "Det ser ud til, at dit websted endnu ikke har en aktiv licens."
|
447 |
-
|
448 |
-
#: includes/class-freemius.php:16926
|
449 |
-
msgid "It looks like the license deactivation failed."
|
450 |
-
msgstr "Det ser ud til, at licens-deaktiveringen mislykkedes."
|
451 |
-
|
452 |
-
#: includes/class-freemius.php:16954
|
453 |
-
msgid "Your license was successfully deactivated, you are back to the %s plan."
|
454 |
-
msgstr "Din licens blev deaktiveret, du er tilbage på planen %s."
|
455 |
-
|
456 |
-
#: includes/class-freemius.php:16955
|
457 |
-
msgid "O.K"
|
458 |
-
msgstr "O.K"
|
459 |
-
|
460 |
-
#: includes/class-freemius.php:17003
|
461 |
-
msgid "Your plan was successfully downgraded. Your %s plan license will expire in %s."
|
462 |
-
msgstr "Din plan blev nedgraderet. Licensen til din %s plan vil udløbe om %s."
|
463 |
-
|
464 |
-
#: includes/class-freemius.php:17013
|
465 |
-
msgid "Seems like we are having some temporary issue with your plan downgrade. Please try again in few minutes."
|
466 |
-
msgstr "Seems like we are having some temporary issue with your plan downgrade. Please try again in few minutes."
|
467 |
-
|
468 |
-
#: includes/class-freemius.php:17037
|
469 |
-
msgid "You are already running the %s in a trial mode."
|
470 |
-
msgstr "You are already running the %s in a trial mode."
|
471 |
-
|
472 |
-
#: includes/class-freemius.php:17048
|
473 |
-
msgid "You already utilized a trial before."
|
474 |
-
msgstr "Du har allerede brugt din prøveperiode."
|
475 |
-
|
476 |
-
#: includes/class-freemius.php:17062
|
477 |
-
msgid "Plan %s do not exist, therefore, can't start a trial."
|
478 |
-
msgstr "Plan %s eksisterer ikke og kan derfor ikke starte prøveperiode."
|
479 |
-
|
480 |
-
#: includes/class-freemius.php:17073
|
481 |
-
msgid "Plan %s does not support a trial period."
|
482 |
-
msgstr "Plan %s understøtter ikke en prøveperiode."
|
483 |
-
|
484 |
-
#: includes/class-freemius.php:17084
|
485 |
-
msgid "None of the %s's plans supports a trial period."
|
486 |
-
msgstr "None of the %s's plans supports a trial period."
|
487 |
-
|
488 |
-
#: includes/class-freemius.php:17134
|
489 |
-
msgid "It looks like you are not in trial mode anymore so there's nothing to cancel :)"
|
490 |
-
msgstr "It looks like you are not in trial mode anymore so there's nothing to cancel :)"
|
491 |
-
|
492 |
-
#: includes/class-freemius.php:17185
|
493 |
-
msgid "Your %s free trial was successfully cancelled."
|
494 |
-
msgstr "Din gratis prøveperiode for %s er blevet annulleret."
|
495 |
-
|
496 |
-
#: includes/class-freemius.php:17190
|
497 |
-
msgid "Seems like we are having some temporary issue with your trial cancellation. Please try again in few minutes."
|
498 |
-
msgstr "Seems like we are having some temporary issue with your trial cancellation. Please try again in few minutes."
|
499 |
-
|
500 |
-
#: includes/class-freemius.php:17474
|
501 |
-
msgid "Version %s was released."
|
502 |
-
msgstr "Version %s er blevet udgivet."
|
503 |
-
|
504 |
-
#: includes/class-freemius.php:17474
|
505 |
-
msgid "Please download %s."
|
506 |
-
msgstr "Download venligst %s."
|
507 |
-
|
508 |
-
#: includes/class-freemius.php:17481
|
509 |
-
msgid "the latest %s version here"
|
510 |
-
msgstr "den seneste version af %s her"
|
511 |
-
|
512 |
-
#: includes/class-freemius.php:17486
|
513 |
-
msgid "New"
|
514 |
-
msgstr "Ny"
|
515 |
-
|
516 |
-
#: includes/class-freemius.php:17491
|
517 |
-
msgid "Seems like you got the latest release."
|
518 |
-
msgstr "Det ser ud til, at du har den seneste udgivelse."
|
519 |
-
|
520 |
-
#: includes/class-freemius.php:17492
|
521 |
-
msgid "You are all good!"
|
522 |
-
msgstr "Det var det!"
|
523 |
-
|
524 |
-
#: includes/class-freemius.php:17758
|
525 |
-
msgid "Verification mail was just sent to %s. If you can't find it after 5 min, please check your spam box."
|
526 |
-
msgstr "Verification mail was just sent to %s. If you can't find it after 5 min, please check your spam box."
|
527 |
-
|
528 |
-
#: includes/class-freemius.php:17893
|
529 |
-
msgid "Site successfully opted in."
|
530 |
-
msgstr "Site successfully opted in."
|
531 |
-
|
532 |
-
#: includes/class-freemius.php17894, includes/class-freemius.php:18671
|
533 |
-
msgid "Awesome"
|
534 |
-
msgstr "Sejt"
|
535 |
-
|
536 |
-
#: includes/class-freemius.php17910, templates/forms/optout.php:32
|
537 |
-
msgid "We appreciate your help in making the %s better by letting us track some usage data."
|
538 |
-
msgstr "We appreciate your help in making the %s better by letting us track some usage data."
|
539 |
-
|
540 |
-
#: includes/class-freemius.php:17911
|
541 |
-
msgid "Thank you!"
|
542 |
-
msgstr "Thank you!"
|
543 |
-
|
544 |
-
#: includes/class-freemius.php:17918
|
545 |
-
msgid "We will no longer be sending any usage data of %s on %s to %s."
|
546 |
-
msgstr "We will no longer be sending any usage data of %s on %s to %s."
|
547 |
-
|
548 |
-
#: includes/class-freemius.php:18033
|
549 |
-
msgid "Please check your mailbox, you should receive an email via %s to confirm the ownership change. From security reasons, you must confirm the change within the next 15 min. If you cannot find the email, please check your spam folder."
|
550 |
-
msgstr "Please check your mailbox, you should receive an email via %s to confirm the ownership change. From security reasons, you must confirm the change within the next 15 min. If you cannot find the email, please check your spam folder."
|
551 |
-
|
552 |
-
#: includes/class-freemius.php:18039
|
553 |
-
msgid "Thanks for confirming the ownership change. An email was just sent to %s for final approval."
|
554 |
-
msgstr "Thanks for confirming the ownership change. An email was just sent to %s for final approval."
|
555 |
-
|
556 |
-
#: includes/class-freemius.php:18044
|
557 |
-
msgid "%s is the new owner of the account."
|
558 |
-
msgstr "%s er den nye ejer af kontoen."
|
559 |
-
|
560 |
-
#: includes/class-freemius.php:18046
|
561 |
-
msgctxt "as congratulations"
|
562 |
-
msgid "Congrats"
|
563 |
-
msgstr "Tillykke"
|
564 |
-
|
565 |
-
#: includes/class-freemius.php:18066
|
566 |
-
msgid "Sorry, we could not complete the email update. Another user with the same email is already registered."
|
567 |
-
msgstr "Sorry, we could not complete the email update. Another user with the same email is already registered."
|
568 |
-
|
569 |
-
#: includes/class-freemius.php:18067
|
570 |
-
msgid "If you would like to give up the ownership of the %s's account to %s click the Change Ownership button."
|
571 |
-
msgstr "If you would like to give up the ownership of the %s's account to %s click the Change Ownership button."
|
572 |
-
|
573 |
-
#: includes/class-freemius.php:18074
|
574 |
-
msgid "Change Ownership"
|
575 |
-
msgstr "Skift ejerskab"
|
576 |
-
|
577 |
-
#: includes/class-freemius.php:18082
|
578 |
-
msgid "Your email was successfully updated. You should receive an email with confirmation instructions in few moments."
|
579 |
-
msgstr "Your email was successfully updated. You should receive an email with confirmation instructions in few moments."
|
580 |
-
|
581 |
-
#: includes/class-freemius.php:18094
|
582 |
-
msgid "Please provide your full name."
|
583 |
-
msgstr "Indtast venligst dit fulde navn."
|
584 |
-
|
585 |
-
#: includes/class-freemius.php:18099
|
586 |
-
msgid "Your name was successfully updated."
|
587 |
-
msgstr "Dit navn er blevet opdateret."
|
588 |
-
|
589 |
-
#: includes/class-freemius.php:18160
|
590 |
-
msgid "You have successfully updated your %s."
|
591 |
-
msgstr "Opdatering af %s blev gennemført."
|
592 |
-
|
593 |
-
#: includes/class-freemius.php:18300
|
594 |
-
msgid "Just letting you know that the add-ons information of %s is being pulled from an external server."
|
595 |
-
msgstr "Just letting you know that the add-ons information of %s is being pulled from an external server."
|
596 |
-
|
597 |
-
#: includes/class-freemius.php:18301
|
598 |
-
msgctxt "advance notice of something that will need attention."
|
599 |
-
msgid "Heads up"
|
600 |
-
msgstr "Se her"
|
601 |
-
|
602 |
-
#: includes/class-freemius.php:18711
|
603 |
-
msgctxt "exclamation"
|
604 |
-
msgid "Hey"
|
605 |
-
msgstr "Hey"
|
606 |
-
|
607 |
-
#: includes/class-freemius.php:18711
|
608 |
-
msgid "How do you like %s so far? Test all our %s premium features with a %d-day free trial."
|
609 |
-
msgstr "How do you like %s so far? Test all our %s premium features with a %d-day free trial."
|
610 |
-
|
611 |
-
#: includes/class-freemius.php:18719
|
612 |
-
msgid "No commitment for %s days - cancel anytime!"
|
613 |
-
msgstr "Ingen bindinger i %s dage - annuller når som helst!"
|
614 |
-
|
615 |
-
#: includes/class-freemius.php:18720
|
616 |
-
msgid "No credit card required"
|
617 |
-
msgstr "Betalingskort ikke påkrævet"
|
618 |
-
|
619 |
-
#: includes/class-freemius.php18727, templates/forms/trial-start.php:53
|
620 |
-
msgctxt "call to action"
|
621 |
-
msgid "Start free trial"
|
622 |
-
msgstr "Start gratis prøveperiode"
|
623 |
-
|
624 |
-
#: includes/class-freemius.php:18804
|
625 |
-
msgid "Hey there, did you know that %s has an affiliate program? If you like the %s you can become our ambassador and earn some cash!"
|
626 |
-
msgstr "Hey there, did you know that %s has an affiliate program? If you like the %s you can become our ambassador and earn some cash!"
|
627 |
-
|
628 |
-
#: includes/class-freemius.php:18813
|
629 |
-
msgid "Learn more"
|
630 |
-
msgstr "Læs mere"
|
631 |
-
|
632 |
-
#: includes/class-freemius.php18963, templates/account.php394,
|
633 |
-
#: templates/account.php497, templates/connect.php169,
|
634 |
-
#: templates/connect.php408, templates/forms/license-activation.php24,
|
635 |
-
#: templates/account/partials/addon.php:230
|
636 |
-
msgid "Activate License"
|
637 |
-
msgstr "Aktiver licens"
|
638 |
-
|
639 |
-
#: includes/class-freemius.php18964, templates/account.php457,
|
640 |
-
#: templates/account.php496, templates/account/partials/site.php:256
|
641 |
-
msgid "Change License"
|
642 |
-
msgstr "Skift licens"
|
643 |
-
|
644 |
-
#: includes/class-freemius.php19046, templates/account/partials/site.php:161
|
645 |
-
msgid "Opt Out"
|
646 |
-
msgstr "Frameld"
|
647 |
-
|
648 |
-
#: includes/class-freemius.php19048, includes/class-freemius.php19053,
|
649 |
-
#: templates/account/partials/site.php43,
|
650 |
-
#: templates/account/partials/site.php:161
|
651 |
-
msgid "Opt In"
|
652 |
-
msgstr "Tilmeld"
|
653 |
-
|
654 |
-
#: includes/class-freemius.php:19245
|
655 |
-
msgid "Please follow these steps to complete the upgrade"
|
656 |
-
msgstr "Følg venligst disse trin for at færdiggøre opgraderingen"
|
657 |
-
|
658 |
-
#: includes/class-freemius.php:19249
|
659 |
-
msgid "Download the latest %s version"
|
660 |
-
msgstr "Download den seneste version af %s"
|
661 |
-
|
662 |
-
#: includes/class-freemius.php:19253
|
663 |
-
msgid "Upload and activate the downloaded version"
|
664 |
-
msgstr "Upload og aktiver den downloadede version"
|
665 |
-
|
666 |
-
#: includes/class-freemius.php:19255
|
667 |
-
msgid "How to upload and activate?"
|
668 |
-
msgstr "Upload og aktivering, hvordan?"
|
669 |
-
|
670 |
-
#: includes/class-freemius.php:19384
|
671 |
-
msgid "%sClick here%s to choose the sites where you'd like to activate the license on."
|
672 |
-
msgstr "%sClick here%s to choose the sites where you'd like to activate the license on."
|
673 |
-
|
674 |
-
#: includes/class-freemius.php:19545
|
675 |
-
msgid "Auto installation only works for opted-in users."
|
676 |
-
msgstr "Auto installation only works for opted-in users."
|
677 |
-
|
678 |
-
#: includes/class-freemius.php19555, includes/class-freemius.php19588,
|
679 |
-
#: includes/class-fs-plugin-updater.php713,
|
680 |
-
#: includes/class-fs-plugin-updater.php:727
|
681 |
-
msgid "Invalid module ID."
|
682 |
-
msgstr "Ugyldigt modul-ID."
|
683 |
-
|
684 |
-
#: includes/class-freemius.php19564, includes/class-fs-plugin-updater.php:747
|
685 |
-
msgid "Premium version already active."
|
686 |
-
msgstr "Premium version allerede aktiv."
|
687 |
-
|
688 |
-
#: includes/class-freemius.php:19571
|
689 |
-
msgid "You do not have a valid license to access the premium version."
|
690 |
-
msgstr "Du har ikke en gyldig licens til at benytte premium-versionen."
|
691 |
-
|
692 |
-
#: includes/class-freemius.php:19578
|
693 |
-
msgid "Plugin is a \"Serviceware\" which means it does not have a premium code version."
|
694 |
-
msgstr "Plugin is a \"Serviceware\" which means it does not have a premium code version."
|
695 |
-
|
696 |
-
#: includes/class-freemius.php19596, includes/class-fs-plugin-updater.php:746
|
697 |
-
msgid "Premium add-on version already installed."
|
698 |
-
msgstr "Premium tilføjelse er allerede installeret."
|
699 |
-
|
700 |
-
#: includes/class-freemius.php:19941
|
701 |
-
msgid "View paid features"
|
702 |
-
msgstr "Vis betalte features"
|
703 |
-
|
704 |
-
#: includes/class-freemius.php:20251
|
705 |
-
msgid "Thank you so much for using %s and its add-ons!"
|
706 |
-
msgstr "Thank you so much for using %s and its add-ons!"
|
707 |
-
|
708 |
-
#: includes/class-freemius.php:20252
|
709 |
-
msgid "Thank you so much for using %s!"
|
710 |
-
msgstr "Thank you so much for using %s!"
|
711 |
-
|
712 |
-
#: includes/class-freemius.php:20258
|
713 |
-
msgid "You've already opted-in to our usage-tracking, which helps us keep improving the %s."
|
714 |
-
msgstr "You've already opted-in to our usage-tracking, which helps us keep improving the %s."
|
715 |
-
|
716 |
-
#: includes/class-freemius.php:20262
|
717 |
-
msgid "Thank you so much for using our products!"
|
718 |
-
msgstr "Thank you so much for using our products!"
|
719 |
-
|
720 |
-
#: includes/class-freemius.php:20263
|
721 |
-
msgid "You've already opted-in to our usage-tracking, which helps us keep improving them."
|
722 |
-
msgstr "You've already opted-in to our usage-tracking, which helps us keep improving them."
|
723 |
-
|
724 |
-
#: includes/class-freemius.php:20282
|
725 |
-
msgid "%s and its add-ons"
|
726 |
-
msgstr "%s and its add-ons"
|
727 |
-
|
728 |
-
#: includes/class-freemius.php:20291
|
729 |
-
msgid "Products"
|
730 |
-
msgstr "Products"
|
731 |
-
|
732 |
-
#: includes/class-freemius.php20298, templates/connect.php:259
|
733 |
-
msgid "Yes"
|
734 |
-
msgstr "Yes"
|
735 |
-
|
736 |
-
#: includes/class-freemius.php20299, templates/connect.php:260
|
737 |
-
msgid "send me security & feature updates, educational content and offers."
|
738 |
-
msgstr "send me security & feature updates, educational content and offers."
|
739 |
-
|
740 |
-
#: includes/class-freemius.php20300, templates/connect.php:265
|
741 |
-
msgid "No"
|
742 |
-
msgstr "No"
|
743 |
-
|
744 |
-
#: includes/class-freemius.php20302, templates/connect.php:267
|
745 |
-
msgid "do %sNOT%s send me security & feature updates, educational content and offers."
|
746 |
-
msgstr "do %sNOT%s send me security & feature updates, educational content and offers."
|
747 |
-
|
748 |
-
#: includes/class-freemius.php:20312
|
749 |
-
msgid "Due to the new %sEU General Data Protection Regulation (GDPR)%s compliance requirements it is required that you provide your explicit consent, again, confirming that you are onboard 🙂"
|
750 |
-
msgstr "Due to the new %sEU General Data Protection Regulation (GDPR)%s compliance requirements it is required that you provide your explicit consent, again, confirming that you are onboard 🙂"
|
751 |
-
|
752 |
-
#: includes/class-freemius.php20314, templates/connect.php:274
|
753 |
-
msgid "Please let us know if you'd like us to contact you for security & feature updates, educational content, and occasional offers:"
|
754 |
-
msgstr "Please let us know if you'd like us to contact you for security & feature updates, educational content, and occasional offers:"
|
755 |
-
|
756 |
-
#: includes/class-freemius.php:20598
|
757 |
-
msgid "License key is empty."
|
758 |
-
msgstr "License key is empty."
|
759 |
-
|
760 |
-
#: includes/class-fs-plugin-updater.php184,
|
761 |
-
#: includes/class-fs-plugin-updater.php:219
|
762 |
-
msgid "%sRenew your license now%s to access version %s security & feature updates, and support."
|
763 |
-
msgstr "%sRenew your license now%s to access version %s security & feature updates, and support."
|
764 |
-
|
765 |
-
#: includes/class-fs-plugin-updater.php:776
|
766 |
-
msgid "Installing plugin: %s"
|
767 |
-
msgstr "Installerer plugin: %s"
|
768 |
-
|
769 |
-
#: includes/class-fs-plugin-updater.php:817
|
770 |
-
msgid "Unable to connect to the filesystem. Please confirm your credentials."
|
771 |
-
msgstr "Unable to connect to the filesystem. Please confirm your credentials."
|
772 |
-
|
773 |
-
#: includes/class-fs-plugin-updater.php:923
|
774 |
-
msgid "The remote plugin package does not contain a folder with the desired slug and renaming did not work."
|
775 |
-
msgstr "The remote plugin package does not contain a folder with the desired slug and renaming did not work."
|
776 |
-
|
777 |
-
#: includes/fs-plugin-info-dialog.php336,
|
778 |
-
#: templates/account/partials/addon.php:287
|
779 |
-
msgctxt "verb"
|
780 |
-
msgid "Purchase"
|
781 |
-
msgstr "Køb"
|
782 |
-
|
783 |
-
#: includes/fs-plugin-info-dialog.php:339
|
784 |
-
msgid "Start my free %s"
|
785 |
-
msgstr "Start min gratis %s"
|
786 |
-
|
787 |
-
#: includes/fs-plugin-info-dialog.php:380
|
788 |
-
msgid "Install Free Version Now"
|
789 |
-
msgstr "Install Free Version Now"
|
790 |
-
|
791 |
-
#: includes/fs-plugin-info-dialog.php381, templates/auto-installation.php111,
|
792 |
-
#: templates/account/partials/addon.php267,
|
793 |
-
#: templates/account/partials/addon.php:317
|
794 |
-
msgid "Install Now"
|
795 |
-
msgstr "Installer nu"
|
796 |
-
|
797 |
-
#: includes/fs-plugin-info-dialog.php:392
|
798 |
-
msgctxt "as download latest version"
|
799 |
-
msgid "Download Latest Free Version"
|
800 |
-
msgstr "Download Latest Free Version"
|
801 |
-
|
802 |
-
#: includes/fs-plugin-info-dialog.php393, templates/account.php80,
|
803 |
-
#: templates/account/partials/addon.php:21
|
804 |
-
msgctxt "as download latest version"
|
805 |
-
msgid "Download Latest"
|
806 |
-
msgstr "Download seneste"
|
807 |
-
|
808 |
-
#: includes/fs-plugin-info-dialog.php:403
|
809 |
-
msgid "Install Free Version Update Now"
|
810 |
-
msgstr "Install Free Version Update Now"
|
811 |
-
|
812 |
-
#: includes/fs-plugin-info-dialog.php404, templates/account.php:448
|
813 |
-
msgid "Install Update Now"
|
814 |
-
msgstr "Installer opdatering nu"
|
815 |
-
|
816 |
-
#: includes/fs-plugin-info-dialog.php:415
|
817 |
-
msgid "Newer Free Version (%s) Installed"
|
818 |
-
msgstr "Newer Free Version (%s) Installed"
|
819 |
-
|
820 |
-
#: includes/fs-plugin-info-dialog.php:416
|
821 |
-
msgid "Newer Version (%s) Installed"
|
822 |
-
msgstr "Nyere version (%s) installeret"
|
823 |
-
|
824 |
-
#: includes/fs-plugin-info-dialog.php:424
|
825 |
-
msgid "Latest Free Version Installed"
|
826 |
-
msgstr "Latest Free Version Installed"
|
827 |
-
|
828 |
-
#: includes/fs-plugin-info-dialog.php:425
|
829 |
-
msgid "Latest Version Installed"
|
830 |
-
msgstr "Seneste version installeret"
|
831 |
-
|
832 |
-
#: includes/fs-plugin-info-dialog.php:580
|
833 |
-
msgctxt "Plugin installer section title"
|
834 |
-
msgid "Description"
|
835 |
-
msgstr "Beskrivelse"
|
836 |
-
|
837 |
-
#: includes/fs-plugin-info-dialog.php:581
|
838 |
-
msgctxt "Plugin installer section title"
|
839 |
-
msgid "Installation"
|
840 |
-
msgstr "Installering"
|
841 |
-
|
842 |
-
#: includes/fs-plugin-info-dialog.php:582
|
843 |
-
msgctxt "Plugin installer section title"
|
844 |
-
msgid "FAQ"
|
845 |
-
msgstr "FAQ"
|
846 |
-
|
847 |
-
#: includes/fs-plugin-info-dialog.php583,
|
848 |
-
#: templates/plugin-info/description.php:55
|
849 |
-
msgid "Screenshots"
|
850 |
-
msgstr "Skærmbilleder"
|
851 |
-
|
852 |
-
#: includes/fs-plugin-info-dialog.php:584
|
853 |
-
msgctxt "Plugin installer section title"
|
854 |
-
msgid "Changelog"
|
855 |
-
msgstr "Ændringslog"
|
856 |
-
|
857 |
-
#: includes/fs-plugin-info-dialog.php:585
|
858 |
-
msgctxt "Plugin installer section title"
|
859 |
-
msgid "Reviews"
|
860 |
-
msgstr "Anmeldelser"
|
861 |
-
|
862 |
-
#: includes/fs-plugin-info-dialog.php:586
|
863 |
-
msgctxt "Plugin installer section title"
|
864 |
-
msgid "Other Notes"
|
865 |
-
msgstr "Andre noter"
|
866 |
-
|
867 |
-
#: includes/fs-plugin-info-dialog.php:601
|
868 |
-
msgctxt "Plugin installer section title"
|
869 |
-
msgid "Features & Pricing"
|
870 |
-
msgstr "Funktioner og priser"
|
871 |
-
|
872 |
-
#: includes/fs-plugin-info-dialog.php:611
|
873 |
-
msgid "Plugin Install"
|
874 |
-
msgstr "Plugin-installering"
|
875 |
-
|
876 |
-
#: includes/fs-plugin-info-dialog.php:683
|
877 |
-
msgctxt "e.g. Professional Plan"
|
878 |
-
msgid "%s Plan"
|
879 |
-
msgstr "%s Plan"
|
880 |
-
|
881 |
-
#: includes/fs-plugin-info-dialog.php:709
|
882 |
-
msgctxt "e.g. the best product"
|
883 |
-
msgid "Best"
|
884 |
-
msgstr "Bedste"
|
885 |
-
|
886 |
-
#: includes/fs-plugin-info-dialog.php715,
|
887 |
-
#: includes/fs-plugin-info-dialog.php:735
|
888 |
-
msgctxt "as every month"
|
889 |
-
msgid "Monthly"
|
890 |
-
msgstr "Månedligt"
|
891 |
-
|
892 |
-
#: includes/fs-plugin-info-dialog.php:718
|
893 |
-
msgctxt "as once a year"
|
894 |
-
msgid "Annual"
|
895 |
-
msgstr "Årligt"
|
896 |
-
|
897 |
-
#: includes/fs-plugin-info-dialog.php:721
|
898 |
-
msgid "Lifetime"
|
899 |
-
msgstr "Livstid"
|
900 |
-
|
901 |
-
#: includes/fs-plugin-info-dialog.php735,
|
902 |
-
#: includes/fs-plugin-info-dialog.php737,
|
903 |
-
#: includes/fs-plugin-info-dialog.php:739
|
904 |
-
msgctxt "e.g. billed monthly"
|
905 |
-
msgid "Billed %s"
|
906 |
-
msgstr "Faktureret %s"
|
907 |
-
|
908 |
-
#: includes/fs-plugin-info-dialog.php:737
|
909 |
-
msgctxt "as once a year"
|
910 |
-
msgid "Annually"
|
911 |
-
msgstr "Årligt"
|
912 |
-
|
913 |
-
#: includes/fs-plugin-info-dialog.php:739
|
914 |
-
msgctxt "as once a year"
|
915 |
-
msgid "Once"
|
916 |
-
msgstr "Engangsbeløb"
|
917 |
-
|
918 |
-
#: includes/fs-plugin-info-dialog.php:745
|
919 |
-
msgid "Single Site License"
|
920 |
-
msgstr "Single Site License"
|
921 |
-
|
922 |
-
#: includes/fs-plugin-info-dialog.php:747
|
923 |
-
msgid "Unlimited Licenses"
|
924 |
-
msgstr "Ubegrænsede licenser"
|
925 |
-
|
926 |
-
#: includes/fs-plugin-info-dialog.php:749
|
927 |
-
msgid "Up to %s Sites"
|
928 |
-
msgstr "Op til %s websteder"
|
929 |
-
|
930 |
-
#: includes/fs-plugin-info-dialog.php759,
|
931 |
-
#: templates/plugin-info/features.php:82
|
932 |
-
msgctxt "as monthly period"
|
933 |
-
msgid "mo"
|
934 |
-
msgstr "md"
|
935 |
-
|
936 |
-
#: includes/fs-plugin-info-dialog.php766,
|
937 |
-
#: templates/plugin-info/features.php:80
|
938 |
-
msgctxt "as annual period"
|
939 |
-
msgid "year"
|
940 |
-
msgstr "år"
|
941 |
-
|
942 |
-
#: includes/fs-plugin-info-dialog.php:820
|
943 |
-
msgctxt "noun"
|
944 |
-
msgid "Price"
|
945 |
-
msgstr "Pris"
|
946 |
-
|
947 |
-
#: includes/fs-plugin-info-dialog.php:868
|
948 |
-
msgid "Save %s"
|
949 |
-
msgstr "Spar %s"
|
950 |
-
|
951 |
-
#: includes/fs-plugin-info-dialog.php:878
|
952 |
-
msgid "No commitment for %s - cancel anytime"
|
953 |
-
msgstr "Ingen bindinger ved %s - annuller når som helst"
|
954 |
-
|
955 |
-
#: includes/fs-plugin-info-dialog.php:881
|
956 |
-
msgid "After your free %s, pay as little as %s"
|
957 |
-
msgstr "Efter din gratis %s er prisen kun %s"
|
958 |
-
|
959 |
-
#: includes/fs-plugin-info-dialog.php:892
|
960 |
-
msgid "Details"
|
961 |
-
msgstr "Detaljer"
|
962 |
-
|
963 |
-
#: includes/fs-plugin-info-dialog.php896, templates/account.php87,
|
964 |
-
#: templates/debug.php191, templates/debug.php228, templates/debug.php442,
|
965 |
-
#: templates/account/partials/addon.php:28
|
966 |
-
msgctxt "product version"
|
967 |
-
msgid "Version"
|
968 |
-
msgstr "Version"
|
969 |
-
|
970 |
-
#: includes/fs-plugin-info-dialog.php:903
|
971 |
-
msgctxt "as the plugin author"
|
972 |
-
msgid "Author"
|
973 |
-
msgstr "Forfatter"
|
974 |
-
|
975 |
-
#: includes/fs-plugin-info-dialog.php:910
|
976 |
-
msgid "Last Updated"
|
977 |
-
msgstr "Senest opdateret"
|
978 |
-
|
979 |
-
#: includes/fs-plugin-info-dialog.php:915
|
980 |
-
msgctxt "x-ago"
|
981 |
-
msgid "%s ago"
|
982 |
-
msgstr "%s siden"
|
983 |
-
|
984 |
-
#: includes/fs-plugin-info-dialog.php:924
|
985 |
-
msgid "Requires WordPress Version"
|
986 |
-
msgstr "Kræver WordPress-version"
|
987 |
-
|
988 |
-
#: includes/fs-plugin-info-dialog.php:925
|
989 |
-
msgid "%s or higher"
|
990 |
-
msgstr "%s eller højere"
|
991 |
-
|
992 |
-
#: includes/fs-plugin-info-dialog.php:932
|
993 |
-
msgid "Compatible up to"
|
994 |
-
msgstr "Kompatibel op til"
|
995 |
-
|
996 |
-
#: includes/fs-plugin-info-dialog.php:940
|
997 |
-
msgid "Downloaded"
|
998 |
-
msgstr "Downloadet"
|
999 |
-
|
1000 |
-
#: includes/fs-plugin-info-dialog.php:944
|
1001 |
-
msgid "%s time"
|
1002 |
-
msgstr "%s gang"
|
1003 |
-
|
1004 |
-
#: includes/fs-plugin-info-dialog.php:946
|
1005 |
-
msgid "%s times"
|
1006 |
-
msgstr "%s gange"
|
1007 |
-
|
1008 |
-
#: includes/fs-plugin-info-dialog.php:956
|
1009 |
-
msgid "WordPress.org Plugin Page"
|
1010 |
-
msgstr "WordPress.org Plugin-side"
|
1011 |
-
|
1012 |
-
#: includes/fs-plugin-info-dialog.php:964
|
1013 |
-
msgid "Plugin Homepage"
|
1014 |
-
msgstr "Plugin-websted"
|
1015 |
-
|
1016 |
-
#: includes/fs-plugin-info-dialog.php972,
|
1017 |
-
#: includes/fs-plugin-info-dialog.php:1054
|
1018 |
-
msgid "Donate to this plugin"
|
1019 |
-
msgstr "Donér til dette plugin"
|
1020 |
-
|
1021 |
-
#: includes/fs-plugin-info-dialog.php:979
|
1022 |
-
msgid "Average Rating"
|
1023 |
-
msgstr "Gennemsnitlig vurdering"
|
1024 |
-
|
1025 |
-
#: includes/fs-plugin-info-dialog.php:986
|
1026 |
-
msgid "based on %s"
|
1027 |
-
msgstr "baseret på %s"
|
1028 |
-
|
1029 |
-
#: includes/fs-plugin-info-dialog.php:990
|
1030 |
-
msgid "%s rating"
|
1031 |
-
msgstr "%s vurdering"
|
1032 |
-
|
1033 |
-
#: includes/fs-plugin-info-dialog.php:992
|
1034 |
-
msgid "%s ratings"
|
1035 |
-
msgstr "%s vurderinger"
|
1036 |
-
|
1037 |
-
#: includes/fs-plugin-info-dialog.php:1007
|
1038 |
-
msgid "%s star"
|
1039 |
-
msgstr "%s stjerne"
|
1040 |
-
|
1041 |
-
#: includes/fs-plugin-info-dialog.php:1009
|
1042 |
-
msgid "%s stars"
|
1043 |
-
msgstr "%s stjerner"
|
1044 |
-
|
1045 |
-
#: includes/fs-plugin-info-dialog.php:1020
|
1046 |
-
msgid "Click to see reviews that provided a rating of %s"
|
1047 |
-
msgstr "Click to see reviews that provided a rating of %s"
|
1048 |
-
|
1049 |
-
#: includes/fs-plugin-info-dialog.php:1033
|
1050 |
-
msgid "Contributors"
|
1051 |
-
msgstr "Bidragsydere"
|
1052 |
-
|
1053 |
-
#: includes/fs-plugin-info-dialog.php1062,
|
1054 |
-
#: includes/fs-plugin-info-dialog.php:1064
|
1055 |
-
msgid "Warning"
|
1056 |
-
msgstr "Advarsel"
|
1057 |
-
|
1058 |
-
#: includes/fs-plugin-info-dialog.php:1062
|
1059 |
-
msgid "This plugin has not been tested with your current version of WordPress."
|
1060 |
-
msgstr "Dette plugin er ikke blevet testet med din nuværende version af WordPress."
|
1061 |
-
|
1062 |
-
#: includes/fs-plugin-info-dialog.php:1064
|
1063 |
-
msgid "This plugin has not been marked as compatible with your version of WordPress."
|
1064 |
-
msgstr "This plugin has not been marked as compatible with your version of WordPress."
|
1065 |
-
|
1066 |
-
#: includes/fs-plugin-info-dialog.php:1083
|
1067 |
-
msgid "Paid add-on must be deployed to Freemius."
|
1068 |
-
msgstr "Paid add-on must be deployed to Freemius."
|
1069 |
-
|
1070 |
-
#: includes/fs-plugin-info-dialog.php:1084
|
1071 |
-
msgid "Add-on must be deployed to WordPress.org or Freemius."
|
1072 |
-
msgstr "Add-on must be deployed to WordPress.org or Freemius."
|
1073 |
-
|
1074 |
-
#: templates/account.php81, templates/account/partials/addon.php22,
|
1075 |
-
#: templates/account/partials/site.php:295
|
1076 |
-
msgid "Downgrading your plan will immediately stop all future recurring payments and your %s plan license will expire in %s."
|
1077 |
-
msgstr "Downgrading your plan will immediately stop all future recurring payments and your %s plan license will expire in %s."
|
1078 |
-
|
1079 |
-
#: templates/account.php82, templates/account/partials/addon.php:23
|
1080 |
-
msgid "Cancelling the trial will immediately block access to all premium features. Are you sure?"
|
1081 |
-
msgstr "Cancelling the trial will immediately block access to all premium features. Are you sure?"
|
1082 |
-
|
1083 |
-
#: templates/account.php83, templates/account/partials/addon.php24,
|
1084 |
-
#: templates/account/partials/site.php:296
|
1085 |
-
msgid "You can still enjoy all %s features but you will not have access to %s updates and support."
|
1086 |
-
msgstr "You can still enjoy all %s features but you will not have access to %s updates and support."
|
1087 |
-
|
1088 |
-
#: templates/account.php84, templates/account/partials/addon.php25,
|
1089 |
-
#: templates/account/partials/site.php:297
|
1090 |
-
msgid "Once your license expires you can still use the Free version but you will NOT have access to the %s features."
|
1091 |
-
msgstr "Once your license expires you can still use the Free version but you will NOT have access to the %s features."
|
1092 |
-
|
1093 |
-
#. translators: %s: Plan title (e.g. "Professional")
|
1094 |
-
#: templates/account.php86,
|
1095 |
-
#: templates/account/partials/activate-license-button.php31,
|
1096 |
-
#: templates/account/partials/addon.php:27
|
1097 |
-
msgid "Activate %s Plan"
|
1098 |
-
msgstr "Aktiver %s plan"
|
1099 |
-
|
1100 |
-
#. translators: %s: Time period (e.g. Auto renews in "2 months")
|
1101 |
-
#: templates/account.php89, templates/account/partials/addon.php30,
|
1102 |
-
#: templates/account/partials/site.php:275
|
1103 |
-
msgid "Auto renews in %s"
|
1104 |
-
msgstr "Auto-fornyer om %s"
|
1105 |
-
|
1106 |
-
#. translators: %s: Time period (e.g. Expires in "2 months")
|
1107 |
-
#: templates/account.php91, templates/account/partials/addon.php32,
|
1108 |
-
#: templates/account/partials/site.php:277
|
1109 |
-
msgid "Expires in %s"
|
1110 |
-
msgstr "Udløber om %s"
|
1111 |
-
|
1112 |
-
#: templates/account.php92, templates/account/partials/addon.php:33
|
1113 |
-
msgctxt "as synchronize license"
|
1114 |
-
msgid "Sync License"
|
1115 |
-
msgstr "Synkroniser licens"
|
1116 |
-
|
1117 |
-
#: templates/account.php93, templates/account/partials/addon.php:34
|
1118 |
-
msgid "Cancel Trial"
|
1119 |
-
msgstr "Annuller prøveperiode"
|
1120 |
-
|
1121 |
-
#: templates/account.php94, templates/account/partials/addon.php:35
|
1122 |
-
msgid "Change Plan"
|
1123 |
-
msgstr "Skift plan"
|
1124 |
-
|
1125 |
-
#: templates/account.php95, templates/account/partials/addon.php:36
|
1126 |
-
msgctxt "verb"
|
1127 |
-
msgid "Upgrade"
|
1128 |
-
msgstr "Opgrader"
|
1129 |
-
|
1130 |
-
#: templates/account.php97, templates/account/partials/addon.php38,
|
1131 |
-
#: templates/account/partials/site.php:298
|
1132 |
-
msgctxt "verb"
|
1133 |
-
msgid "Downgrade"
|
1134 |
-
msgstr "Nedgrader"
|
1135 |
-
|
1136 |
-
#: templates/account.php99, templates/add-ons.php126,
|
1137 |
-
#: templates/plugin-info/features.php72,
|
1138 |
-
#: templates/account/partials/addon.php40,
|
1139 |
-
#: templates/account/partials/site.php:31
|
1140 |
-
msgid "Free"
|
1141 |
-
msgstr "Gratis"
|
1142 |
-
|
1143 |
-
#: templates/account.php100, templates/account/partials/addon.php:41
|
1144 |
-
msgid "Activate"
|
1145 |
-
msgstr "Aktiver"
|
1146 |
-
|
1147 |
-
#: templates/account.php101, templates/debug.php361,
|
1148 |
-
#: includes/customizer/class-fs-customizer-upsell-control.php106,
|
1149 |
-
#: templates/account/partials/addon.php:42
|
1150 |
-
msgctxt "as product pricing plan"
|
1151 |
-
msgid "Plan"
|
1152 |
-
msgstr "Plan"
|
1153 |
-
|
1154 |
-
#: templates/account.php:154
|
1155 |
-
msgid "Free Trial"
|
1156 |
-
msgstr "Gratis prøveperiode"
|
1157 |
-
|
1158 |
-
#: templates/account.php:165
|
1159 |
-
msgid "Account Details"
|
1160 |
-
msgstr "Kontodetaljer"
|
1161 |
-
|
1162 |
-
#: templates/account.php:175
|
1163 |
-
msgid "Deleting the account will automatically deactivate your %s plan license so you can use it on other sites. If you want to terminate the recurring payments as well, click the \"Cancel\" button, and first \"Downgrade\" your account. Are you sure you would like to continue with the deletion?"
|
1164 |
-
msgstr "Deleting the account will automatically deactivate your %s plan license so you can use it on other sites. If you want to terminate the recurring payments as well, click the \"Cancel\" button, and first \"Downgrade\" your account. Are you sure you would like to continue with the deletion?"
|
1165 |
-
|
1166 |
-
#: templates/account.php:177
|
1167 |
-
msgid "Deletion is not temporary. Only delete if you no longer want to use this %s anymore. Are you sure you would like to continue with the deletion?"
|
1168 |
-
msgstr "Deletion is not temporary. Only delete if you no longer want to use this %s anymore. Are you sure you would like to continue with the deletion?"
|
1169 |
-
|
1170 |
-
#: templates/account.php:180
|
1171 |
-
msgid "Delete Account"
|
1172 |
-
msgstr "Slet konto"
|
1173 |
-
|
1174 |
-
#: templates/account.php192, templates/account/partials/addon.php155,
|
1175 |
-
#: templates/account/partials/deactivate-license-button.php:35
|
1176 |
-
msgid "Deactivate License"
|
1177 |
-
msgstr "Deaktiver licens"
|
1178 |
-
|
1179 |
-
#: templates/account.php:210
|
1180 |
-
msgid "Are you sure you want to proceed?"
|
1181 |
-
msgstr "Er du sikker på, du vil fortsætte?"
|
1182 |
-
|
1183 |
-
#: templates/account.php210, templates/account/partials/addon.php:177
|
1184 |
-
msgid "Cancel Subscription"
|
1185 |
-
msgstr "Annuller abonnement"
|
1186 |
-
|
1187 |
-
#: templates/account.php:239
|
1188 |
-
msgctxt "as synchronize"
|
1189 |
-
msgid "Sync"
|
1190 |
-
msgstr "Synkroniser"
|
1191 |
-
|
1192 |
-
#: templates/account.php253, templates/debug.php:477
|
1193 |
-
msgid "Name"
|
1194 |
-
msgstr "Navn"
|
1195 |
-
|
1196 |
-
#: templates/account.php259, templates/debug.php:478
|
1197 |
-
msgid "Email"
|
1198 |
-
msgstr "E-mail"
|
1199 |
-
|
1200 |
-
#: templates/account.php266, templates/debug.php360, templates/debug.php:516
|
1201 |
-
msgid "User ID"
|
1202 |
-
msgstr "Bruger-ID"
|
1203 |
-
|
1204 |
-
#: templates/account.php:274
|
1205 |
-
msgid "Site ID"
|
1206 |
-
msgstr "Websteds-ID"
|
1207 |
-
|
1208 |
-
#: templates/account.php:277
|
1209 |
-
msgid "No ID"
|
1210 |
-
msgstr "Intet ID"
|
1211 |
-
|
1212 |
-
#: templates/account.php282, templates/debug.php233, templates/debug.php362,
|
1213 |
-
#: templates/debug.php443, templates/debug.php480,
|
1214 |
-
#: templates/account/partials/site.php:219
|
1215 |
-
msgid "Public Key"
|
1216 |
-
msgstr "Offentlig nøgle"
|
1217 |
-
|
1218 |
-
#: templates/account.php288, templates/debug.php363, templates/debug.php444,
|
1219 |
-
#: templates/debug.php481, templates/account/partials/site.php:231
|
1220 |
-
msgid "Secret Key"
|
1221 |
-
msgstr "Privat nøgle"
|
1222 |
-
|
1223 |
-
#: templates/account.php:291
|
1224 |
-
msgctxt "as secret encryption key missing"
|
1225 |
-
msgid "No Secret"
|
1226 |
-
msgstr "Ingen privat nøgle"
|
1227 |
-
|
1228 |
-
#: templates/account.php310, templates/account/partials/site.php112,
|
1229 |
-
#: templates/account/partials/site.php:114
|
1230 |
-
msgid "Trial"
|
1231 |
-
msgstr "Prøveperiode"
|
1232 |
-
|
1233 |
-
#: templates/account.php329, templates/debug.php521,
|
1234 |
-
#: templates/account/partials/site.php:248
|
1235 |
-
msgid "License Key"
|
1236 |
-
msgstr "Licensnøgle"
|
1237 |
-
|
1238 |
-
#: templates/account.php:359
|
1239 |
-
msgid "not verified"
|
1240 |
-
msgstr "ikke verificeret"
|
1241 |
-
|
1242 |
-
#: templates/account.php:416
|
1243 |
-
msgid "Premium version"
|
1244 |
-
msgstr "Premium version"
|
1245 |
-
|
1246 |
-
#: templates/account.php:418
|
1247 |
-
msgid "Free version"
|
1248 |
-
msgstr "Gratis version"
|
1249 |
-
|
1250 |
-
#: templates/account.php:430
|
1251 |
-
msgid "Verify Email"
|
1252 |
-
msgstr "Verificer e-mail"
|
1253 |
-
|
1254 |
-
#: templates/account.php:441
|
1255 |
-
msgid "Download %s Version"
|
1256 |
-
msgstr "Download 1%s version"
|
1257 |
-
|
1258 |
-
#: templates/account.php455, templates/account.php636,
|
1259 |
-
#: templates/account/partials/site.php237,
|
1260 |
-
#: templates/account/partials/site.php:255
|
1261 |
-
msgctxt "verb"
|
1262 |
-
msgid "Show"
|
1263 |
-
msgstr "Vis"
|
1264 |
-
|
1265 |
-
#: templates/account.php:469
|
1266 |
-
msgid "What is your %s?"
|
1267 |
-
msgstr "Angiv venligst %s?"
|
1268 |
-
|
1269 |
-
#: templates/account.php477, templates/account/billing.php:27
|
1270 |
-
msgctxt "verb"
|
1271 |
-
msgid "Edit"
|
1272 |
-
msgstr "Rediger"
|
1273 |
-
|
1274 |
-
#: templates/account.php:490
|
1275 |
-
msgid "Sites"
|
1276 |
-
msgstr "Websteder"
|
1277 |
-
|
1278 |
-
#: templates/account.php:501
|
1279 |
-
msgid "Search by address"
|
1280 |
-
msgstr "Search by address"
|
1281 |
-
|
1282 |
-
#: templates/account.php510, templates/account.php558, templates/debug.php226,
|
1283 |
-
#: templates/debug.php354, templates/debug.php439, templates/debug.php476,
|
1284 |
-
#: templates/debug.php514, templates/debug.php587,
|
1285 |
-
#: templates/account/payments.php35, templates/debug/logger.php:21
|
1286 |
-
msgid "ID"
|
1287 |
-
msgstr "ID"
|
1288 |
-
|
1289 |
-
#: templates/account.php511, templates/debug.php:357
|
1290 |
-
msgid "Address"
|
1291 |
-
msgstr "Address"
|
1292 |
-
|
1293 |
-
#: templates/account.php:512
|
1294 |
-
msgid "License"
|
1295 |
-
msgstr "Licens"
|
1296 |
-
|
1297 |
-
#: templates/account.php:513
|
1298 |
-
msgid "Plan"
|
1299 |
-
msgstr "Plan"
|
1300 |
-
|
1301 |
-
#: templates/account.php:561
|
1302 |
-
msgctxt "as software license"
|
1303 |
-
msgid "License"
|
1304 |
-
msgstr "Licens"
|
1305 |
-
|
1306 |
-
#: templates/account.php:630
|
1307 |
-
msgctxt "verb"
|
1308 |
-
msgid "Hide"
|
1309 |
-
msgstr "Skjul"
|
1310 |
-
|
1311 |
-
#: templates/account.php:665
|
1312 |
-
msgid "Deactivating your license will block all premium features, but will enable activating the license on another site. Are you sure you want to proceed?"
|
1313 |
-
msgstr "Deactivating your license will block all premium features, but will enable activating the license on another site. Are you sure you want to proceed?"
|
1314 |
-
|
1315 |
-
#: templates/add-ons.php:36
|
1316 |
-
msgid "Add Ons for %s"
|
1317 |
-
msgstr "Tilføjelser til %s"
|
1318 |
-
|
1319 |
-
#: templates/add-ons.php:44
|
1320 |
-
msgid "We could'nt load the add-ons list. It's probably an issue on our side, please try to come back in few minutes."
|
1321 |
-
msgstr "We could'nt load the add-ons list. It's probably an issue on our side, please try to come back in few minutes."
|
1322 |
-
|
1323 |
-
#: templates/add-ons.php:135
|
1324 |
-
msgid "View details"
|
1325 |
-
msgstr "Vis detaljer"
|
1326 |
-
|
1327 |
-
#: templates/admin-notice.php13, templates/forms/license-activation.php208,
|
1328 |
-
#: templates/forms/resend-key.php:77
|
1329 |
-
msgctxt "as close a window"
|
1330 |
-
msgid "Dismiss"
|
1331 |
-
msgstr "Fjern"
|
1332 |
-
|
1333 |
-
#: templates/auto-installation.php:45
|
1334 |
-
msgid "%s sec"
|
1335 |
-
msgstr "1%s sek"
|
1336 |
-
|
1337 |
-
#: templates/auto-installation.php:83
|
1338 |
-
msgid "Automatic Installation"
|
1339 |
-
msgstr "Automatisk installering"
|
1340 |
-
|
1341 |
-
#: templates/auto-installation.php:93
|
1342 |
-
msgid "An automated download and installation of %s (paid version) from %s will start in %s. If you would like to do it manually - click the cancellation button now."
|
1343 |
-
msgstr "An automated download and installation of %s (paid version) from %s will start in %s. If you would like to do it manually - click the cancellation button now."
|
1344 |
-
|
1345 |
-
#: templates/auto-installation.php:104
|
1346 |
-
msgid "The installation process has started and may take a few minutes to complete. Please wait until it is done - do not refresh this page."
|
1347 |
-
msgstr "The installation process has started and may take a few minutes to complete. Please wait until it is done - do not refresh this page."
|
1348 |
-
|
1349 |
-
#: templates/auto-installation.php:109
|
1350 |
-
msgid "Cancel Installation"
|
1351 |
-
msgstr "Annuller installering"
|
1352 |
-
|
1353 |
-
#: templates/checkout.php:172
|
1354 |
-
msgid "Checkout"
|
1355 |
-
msgstr "Udtjekning"
|
1356 |
-
|
1357 |
-
#: templates/checkout.php:172
|
1358 |
-
msgid "PCI compliant"
|
1359 |
-
msgstr "PCI compliant"
|
1360 |
-
|
1361 |
-
#. translators: %s: name (e.g. Hey John,)
|
1362 |
-
#: templates/connect.php:110
|
1363 |
-
msgctxt "greeting"
|
1364 |
-
msgid "Hey %s,"
|
1365 |
-
msgstr "Hey %s,"
|
1366 |
-
|
1367 |
-
#: templates/connect.php:152
|
1368 |
-
msgid "Allow & Continue"
|
1369 |
-
msgstr "Tillad & Fortsæt"
|
1370 |
-
|
1371 |
-
#: templates/connect.php:156
|
1372 |
-
msgid "Re-send activation email"
|
1373 |
-
msgstr "Gensend e-mail om aktivering"
|
1374 |
-
|
1375 |
-
#: templates/connect.php:160
|
1376 |
-
msgid "Thanks %s!"
|
1377 |
-
msgstr "Tak %s!"
|
1378 |
-
|
1379 |
-
#: templates/connect.php170, templates/forms/license-activation.php:43
|
1380 |
-
msgid "Agree & Activate License"
|
1381 |
-
msgstr "Accepter & aktiver licens"
|
1382 |
-
|
1383 |
-
#: templates/connect.php:179
|
1384 |
-
msgid "Thanks for purchasing %s! To get started, please enter your license key:"
|
1385 |
-
msgstr "Tak for at købe %s! For at komme i gang, venligst indtast din licensnøgle:"
|
1386 |
-
|
1387 |
-
#: templates/connect.php:186
|
1388 |
-
msgid "Never miss an important update - opt in to our security & feature updates notifications, educational content, offers, and non-sensitive diagnostic tracking with %4$s."
|
1389 |
-
msgstr "Never miss an important update - opt in to our security & feature updates notifications, educational content, offers, and non-sensitive diagnostic tracking with %4$s."
|
1390 |
-
|
1391 |
-
#: templates/connect.php:187
|
1392 |
-
msgid "Never miss an important update - opt in to our security and feature updates notifications, and non-sensitive diagnostic tracking with %4$s."
|
1393 |
-
msgstr "Never miss an important update - opt in to our security and feature updates notifications, and non-sensitive diagnostic tracking with %4$s."
|
1394 |
-
|
1395 |
-
#: templates/connect.php:193
|
1396 |
-
msgid "Never miss an important update - opt in to our security & feature updates notifications, educational content, offers, and non-sensitive diagnostic tracking with %4$s. If you skip this, that's okay! %1$s will still work just fine."
|
1397 |
-
msgstr "Never miss an important update - opt in to our security & feature updates notifications, educational content, offers, and non-sensitive diagnostic tracking with %4$s. If you skip this, that's okay! %1$s will still work just fine."
|
1398 |
-
|
1399 |
-
#: templates/connect.php:194
|
1400 |
-
msgid "Never miss an important update - opt in to our security & feature updates notifications, and non-sensitive diagnostic tracking with %4$s. If you skip this, that's okay! %1$s will still work just fine."
|
1401 |
-
msgstr "Never miss an important update - opt in to our security & feature updates notifications, and non-sensitive diagnostic tracking with %4$s. If you skip this, that's okay! %1$s will still work just fine."
|
1402 |
-
|
1403 |
-
#: templates/connect.php:228
|
1404 |
-
msgid "We're excited to introduce the Freemius network-level integration."
|
1405 |
-
msgstr "We're excited to introduce the Freemius network-level integration."
|
1406 |
-
|
1407 |
-
#: templates/connect.php:231
|
1408 |
-
msgid "During the update process we detected %d site(s) that are still pending license activation."
|
1409 |
-
msgstr "During the update process we detected %d site(s) that are still pending license activation."
|
1410 |
-
|
1411 |
-
#: templates/connect.php:233
|
1412 |
-
msgid "If you'd like to use the %s on those sites, please enter your license key below and click the activation button."
|
1413 |
-
msgstr "If you'd like to use the %s on those sites, please enter your license key below and click the activation button."
|
1414 |
-
|
1415 |
-
#: templates/connect.php:235
|
1416 |
-
msgid "%s's paid features"
|
1417 |
-
msgstr "%s's paid features"
|
1418 |
-
|
1419 |
-
#: templates/connect.php:240
|
1420 |
-
msgid "Alternatively, you can skip it for now and activate the license later, in your %s's network-level Account page."
|
1421 |
-
msgstr "Alternatively, you can skip it for now and activate the license later, in your %s's network-level Account page."
|
1422 |
-
|
1423 |
-
#: templates/connect.php:242
|
1424 |
-
msgid "During the update process we detected %s site(s) in the network that are still pending your attention."
|
1425 |
-
msgstr "During the update process we detected %s site(s) in the network that are still pending your attention."
|
1426 |
-
|
1427 |
-
#: templates/connect.php251, templates/forms/license-activation.php:46
|
1428 |
-
msgid "License key"
|
1429 |
-
msgstr "Licensnøgle"
|
1430 |
-
|
1431 |
-
#: templates/connect.php254, templates/forms/license-activation.php:19
|
1432 |
-
msgid "Can't find your license key?"
|
1433 |
-
msgstr "Kan du ikke finde din licensnøgle?"
|
1434 |
-
|
1435 |
-
#: templates/connect.php302, templates/connect.php617,
|
1436 |
-
#: templates/forms/deactivation/retry-skip.php:20
|
1437 |
-
msgctxt "verb"
|
1438 |
-
msgid "Skip"
|
1439 |
-
msgstr "Spring over"
|
1440 |
-
|
1441 |
-
#: templates/connect.php:305
|
1442 |
-
msgid "Delegate to Site Admins"
|
1443 |
-
msgstr "Delegate to Site Admins"
|
1444 |
-
|
1445 |
-
#: templates/connect.php:305
|
1446 |
-
msgid "If you click it, this decision will be delegated to the sites administrators."
|
1447 |
-
msgstr "If you click it, this decision will be delegated to the sites administrators."
|
1448 |
-
|
1449 |
-
#: templates/connect.php:333
|
1450 |
-
msgid "Your Profile Overview"
|
1451 |
-
msgstr "Overblik af din profil"
|
1452 |
-
|
1453 |
-
#: templates/connect.php:334
|
1454 |
-
msgid "Name and email address"
|
1455 |
-
msgstr "Navn og e-mailadresse"
|
1456 |
-
|
1457 |
-
#: templates/connect.php:339
|
1458 |
-
msgid "Your Site Overview"
|
1459 |
-
msgstr "Overblik af dit websted"
|
1460 |
-
|
1461 |
-
#: templates/connect.php:340
|
1462 |
-
msgid "Site URL, WP version, PHP info, plugins & themes"
|
1463 |
-
msgstr "Websteds-URL, WP version, PHP info, plugins og temaer"
|
1464 |
-
|
1465 |
-
#: templates/connect.php:345
|
1466 |
-
msgid "Admin Notices"
|
1467 |
-
msgstr "Admin-meddelelser"
|
1468 |
-
|
1469 |
-
#: templates/connect.php346, templates/connect.php:362
|
1470 |
-
msgid "Updates, announcements, marketing, no spam"
|
1471 |
-
msgstr "Updates, announcements, marketing, no spam"
|
1472 |
-
|
1473 |
-
#: templates/connect.php:351
|
1474 |
-
msgid "Current %s Events"
|
1475 |
-
msgstr "Current %s Events"
|
1476 |
-
|
1477 |
-
#: templates/connect.php:352
|
1478 |
-
msgid "Activation, deactivation and uninstall"
|
1479 |
-
msgstr "Aktivering, deaktivering og afinstallering"
|
1480 |
-
|
1481 |
-
#: templates/connect.php:361
|
1482 |
-
msgid "Newsletter"
|
1483 |
-
msgstr "Nyhedsbrev"
|
1484 |
-
|
1485 |
-
#: templates/connect.php378, templates/forms/license-activation.php:38
|
1486 |
-
msgid "The %1$s will be periodically sending data to %2$s to check for security and feature updates, and verify the validity of your license."
|
1487 |
-
msgstr "The %1$s will be periodically sending data to %2$s to check for security and feature updates, and verify the validity of your license."
|
1488 |
-
|
1489 |
-
#: templates/connect.php:383
|
1490 |
-
msgid "What permissions are being granted?"
|
1491 |
-
msgstr "Hvilke tilladelser bliver givet?"
|
1492 |
-
|
1493 |
-
#: templates/connect.php:404
|
1494 |
-
msgid "Don't have a license key?"
|
1495 |
-
msgstr "Har du ikke en licensnøgle?"
|
1496 |
-
|
1497 |
-
#: templates/connect.php:405
|
1498 |
-
msgid "Activate Free Version"
|
1499 |
-
msgstr "Aktiver gratis version"
|
1500 |
-
|
1501 |
-
#: templates/connect.php:407
|
1502 |
-
msgid "Have a license key?"
|
1503 |
-
msgstr "Har du en licensnøgle?"
|
1504 |
-
|
1505 |
-
#: templates/connect.php:415
|
1506 |
-
msgid "Privacy Policy"
|
1507 |
-
msgstr "Privatlivspolitik"
|
1508 |
-
|
1509 |
-
#: templates/connect.php:417
|
1510 |
-
msgid "Terms of Service"
|
1511 |
-
msgstr "Servicevilkår"
|
1512 |
-
|
1513 |
-
#: templates/connect.php:750
|
1514 |
-
msgctxt "as in the process of sending an email"
|
1515 |
-
msgid "Sending email"
|
1516 |
-
msgstr "Sender e-mail"
|
1517 |
-
|
1518 |
-
#: templates/connect.php:751
|
1519 |
-
msgctxt "as activating plugin"
|
1520 |
-
msgid "Activating"
|
1521 |
-
msgstr "Aktiverer"
|
1522 |
-
|
1523 |
-
#: templates/contact.php:78
|
1524 |
-
msgid "Contact"
|
1525 |
-
msgstr "Kontakt"
|
1526 |
-
|
1527 |
-
#: templates/debug.php:17
|
1528 |
-
msgctxt "as turned off"
|
1529 |
-
msgid "Off"
|
1530 |
-
msgstr "Fra"
|
1531 |
-
|
1532 |
-
#: templates/debug.php:18
|
1533 |
-
msgctxt "as turned on"
|
1534 |
-
msgid "On"
|
1535 |
-
msgstr "Til"
|
1536 |
-
|
1537 |
-
#: templates/debug.php:20
|
1538 |
-
msgid "SDK"
|
1539 |
-
msgstr "SDK"
|
1540 |
-
|
1541 |
-
#: templates/debug.php:24
|
1542 |
-
msgctxt "as code debugging"
|
1543 |
-
msgid "Debugging"
|
1544 |
-
msgstr "Fejlfinding"
|
1545 |
-
|
1546 |
-
#: templates/debug.php54, templates/debug.php238, templates/debug.php364,
|
1547 |
-
#: templates/debug.php:482
|
1548 |
-
msgid "Actions"
|
1549 |
-
msgstr "Handlinger"
|
1550 |
-
|
1551 |
-
#: templates/debug.php:64
|
1552 |
-
msgid "Are you sure you want to delete all Freemius data?"
|
1553 |
-
msgstr "Er du sikker på, du vil slette al Freemius data?"
|
1554 |
-
|
1555 |
-
#: templates/debug.php:64
|
1556 |
-
msgid "Delete All Accounts"
|
1557 |
-
msgstr "Slet alle konti"
|
1558 |
-
|
1559 |
-
#: templates/debug.php:71
|
1560 |
-
msgid "Clear API Cache"
|
1561 |
-
msgstr "Ryd API-cache"
|
1562 |
-
|
1563 |
-
#: templates/debug.php:79
|
1564 |
-
msgid "Clear Updates Transients"
|
1565 |
-
msgstr "Clear Updates Transients"
|
1566 |
-
|
1567 |
-
#: templates/debug.php:86
|
1568 |
-
msgid "Sync Data From Server"
|
1569 |
-
msgstr "Synkroniser data fra server"
|
1570 |
-
|
1571 |
-
#: templates/debug.php:90
|
1572 |
-
msgid "Load DB Option"
|
1573 |
-
msgstr "Hent DB-indstilling"
|
1574 |
-
|
1575 |
-
#: templates/debug.php:93
|
1576 |
-
msgid "Set DB Option"
|
1577 |
-
msgstr "Sæt DB-indstilling"
|
1578 |
-
|
1579 |
-
#: templates/debug.php:170
|
1580 |
-
msgid "Key"
|
1581 |
-
msgstr "Nøgle"
|
1582 |
-
|
1583 |
-
#: templates/debug.php:171
|
1584 |
-
msgid "Value"
|
1585 |
-
msgstr "Værdi"
|
1586 |
-
|
1587 |
-
#: templates/debug.php:187
|
1588 |
-
msgctxt "as software development kit versions"
|
1589 |
-
msgid "SDK Versions"
|
1590 |
-
msgstr "SDK-versioner"
|
1591 |
-
|
1592 |
-
#: templates/debug.php:192
|
1593 |
-
msgid "SDK Path"
|
1594 |
-
msgstr "SDK-sti"
|
1595 |
-
|
1596 |
-
#: templates/debug.php193, templates/debug.php:232
|
1597 |
-
msgid "Module Path"
|
1598 |
-
msgstr "Modul-sti"
|
1599 |
-
|
1600 |
-
#: templates/debug.php:194
|
1601 |
-
msgid "Is Active"
|
1602 |
-
msgstr "Er aktiv"
|
1603 |
-
|
1604 |
-
#: templates/debug.php222, templates/debug/plugins-themes-sync.php:35
|
1605 |
-
msgid "Plugins"
|
1606 |
-
msgstr "Plugins"
|
1607 |
-
|
1608 |
-
#: templates/debug.php222, templates/debug/plugins-themes-sync.php:56
|
1609 |
-
msgid "Themes"
|
1610 |
-
msgstr "Temaer"
|
1611 |
-
|
1612 |
-
#: templates/debug.php227, templates/debug.php359, templates/debug.php441,
|
1613 |
-
#: templates/debug/scheduled-crons.php:80
|
1614 |
-
msgid "Slug"
|
1615 |
-
msgstr "Kortnavn"
|
1616 |
-
|
1617 |
-
#: templates/debug.php229, templates/debug.php:440
|
1618 |
-
msgid "Title"
|
1619 |
-
msgstr "Titel"
|
1620 |
-
|
1621 |
-
#: templates/debug.php:230
|
1622 |
-
msgctxt "as application program interface"
|
1623 |
-
msgid "API"
|
1624 |
-
msgstr "API"
|
1625 |
-
|
1626 |
-
#: templates/debug.php:231
|
1627 |
-
msgid "Freemius State"
|
1628 |
-
msgstr "Freemius tilstand"
|
1629 |
-
|
1630 |
-
#: templates/debug.php:235
|
1631 |
-
msgid "Network Blog"
|
1632 |
-
msgstr "Network Blog"
|
1633 |
-
|
1634 |
-
#: templates/debug.php:236
|
1635 |
-
msgid "Network User"
|
1636 |
-
msgstr "Network User"
|
1637 |
-
|
1638 |
-
#: templates/debug.php:273
|
1639 |
-
msgctxt "as connection was successful"
|
1640 |
-
msgid "Connected"
|
1641 |
-
msgstr "Forbundet"
|
1642 |
-
|
1643 |
-
#: templates/debug.php:274
|
1644 |
-
msgctxt "as connection blocked"
|
1645 |
-
msgid "Blocked"
|
1646 |
-
msgstr "Blokeret"
|
1647 |
-
|
1648 |
-
#: templates/debug.php:310
|
1649 |
-
msgid "Simulate Trial"
|
1650 |
-
msgstr "Simuler prøveperiode"
|
1651 |
-
|
1652 |
-
#: templates/debug.php:322
|
1653 |
-
msgid "Simulate Network Upgrade"
|
1654 |
-
msgstr "Simulate Network Upgrade"
|
1655 |
-
|
1656 |
-
#: templates/debug.php:348
|
1657 |
-
msgid "%s Installs"
|
1658 |
-
msgstr "%s installeringer"
|
1659 |
-
|
1660 |
-
#: templates/debug.php:350
|
1661 |
-
msgctxt "like websites"
|
1662 |
-
msgid "Sites"
|
1663 |
-
msgstr "Websteder"
|
1664 |
-
|
1665 |
-
#: templates/debug.php356, templates/account/partials/site.php:148
|
1666 |
-
msgid "Blog ID"
|
1667 |
-
msgstr "Blog ID"
|
1668 |
-
|
1669 |
-
#: templates/debug.php421, templates/debug.php499,
|
1670 |
-
#: templates/account/partials/addon.php:334
|
1671 |
-
msgctxt "verb"
|
1672 |
-
msgid "Delete"
|
1673 |
-
msgstr "Slet"
|
1674 |
-
|
1675 |
-
#: templates/debug.php:435
|
1676 |
-
msgid "Add Ons of module %s"
|
1677 |
-
msgstr "Tilføjelser til modul %s"
|
1678 |
-
|
1679 |
-
#: templates/debug.php:472
|
1680 |
-
msgid "Users"
|
1681 |
-
msgstr "Brugere"
|
1682 |
-
|
1683 |
-
#: templates/debug.php:479
|
1684 |
-
msgid "Verified"
|
1685 |
-
msgstr "Verificeret"
|
1686 |
-
|
1687 |
-
#: templates/debug.php:510
|
1688 |
-
msgid "%s Licenses"
|
1689 |
-
msgstr "1%s licenser"
|
1690 |
-
|
1691 |
-
#: templates/debug.php:515
|
1692 |
-
msgid "Plugin ID"
|
1693 |
-
msgstr "Plugin-ID"
|
1694 |
-
|
1695 |
-
#: templates/debug.php:517
|
1696 |
-
msgid "Plan ID"
|
1697 |
-
msgstr "Plan-ID"
|
1698 |
-
|
1699 |
-
#: templates/debug.php:518
|
1700 |
-
msgid "Quota"
|
1701 |
-
msgstr "Kvote"
|
1702 |
-
|
1703 |
-
#: templates/debug.php:519
|
1704 |
-
msgid "Activated"
|
1705 |
-
msgstr "Aktiveret"
|
1706 |
-
|
1707 |
-
#: templates/debug.php:520
|
1708 |
-
msgid "Blocking"
|
1709 |
-
msgstr "Blokerer"
|
1710 |
-
|
1711 |
-
#: templates/debug.php:522
|
1712 |
-
msgctxt "as expiration date"
|
1713 |
-
msgid "Expiration"
|
1714 |
-
msgstr "Udløber"
|
1715 |
-
|
1716 |
-
#: templates/debug.php:545
|
1717 |
-
msgid "Debug Log"
|
1718 |
-
msgstr "Fejlfindingslog"
|
1719 |
-
|
1720 |
-
#: templates/debug.php:549
|
1721 |
-
msgid "All Types"
|
1722 |
-
msgstr "Alle typer"
|
1723 |
-
|
1724 |
-
#: templates/debug.php:556
|
1725 |
-
msgid "All Requests"
|
1726 |
-
msgstr "Alle forespørgsler"
|
1727 |
-
|
1728 |
-
#: templates/debug.php561, templates/debug.php590,
|
1729 |
-
#: templates/debug/logger.php:25
|
1730 |
-
msgid "File"
|
1731 |
-
msgstr "Fil"
|
1732 |
-
|
1733 |
-
#: templates/debug.php562, templates/debug.php588,
|
1734 |
-
#: templates/debug/logger.php:23
|
1735 |
-
msgid "Function"
|
1736 |
-
msgstr "Funktion"
|
1737 |
-
|
1738 |
-
#: templates/debug.php:563
|
1739 |
-
msgid "Process ID"
|
1740 |
-
msgstr "Proces-ID"
|
1741 |
-
|
1742 |
-
#: templates/debug.php:564
|
1743 |
-
msgid "Logger"
|
1744 |
-
msgstr "Logger"
|
1745 |
-
|
1746 |
-
#: templates/debug.php565, templates/debug.php589,
|
1747 |
-
#: templates/debug/logger.php:24
|
1748 |
-
msgid "Message"
|
1749 |
-
msgstr "Besked"
|
1750 |
-
|
1751 |
-
#: templates/debug.php:567
|
1752 |
-
msgid "Filter"
|
1753 |
-
msgstr "Filter"
|
1754 |
-
|
1755 |
-
#: templates/debug.php:575
|
1756 |
-
msgid "Download"
|
1757 |
-
msgstr "Download"
|
1758 |
-
|
1759 |
-
#: templates/debug.php586, templates/debug/logger.php:22
|
1760 |
-
msgid "Type"
|
1761 |
-
msgstr "Type"
|
1762 |
-
|
1763 |
-
#: templates/debug.php591, templates/debug/logger.php:26
|
1764 |
-
msgid "Timestamp"
|
1765 |
-
msgstr "Timestamp"
|
1766 |
-
|
1767 |
-
#: templates/secure-https-header.php:28
|
1768 |
-
msgid "Secure HTTPS %s page, running from an external domain"
|
1769 |
-
msgstr "Secure HTTPS %s page, running from an external domain"
|
1770 |
-
|
1771 |
-
#: includes/customizer/class-fs-customizer-support-section.php55,
|
1772 |
-
#: templates/plugin-info/features.php:43
|
1773 |
-
msgid "Support"
|
1774 |
-
msgstr "Support"
|
1775 |
-
|
1776 |
-
#: includes/debug/class-fs-debug-bar-panel.php48,
|
1777 |
-
#: templates/debug/api-calls.php54, templates/debug/logger.php:62
|
1778 |
-
msgctxt "milliseconds"
|
1779 |
-
msgid "ms"
|
1780 |
-
msgstr "ms"
|
1781 |
-
|
1782 |
-
#: includes/debug/debug-bar-start.php:41
|
1783 |
-
msgid "Freemius API"
|
1784 |
-
msgstr "Freemius API"
|
1785 |
-
|
1786 |
-
#: includes/debug/debug-bar-start.php:42
|
1787 |
-
msgid "Requests"
|
1788 |
-
msgstr "Requests"
|
1789 |
-
|
1790 |
-
#: templates/account/billing.php:28
|
1791 |
-
msgctxt "verb"
|
1792 |
-
msgid "Update"
|
1793 |
-
msgstr "Opdater"
|
1794 |
-
|
1795 |
-
#: templates/account/billing.php:39
|
1796 |
-
msgid "Billing"
|
1797 |
-
msgstr "Betaling"
|
1798 |
-
|
1799 |
-
#: templates/account/billing.php44, templates/account/billing.php:44
|
1800 |
-
msgid "Business name"
|
1801 |
-
msgstr "Firmanavn"
|
1802 |
-
|
1803 |
-
#: templates/account/billing.php45, templates/account/billing.php:45
|
1804 |
-
msgid "Tax / VAT ID"
|
1805 |
-
msgstr "Moms / VAT ID"
|
1806 |
-
|
1807 |
-
#: templates/account/billing.php48, templates/account/billing.php48,
|
1808 |
-
#: templates/account/billing.php49, templates/account/billing.php:49
|
1809 |
-
msgid "Address Line %d"
|
1810 |
-
msgstr "Adresselinje %d"
|
1811 |
-
|
1812 |
-
#: templates/account/billing.php52, templates/account/billing.php:52
|
1813 |
-
msgid "City"
|
1814 |
-
msgstr "By"
|
1815 |
-
|
1816 |
-
#: templates/account/billing.php52, templates/account/billing.php:52
|
1817 |
-
msgid "Town"
|
1818 |
-
msgstr "By"
|
1819 |
-
|
1820 |
-
#: templates/account/billing.php53, templates/account/billing.php:53
|
1821 |
-
msgid "ZIP / Postal Code"
|
1822 |
-
msgstr "ZIP / Postnummer"
|
1823 |
-
|
1824 |
-
#: templates/account/billing.php:308
|
1825 |
-
msgid "Country"
|
1826 |
-
msgstr "Land"
|
1827 |
-
|
1828 |
-
#: templates/account/billing.php:310
|
1829 |
-
msgid "Select Country"
|
1830 |
-
msgstr "Vælg land"
|
1831 |
-
|
1832 |
-
#: templates/account/billing.php317, templates/account/billing.php:318
|
1833 |
-
msgid "State"
|
1834 |
-
msgstr "Stat"
|
1835 |
-
|
1836 |
-
#: templates/account/billing.php317, templates/account/billing.php:318
|
1837 |
-
msgid "Province"
|
1838 |
-
msgstr "Provins"
|
1839 |
-
|
1840 |
-
#: templates/account/payments.php:29
|
1841 |
-
msgid "Payments"
|
1842 |
-
msgstr "Betalinger"
|
1843 |
-
|
1844 |
-
#: templates/account/payments.php:36
|
1845 |
-
msgid "Date"
|
1846 |
-
msgstr "Dato"
|
1847 |
-
|
1848 |
-
#: templates/account/payments.php:37
|
1849 |
-
msgid "Amount"
|
1850 |
-
msgstr "Beløb"
|
1851 |
-
|
1852 |
-
#: templates/account/payments.php38, templates/account/payments.php:50
|
1853 |
-
msgid "Invoice"
|
1854 |
-
msgstr "Faktura"
|
1855 |
-
|
1856 |
-
#: templates/debug/api-calls.php:56
|
1857 |
-
msgid "API"
|
1858 |
-
msgstr "API"
|
1859 |
-
|
1860 |
-
#: templates/debug/api-calls.php:68
|
1861 |
-
msgid "Method"
|
1862 |
-
msgstr "Metode"
|
1863 |
-
|
1864 |
-
#: templates/debug/api-calls.php:69
|
1865 |
-
msgid "Code"
|
1866 |
-
msgstr "Kode"
|
1867 |
-
|
1868 |
-
#: templates/debug/api-calls.php:70
|
1869 |
-
msgid "Length"
|
1870 |
-
msgstr "Længde"
|
1871 |
-
|
1872 |
-
#: templates/debug/api-calls.php:71
|
1873 |
-
msgctxt "as file/folder path"
|
1874 |
-
msgid "Path"
|
1875 |
-
msgstr "Sti"
|
1876 |
-
|
1877 |
-
#: templates/debug/api-calls.php:73
|
1878 |
-
msgid "Body"
|
1879 |
-
msgstr "Body"
|
1880 |
-
|
1881 |
-
#: templates/debug/api-calls.php:75
|
1882 |
-
msgid "Result"
|
1883 |
-
msgstr "Resultat"
|
1884 |
-
|
1885 |
-
#: templates/debug/api-calls.php:76
|
1886 |
-
msgid "Start"
|
1887 |
-
msgstr "Start"
|
1888 |
-
|
1889 |
-
#: templates/debug/api-calls.php:77
|
1890 |
-
msgid "End"
|
1891 |
-
msgstr "Slut"
|
1892 |
-
|
1893 |
-
#: templates/debug/logger.php:15
|
1894 |
-
msgid "Log"
|
1895 |
-
msgstr "Log"
|
1896 |
-
|
1897 |
-
#. translators: %s: time period (e.g. In "2 hours")
|
1898 |
-
#: templates/debug/plugins-themes-sync.php18,
|
1899 |
-
#: templates/debug/scheduled-crons.php:91
|
1900 |
-
msgid "In %s"
|
1901 |
-
msgstr "Om %s"
|
1902 |
-
|
1903 |
-
#. translators: %s: time period (e.g. "2 hours" ago)
|
1904 |
-
#: templates/debug/plugins-themes-sync.php20,
|
1905 |
-
#: templates/debug/scheduled-crons.php:93
|
1906 |
-
msgid "%s ago"
|
1907 |
-
msgstr "%s siden"
|
1908 |
-
|
1909 |
-
#: templates/debug/plugins-themes-sync.php21,
|
1910 |
-
#: templates/debug/scheduled-crons.php:74
|
1911 |
-
msgctxt "seconds"
|
1912 |
-
msgid "sec"
|
1913 |
-
msgstr "sek"
|
1914 |
-
|
1915 |
-
#: templates/debug/plugins-themes-sync.php:23
|
1916 |
-
msgid "Plugins & Themes Sync"
|
1917 |
-
msgstr "Synkronisering af plugins og temaer"
|
1918 |
-
|
1919 |
-
#: templates/debug/plugins-themes-sync.php:28
|
1920 |
-
msgid "Total"
|
1921 |
-
msgstr "Total"
|
1922 |
-
|
1923 |
-
#: templates/debug/plugins-themes-sync.php29,
|
1924 |
-
#: templates/debug/scheduled-crons.php:84
|
1925 |
-
msgid "Last"
|
1926 |
-
msgstr "Sidste"
|
1927 |
-
|
1928 |
-
#: templates/debug/scheduled-crons.php:76
|
1929 |
-
msgid "Scheduled Crons"
|
1930 |
-
msgstr "Planlagte cron jobs"
|
1931 |
-
|
1932 |
-
#: templates/debug/scheduled-crons.php:81
|
1933 |
-
msgid "Module"
|
1934 |
-
msgstr "Modul"
|
1935 |
-
|
1936 |
-
#: templates/debug/scheduled-crons.php:82
|
1937 |
-
msgid "Module Type"
|
1938 |
-
msgstr "Modultype"
|
1939 |
-
|
1940 |
-
#: templates/debug/scheduled-crons.php:83
|
1941 |
-
msgid "Cron Type"
|
1942 |
-
msgstr "Cron Type"
|
1943 |
-
|
1944 |
-
#: templates/debug/scheduled-crons.php:85
|
1945 |
-
msgid "Next"
|
1946 |
-
msgstr "Næste"
|
1947 |
-
|
1948 |
-
#: templates/forms/affiliation.php:82
|
1949 |
-
msgid "Non-expiring"
|
1950 |
-
msgstr "Udløber ikke"
|
1951 |
-
|
1952 |
-
#: templates/forms/affiliation.php:85
|
1953 |
-
msgid "Apply to become an affiliate"
|
1954 |
-
msgstr "Apply to become an affiliate"
|
1955 |
-
|
1956 |
-
#: templates/forms/affiliation.php:104
|
1957 |
-
msgid "Your affiliate application for %s has been accepted! Log in to your affiliate area at: %s."
|
1958 |
-
msgstr "Your affiliate application for %s has been accepted! Log in to your affiliate area at: %s."
|
1959 |
-
|
1960 |
-
#: templates/forms/affiliation.php:119
|
1961 |
-
msgid "Thank you for applying for our affiliate program, we'll review your details during the next 14 days and will get back to you with further information."
|
1962 |
-
msgstr "Thank you for applying for our affiliate program, we'll review your details during the next 14 days and will get back to you with further information."
|
1963 |
-
|
1964 |
-
#: templates/forms/affiliation.php:122
|
1965 |
-
msgid "Your affiliation account was temporarily suspended."
|
1966 |
-
msgstr "Your affiliation account was temporarily suspended."
|
1967 |
-
|
1968 |
-
#: templates/forms/affiliation.php:125
|
1969 |
-
msgid "Thank you for applying for our affiliate program, unfortunately, we've decided at this point to reject your application. Please try again in 30 days."
|
1970 |
-
msgstr "Thank you for applying for our affiliate program, unfortunately, we've decided at this point to reject your application. Please try again in 30 days."
|
1971 |
-
|
1972 |
-
#: templates/forms/affiliation.php:128
|
1973 |
-
msgid "Due to violation of our affiliation terms, we decided to temporarily block your affiliation account. If you have any questions, please contact support."
|
1974 |
-
msgstr "Due to violation of our affiliation terms, we decided to temporarily block your affiliation account. If you have any questions, please contact support."
|
1975 |
-
|
1976 |
-
#: templates/forms/affiliation.php:141
|
1977 |
-
msgid "Like the %s? Become our ambassador and earn cash ;-)"
|
1978 |
-
msgstr "Like the %s? Become our ambassador and earn cash ;-)"
|
1979 |
-
|
1980 |
-
#: templates/forms/affiliation.php:142
|
1981 |
-
msgid "Refer new customers to our %s and earn %s commission on each successful sale you refer!"
|
1982 |
-
msgstr "Refer new customers to our %s and earn %s commission on each successful sale you refer!"
|
1983 |
-
|
1984 |
-
#: templates/forms/affiliation.php:145
|
1985 |
-
msgid "Program Summary"
|
1986 |
-
msgstr "Program Summary"
|
1987 |
-
|
1988 |
-
#: templates/forms/affiliation.php:147
|
1989 |
-
msgid "%s commission when a customer purchases a new license."
|
1990 |
-
msgstr "%s commission when a customer purchases a new license."
|
1991 |
-
|
1992 |
-
#: templates/forms/affiliation.php:149
|
1993 |
-
msgid "Get commission for automated subscription renewals."
|
1994 |
-
msgstr "Get commission for automated subscription renewals."
|
1995 |
-
|
1996 |
-
#: templates/forms/affiliation.php:152
|
1997 |
-
msgid "%s tracking cookie after the first visit to maximize earnings potential."
|
1998 |
-
msgstr "%s tracking cookie after the first visit to maximize earnings potential."
|
1999 |
-
|
2000 |
-
#: templates/forms/affiliation.php:155
|
2001 |
-
msgid "Unlimited commissions."
|
2002 |
-
msgstr "Unlimited commissions."
|
2003 |
-
|
2004 |
-
#: templates/forms/affiliation.php:157
|
2005 |
-
msgid "%s minimum payout amount."
|
2006 |
-
msgstr "%s minimum payout amount."
|
2007 |
-
|
2008 |
-
#: templates/forms/affiliation.php:158
|
2009 |
-
msgid "Payouts are in USD and processed monthly via PayPal."
|
2010 |
-
msgstr "Payouts are in USD and processed monthly via PayPal."
|
2011 |
-
|
2012 |
-
#: templates/forms/affiliation.php:159
|
2013 |
-
msgid "As we reserve 30 days for potential refunds, we only pay commissions that are older than 30 days."
|
2014 |
-
msgstr "As we reserve 30 days for potential refunds, we only pay commissions that are older than 30 days."
|
2015 |
-
|
2016 |
-
#: templates/forms/affiliation.php:162
|
2017 |
-
msgid "Affiliate"
|
2018 |
-
msgstr "Affiliate"
|
2019 |
-
|
2020 |
-
#: templates/forms/affiliation.php165, templates/forms/resend-key.php:23
|
2021 |
-
msgid "Email address"
|
2022 |
-
msgstr "E-mailadresse"
|
2023 |
-
|
2024 |
-
#: templates/forms/affiliation.php:169
|
2025 |
-
msgid "Full name"
|
2026 |
-
msgstr "Fulde navn"
|
2027 |
-
|
2028 |
-
#: templates/forms/affiliation.php:173
|
2029 |
-
msgid "PayPal account email address"
|
2030 |
-
msgstr "E-mailadresse til PayPal-konto"
|
2031 |
-
|
2032 |
-
#: templates/forms/affiliation.php:177
|
2033 |
-
msgid "Where are you going to promote the %s?"
|
2034 |
-
msgstr "Where are you going to promote the %s?"
|
2035 |
-
|
2036 |
-
#: templates/forms/affiliation.php:179
|
2037 |
-
msgid "Enter the domain of your website or other websites from where you plan to promote the %s."
|
2038 |
-
msgstr "Enter the domain of your website or other websites from where you plan to promote the %s."
|
2039 |
-
|
2040 |
-
#: templates/forms/affiliation.php:181
|
2041 |
-
msgid "Add another domain"
|
2042 |
-
msgstr "Tilføj andet domæne"
|
2043 |
-
|
2044 |
-
#: templates/forms/affiliation.php:185
|
2045 |
-
msgid "Extra Domains"
|
2046 |
-
msgstr "Ekstra domæner"
|
2047 |
-
|
2048 |
-
#: templates/forms/affiliation.php:186
|
2049 |
-
msgid "Extra domains where you will be marketing the product from."
|
2050 |
-
msgstr "Extra domains where you will be marketing the product from."
|
2051 |
-
|
2052 |
-
#: templates/forms/affiliation.php:196
|
2053 |
-
msgid "Promotion methods"
|
2054 |
-
msgstr "Promotion methods"
|
2055 |
-
|
2056 |
-
#: templates/forms/affiliation.php:199
|
2057 |
-
msgid "Social media (Facebook, Twitter, etc.)"
|
2058 |
-
msgstr "Social media (Facebook, Twitter, etc.)"
|
2059 |
-
|
2060 |
-
#: templates/forms/affiliation.php:203
|
2061 |
-
msgid "Mobile apps"
|
2062 |
-
msgstr "Mobile apps"
|
2063 |
-
|
2064 |
-
#: templates/forms/affiliation.php:207
|
2065 |
-
msgid "Website, email, and social media statistics (optional)"
|
2066 |
-
msgstr "Website, email, and social media statistics (optional)"
|
2067 |
-
|
2068 |
-
#: templates/forms/affiliation.php:210
|
2069 |
-
msgid "Please feel free to provide any relevant website or social media statistics, e.g. monthly unique site visits, number of email subscribers, followers, etc. (we will keep this information confidential)."
|
2070 |
-
msgstr "Please feel free to provide any relevant website or social media statistics, e.g. monthly unique site visits, number of email subscribers, followers, etc. (we will keep this information confidential)."
|
2071 |
-
|
2072 |
-
#: templates/forms/affiliation.php:214
|
2073 |
-
msgid "How will you promote us?"
|
2074 |
-
msgstr "How will you promote us?"
|
2075 |
-
|
2076 |
-
#: templates/forms/affiliation.php:217
|
2077 |
-
msgid "Please provide details on how you intend to promote %s (please be as specific as possible)."
|
2078 |
-
msgstr "Please provide details on how you intend to promote %s (please be as specific as possible)."
|
2079 |
-
|
2080 |
-
#: templates/forms/affiliation.php223, templates/forms/resend-key.php:22
|
2081 |
-
msgid "Cancel"
|
2082 |
-
msgstr "Annuller"
|
2083 |
-
|
2084 |
-
#: templates/forms/affiliation.php:225
|
2085 |
-
msgid "Become an affiliate"
|
2086 |
-
msgstr "Become an affiliate"
|
2087 |
-
|
2088 |
-
#: templates/forms/license-activation.php:20
|
2089 |
-
msgid "Please enter the license key that you received in the email right after the purchase:"
|
2090 |
-
msgstr "Please enter the license key that you received in the email right after the purchase:"
|
2091 |
-
|
2092 |
-
#: templates/forms/license-activation.php:25
|
2093 |
-
msgid "Update License"
|
2094 |
-
msgstr "Opdater licens"
|
2095 |
-
|
2096 |
-
#: templates/forms/optout.php:30
|
2097 |
-
msgctxt "verb"
|
2098 |
-
msgid "Opt Out"
|
2099 |
-
msgstr "Frameld"
|
2100 |
-
|
2101 |
-
#: templates/forms/optout.php:31
|
2102 |
-
msgctxt "verb"
|
2103 |
-
msgid "Opt In"
|
2104 |
-
msgstr "Tilmeld"
|
2105 |
-
|
2106 |
-
#: templates/forms/optout.php:33
|
2107 |
-
msgid "Usage tracking is done in the name of making %s better. Making a better user experience, prioritizing new features, and more good things. We'd really appreciate if you'll reconsider letting us continue with the tracking."
|
2108 |
-
msgstr "Usage tracking is done in the name of making %s better. Making a better user experience, prioritizing new features, and more good things. We'd really appreciate if you'll reconsider letting us continue with the tracking."
|
2109 |
-
|
2110 |
-
#: templates/forms/optout.php:35
|
2111 |
-
msgid "By clicking \"Opt Out\", we will no longer be sending any data from %s to %s."
|
2112 |
-
msgstr "Ved at klikke \"Frameld\" vil vi ikke længere sende data fra %s til %s."
|
2113 |
-
|
2114 |
-
#: templates/forms/premium-versions-upgrade-handler.php:24
|
2115 |
-
msgid "There is a new version of %s available."
|
2116 |
-
msgstr "There is a new version of %s available."
|
2117 |
-
|
2118 |
-
#: templates/forms/premium-versions-upgrade-handler.php:25
|
2119 |
-
msgid " %sRenew your license now%s to access version %s security & feature updates, and support."
|
2120 |
-
msgstr " %sRenew your license now%s to access version %s security & feature updates, and support."
|
2121 |
-
|
2122 |
-
#: templates/forms/premium-versions-upgrade-handler.php:34
|
2123 |
-
msgid "New Version Available"
|
2124 |
-
msgstr "New Version Available"
|
2125 |
-
|
2126 |
-
#: templates/forms/premium-versions-upgrade-handler.php:36
|
2127 |
-
msgid "Renew license"
|
2128 |
-
msgstr "Renew license"
|
2129 |
-
|
2130 |
-
#: templates/forms/premium-versions-upgrade-handler.php:53
|
2131 |
-
msgctxt "close a window"
|
2132 |
-
msgid "Dismiss"
|
2133 |
-
msgstr "Fjern"
|
2134 |
-
|
2135 |
-
#: templates/forms/resend-key.php:21
|
2136 |
-
msgid "Send License Key"
|
2137 |
-
msgstr "Send licensnøgle"
|
2138 |
-
|
2139 |
-
#: templates/forms/resend-key.php:57
|
2140 |
-
msgid "Enter the email address you've used for the upgrade below and we will resend you the license key."
|
2141 |
-
msgstr "Enter the email address you've used for the upgrade below and we will resend you the license key."
|
2142 |
-
|
2143 |
-
#: templates/forms/trial-start.php:22
|
2144 |
-
msgid "You are 1-click away from starting your %1$s-day free trial of the %2$s plan."
|
2145 |
-
msgstr "Du er 1 klik fra at begynde din %1$s dages gratis prøveperiode af planen %2$s."
|
2146 |
-
|
2147 |
-
#: templates/forms/trial-start.php:28
|
2148 |
-
msgid "For compliance with the WordPress.org guidelines, before we start the trial we ask that you opt in with your user and non-sensitive site information, allowing the %s to periodically send data to %s to check for version updates and to validate your trial."
|
2149 |
-
msgstr "For compliance with the WordPress.org guidelines, before we start the trial we ask that you opt in with your user and non-sensitive site information, allowing the %s to periodically send data to %s to check for version updates and to validate your trial."
|
2150 |
-
|
2151 |
-
#: templates/js/style-premium-theme.php:37
|
2152 |
-
msgid "Premium"
|
2153 |
-
msgstr "Premium"
|
2154 |
-
|
2155 |
-
#: templates/partials/network-activation.php:23
|
2156 |
-
msgid "Activate license on all sites in the network."
|
2157 |
-
msgstr "Activate license on all sites in the network."
|
2158 |
-
|
2159 |
-
#: templates/partials/network-activation.php:24
|
2160 |
-
msgid "Apply on all sites in the network."
|
2161 |
-
msgstr "Apply on all sites in the network."
|
2162 |
-
|
2163 |
-
#: templates/partials/network-activation.php:27
|
2164 |
-
msgid "Activate license on all pending sites."
|
2165 |
-
msgstr "Activate license on all pending sites."
|
2166 |
-
|
2167 |
-
#: templates/partials/network-activation.php:28
|
2168 |
-
msgid "Apply on all pending sites."
|
2169 |
-
msgstr "Apply on all pending sites."
|
2170 |
-
|
2171 |
-
#: templates/partials/network-activation.php36,
|
2172 |
-
#: templates/partials/network-activation.php:68
|
2173 |
-
msgid "allow"
|
2174 |
-
msgstr "allow"
|
2175 |
-
|
2176 |
-
#: templates/partials/network-activation.php38,
|
2177 |
-
#: templates/partials/network-activation.php:70
|
2178 |
-
msgid "delegate"
|
2179 |
-
msgstr "delegate"
|
2180 |
-
|
2181 |
-
#: templates/partials/network-activation.php41,
|
2182 |
-
#: templates/partials/network-activation.php:73
|
2183 |
-
msgid "skip"
|
2184 |
-
msgstr "skip"
|
2185 |
-
|
2186 |
-
#: templates/plugin-info/description.php72,
|
2187 |
-
#: templates/plugin-info/screenshots.php:31
|
2188 |
-
msgid "Click to view full-size screenshot %d"
|
2189 |
-
msgstr "Click to view full-size screenshot %d"
|
2190 |
-
|
2191 |
-
#: templates/plugin-info/features.php:56
|
2192 |
-
msgid "Unlimited Updates"
|
2193 |
-
msgstr "Ubegrænsede opdateringer"
|
2194 |
-
|
2195 |
-
#: templates/account/partials/activate-license-button.php:46
|
2196 |
-
msgid "Localhost"
|
2197 |
-
msgstr "Localhost"
|
2198 |
-
|
2199 |
-
#: templates/account/partials/activate-license-button.php:50
|
2200 |
-
msgctxt "as 5 licenses left"
|
2201 |
-
msgid "%s left"
|
2202 |
-
msgstr "%s tilbage"
|
2203 |
-
|
2204 |
-
#: templates/account/partials/activate-license-button.php:51
|
2205 |
-
msgid "Last license"
|
2206 |
-
msgstr "Seneste license"
|
2207 |
-
|
2208 |
-
#: templates/account/partials/addon.php:111
|
2209 |
-
msgid "Cancelled"
|
2210 |
-
msgstr "Annulleret"
|
2211 |
-
|
2212 |
-
#: templates/account/partials/addon.php:116
|
2213 |
-
msgid "Expired"
|
2214 |
-
msgstr "Udløbet"
|
2215 |
-
|
2216 |
-
#: templates/account/partials/addon.php:121
|
2217 |
-
msgid "No expiration"
|
2218 |
-
msgstr "Udløber ikke"
|
2219 |
-
|
2220 |
-
#: templates/account/partials/addon.php259,
|
2221 |
-
#: templates/account/partials/addon.php:312
|
2222 |
-
msgid "Activate this add-on"
|
2223 |
-
msgstr "Aktiver denne tilføjelse"
|
2224 |
-
|
2225 |
-
#: templates/account/partials/site.php:181
|
2226 |
-
msgid "Owner Name"
|
2227 |
-
msgstr "Owner Name"
|
2228 |
-
|
2229 |
-
#: templates/account/partials/site.php:193
|
2230 |
-
msgid "Owner Email"
|
2231 |
-
msgstr "Owner Email"
|
2232 |
-
|
2233 |
-
#: templates/account/partials/site.php:205
|
2234 |
-
msgid "Owner ID"
|
2235 |
-
msgstr "Owner ID"
|
2236 |
-
|
2237 |
-
#: templates/account/partials/site.php:270
|
2238 |
-
msgid "Subscription"
|
2239 |
-
msgstr "Subscription"
|
2240 |
-
|
2241 |
-
#: templates/forms/deactivation/contact.php:19
|
2242 |
-
msgid "Sorry for the inconvenience and we are here to help if you give us a chance."
|
2243 |
-
msgstr "Vi beklager ulejligheden, og vi er her for at hjælpe, hvis du giver os chancen."
|
2244 |
-
|
2245 |
-
#: templates/forms/deactivation/contact.php:22
|
2246 |
-
msgid "Contact Support"
|
2247 |
-
msgstr "Kontakt support"
|
2248 |
-
|
2249 |
-
#: templates/forms/deactivation/form.php:56
|
2250 |
-
msgid "Anonymous feedback"
|
2251 |
-
msgstr "Anonym feedback"
|
2252 |
-
|
2253 |
-
#: templates/forms/deactivation/form.php:63
|
2254 |
-
msgid "Deactivate"
|
2255 |
-
msgstr "Deaktiver"
|
2256 |
-
|
2257 |
-
#: templates/forms/deactivation/form.php:65
|
2258 |
-
msgid "Activate %s"
|
2259 |
-
msgstr "Aktiver %s"
|
2260 |
-
|
2261 |
-
#: templates/forms/deactivation/form.php:76
|
2262 |
-
msgid "Quick feedback"
|
2263 |
-
msgstr "Hurtig feedback"
|
2264 |
-
|
2265 |
-
#: templates/forms/deactivation/form.php:80
|
2266 |
-
msgid "If you have a moment, please let us know why you are %s"
|
2267 |
-
msgstr "Hvis du har tid, så lad os venligst vide hvorfor du %s"
|
2268 |
-
|
2269 |
-
#: templates/forms/deactivation/form.php:80
|
2270 |
-
msgid "deactivating"
|
2271 |
-
msgstr "deaktiverer"
|
2272 |
-
|
2273 |
-
#: templates/forms/deactivation/form.php:80
|
2274 |
-
msgid "switching"
|
2275 |
-
msgstr "skifter"
|
2276 |
-
|
2277 |
-
#: templates/forms/deactivation/form.php:269
|
2278 |
-
msgid "Submit & %s"
|
2279 |
-
msgstr "Send & %s"
|
2280 |
-
|
2281 |
-
#: templates/forms/deactivation/form.php:290
|
2282 |
-
msgid "Kindly tell us the reason so we can improve."
|
2283 |
-
msgstr "Fortæl os venligst årsagen, så vi kan forbedre det."
|
2284 |
-
|
2285 |
-
#: templates/forms/deactivation/form.php:411
|
2286 |
-
msgid "Yes - %s"
|
2287 |
-
msgstr "Ja - %s"
|
2288 |
-
|
2289 |
-
#: templates/forms/deactivation/form.php:418
|
2290 |
-
msgid "Skip & %s"
|
2291 |
-
msgstr "Spring over & %s"
|
2292 |
-
|
2293 |
-
#: templates/forms/deactivation/retry-skip.php:21
|
2294 |
-
msgid "Click here to use the plugin anonymously"
|
2295 |
-
msgstr "Klik her for at benytte pluginnet anonymt"
|
2296 |
-
|
2297 |
-
#: templates/forms/deactivation/retry-skip.php:23
|
2298 |
-
msgid "You might have missed it, but you don't have to share any data and can just %s the opt-in."
|
2299 |
-
msgstr "You might have missed it, but you don't have to share any data and can just %s the opt-in."
|
|
|
|
|
|
|
|
|
1 |
msgid ""
|
2 |
msgstr ""
|
3 |
+
"Project-Id-Version: \n"
|
4 |
+
"Report-Msgid-Bugs-To: \n"
|
5 |
"POT-Creation-Date: \n"
|
6 |
+
"PO-Revision-Date: \n"
|
7 |
+
"Last-Translator: \n"
|
8 |
+
"Language: \n"
|
9 |
+
"Language-Team: \n"
|
10 |
+
"Content-Type: \n"
|
11 |
+
"Content-Transfer-Encoding: \n"
|
12 |
+
"Plural-Forms: \n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sdk/freemius/languages/freemius-he_IL.mo
CHANGED
Binary file
|
sdk/freemius/languages/freemius-he_IL.po
CHANGED
@@ -2,13 +2,13 @@
|
|
2 |
# This file is distributed under the same license as the freemius package.
|
3 |
# Translators:
|
4 |
# Rami Yushuvaev <r_a_m_i@hotmail.com>, 2017
|
5 |
-
# Vova Feldman <vova@freemius.com>, 2017
|
6 |
msgid ""
|
7 |
msgstr ""
|
8 |
"Project-Id-Version: WordPress SDK\n"
|
9 |
"Report-Msgid-Bugs-To: https://github.com/Freemius/wordpress-sdk/issues\n"
|
10 |
"POT-Creation-Date: \n"
|
11 |
-
"PO-Revision-Date: 2018-05-
|
12 |
"Last-Translator: Vova Feldman <vova@freemius.com>\n"
|
13 |
"Language: he_IL\n"
|
14 |
"Language-Team: Hebrew (Israel) (http://www.transifex.com/freemius/wordpress-sdk/language/he_IL/)\n"
|
@@ -32,7 +32,7 @@ msgstr "שגיאה"
|
|
32 |
|
33 |
#: includes/class-freemius.php:1871
|
34 |
msgid "I found a better %s"
|
35 |
-
msgstr "
|
36 |
|
37 |
#: includes/class-freemius.php:1873
|
38 |
msgid "What's the %s's name?"
|
@@ -183,7 +183,7 @@ msgstr "Premium %s version was successfully activated."
|
|
183 |
#: includes/class-freemius.php4827, includes/class-freemius.php:6660
|
184 |
msgctxt ""
|
185 |
msgid "W00t"
|
186 |
-
msgstr "
|
187 |
|
188 |
#: includes/class-freemius.php:4842
|
189 |
msgid "You have a %s license."
|
@@ -382,7 +382,7 @@ msgstr "It seems like one of the authentication parameters is wrong. Update your
|
|
382 |
#: includes/class-freemius.php:16910
|
383 |
msgctxt ""
|
384 |
msgid "Hmm"
|
385 |
-
msgstr "
|
386 |
|
387 |
#: includes/class-freemius.php:16652
|
388 |
msgid "It looks like you are still on the %s plan. If you did upgrade or change your plan, it's probably an issue on our side - sorry."
|
@@ -428,7 +428,7 @@ msgstr "Your license has expired. You can still continue using all the %s featur
|
|
428 |
|
429 |
#: includes/class-freemius.php:16751
|
430 |
msgid "Your free trial has expired. You can still continue using all our free features."
|
431 |
-
msgstr "
|
432 |
|
433 |
#: includes/class-freemius.php:16753
|
434 |
msgid "Your free trial has expired. %1$sUpgrade now%2$s to continue using the %3$s without interruptions."
|
@@ -540,7 +540,7 @@ msgstr "We appreciate your help in making the %s better by letting us track some
|
|
540 |
|
541 |
#: includes/class-freemius.php:17911
|
542 |
msgid "Thank you!"
|
543 |
-
msgstr "
|
544 |
|
545 |
#: includes/class-freemius.php:17918
|
546 |
msgid "We will no longer be sending any usage data of %s on %s to %s."
|
@@ -680,15 +680,15 @@ msgstr "Auto installation only works for opted-in users."
|
|
680 |
#: includes/class-fs-plugin-updater.php713,
|
681 |
#: includes/class-fs-plugin-updater.php:727
|
682 |
msgid "Invalid module ID."
|
683 |
-
msgstr "
|
684 |
|
685 |
#: includes/class-freemius.php19564, includes/class-fs-plugin-updater.php:747
|
686 |
msgid "Premium version already active."
|
687 |
-
msgstr "
|
688 |
|
689 |
#: includes/class-freemius.php:19571
|
690 |
msgid "You do not have a valid license to access the premium version."
|
691 |
-
msgstr "
|
692 |
|
693 |
#: includes/class-freemius.php:19578
|
694 |
msgid "Plugin is a \"Serviceware\" which means it does not have a premium code version."
|
@@ -700,7 +700,7 @@ msgstr "Premium add-on version already installed."
|
|
700 |
|
701 |
#: includes/class-freemius.php:19941
|
702 |
msgid "View paid features"
|
703 |
-
msgstr "
|
704 |
|
705 |
#: includes/class-freemius.php:20251
|
706 |
msgid "Thank you so much for using %s and its add-ons!"
|
@@ -708,7 +708,7 @@ msgstr "Thank you so much for using %s and its add-ons!"
|
|
708 |
|
709 |
#: includes/class-freemius.php:20252
|
710 |
msgid "Thank you so much for using %s!"
|
711 |
-
msgstr "
|
712 |
|
713 |
#: includes/class-freemius.php:20258
|
714 |
msgid "You've already opted-in to our usage-tracking, which helps us keep improving the %s."
|
@@ -716,7 +716,7 @@ msgstr "You've already opted-in to our usage-tracking, which helps us keep impro
|
|
716 |
|
717 |
#: includes/class-freemius.php:20262
|
718 |
msgid "Thank you so much for using our products!"
|
719 |
-
msgstr "
|
720 |
|
721 |
#: includes/class-freemius.php:20263
|
722 |
msgid "You've already opted-in to our usage-tracking, which helps us keep improving them."
|
@@ -728,23 +728,23 @@ msgstr "%s and its add-ons"
|
|
728 |
|
729 |
#: includes/class-freemius.php:20291
|
730 |
msgid "Products"
|
731 |
-
msgstr "
|
732 |
|
733 |
#: includes/class-freemius.php20298, templates/connect.php:259
|
734 |
msgid "Yes"
|
735 |
-
msgstr "
|
736 |
|
737 |
#: includes/class-freemius.php20299, templates/connect.php:260
|
738 |
msgid "send me security & feature updates, educational content and offers."
|
739 |
-
msgstr "
|
740 |
|
741 |
#: includes/class-freemius.php20300, templates/connect.php:265
|
742 |
msgid "No"
|
743 |
-
msgstr "
|
744 |
|
745 |
#: includes/class-freemius.php20302, templates/connect.php:267
|
746 |
msgid "do %sNOT%s send me security & feature updates, educational content and offers."
|
747 |
-
msgstr "
|
748 |
|
749 |
#: includes/class-freemius.php:20312
|
750 |
msgid "Due to the new %sEU General Data Protection Regulation (GDPR)%s compliance requirements it is required that you provide your explicit consent, again, confirming that you are onboard 🙂"
|
@@ -756,7 +756,7 @@ msgstr "Please let us know if you'd like us to contact you for security & featur
|
|
756 |
|
757 |
#: includes/class-freemius.php:20598
|
758 |
msgid "License key is empty."
|
759 |
-
msgstr "
|
760 |
|
761 |
#: includes/class-fs-plugin-updater.php184,
|
762 |
#: includes/class-fs-plugin-updater.php:219
|
@@ -787,7 +787,7 @@ msgstr "התחל את %s הניסיון שלי"
|
|
787 |
|
788 |
#: includes/fs-plugin-info-dialog.php:380
|
789 |
msgid "Install Free Version Now"
|
790 |
-
msgstr "
|
791 |
|
792 |
#: includes/fs-plugin-info-dialog.php381, templates/auto-installation.php111,
|
793 |
#: templates/account/partials/addon.php267,
|
@@ -808,7 +808,7 @@ msgstr "הורד גרסה אחרונה"
|
|
808 |
|
809 |
#: includes/fs-plugin-info-dialog.php:403
|
810 |
msgid "Install Free Version Update Now"
|
811 |
-
msgstr "
|
812 |
|
813 |
#: includes/fs-plugin-info-dialog.php404, templates/account.php:448
|
814 |
msgid "Install Update Now"
|
@@ -824,7 +824,7 @@ msgstr "גרסה חדשה (%s) הותקנה"
|
|
824 |
|
825 |
#: includes/fs-plugin-info-dialog.php:424
|
826 |
msgid "Latest Free Version Installed"
|
827 |
-
msgstr "
|
828 |
|
829 |
#: includes/fs-plugin-info-dialog.php:425
|
830 |
msgid "Latest Version Installed"
|
@@ -1017,7 +1017,7 @@ msgstr "עמוד התוסף"
|
|
1017 |
#: includes/fs-plugin-info-dialog.php972,
|
1018 |
#: includes/fs-plugin-info-dialog.php:1054
|
1019 |
msgid "Donate to this plugin"
|
1020 |
-
msgstr "
|
1021 |
|
1022 |
#: includes/fs-plugin-info-dialog.php:979
|
1023 |
msgid "Average Rating"
|
@@ -1058,11 +1058,11 @@ msgstr "Warning"
|
|
1058 |
|
1059 |
#: includes/fs-plugin-info-dialog.php:1062
|
1060 |
msgid "This plugin has not been tested with your current version of WordPress."
|
1061 |
-
msgstr "
|
1062 |
|
1063 |
#: includes/fs-plugin-info-dialog.php:1064
|
1064 |
msgid "This plugin has not been marked as compatible with your version of WordPress."
|
1065 |
-
msgstr "
|
1066 |
|
1067 |
#: includes/fs-plugin-info-dialog.php:1083
|
1068 |
msgid "Paid add-on must be deployed to Freemius."
|
@@ -1278,7 +1278,7 @@ msgstr "אתרים"
|
|
1278 |
|
1279 |
#: templates/account.php:501
|
1280 |
msgid "Search by address"
|
1281 |
-
msgstr "
|
1282 |
|
1283 |
#: templates/account.php510, templates/account.php558, templates/debug.php226,
|
1284 |
#: templates/debug.php354, templates/debug.php439, templates/debug.php476,
|
@@ -1289,7 +1289,7 @@ msgstr "מזהה"
|
|
1289 |
|
1290 |
#: templates/account.php511, templates/debug.php:357
|
1291 |
msgid "Address"
|
1292 |
-
msgstr "
|
1293 |
|
1294 |
#: templates/account.php:512
|
1295 |
msgid "License"
|
@@ -1311,7 +1311,7 @@ msgstr "הסתר"
|
|
1311 |
|
1312 |
#: templates/account.php:665
|
1313 |
msgid "Deactivating your license will block all premium features, but will enable activating the license on another site. Are you sure you want to proceed?"
|
1314 |
-
msgstr "
|
1315 |
|
1316 |
#: templates/add-ons.php:36
|
1317 |
msgid "Add Ons for %s"
|
@@ -1341,11 +1341,11 @@ msgstr "התקנה אוטומטית"
|
|
1341 |
|
1342 |
#: templates/auto-installation.php:93
|
1343 |
msgid "An automated download and installation of %s (paid version) from %s will start in %s. If you would like to do it manually - click the cancellation button now."
|
1344 |
-
msgstr "
|
1345 |
|
1346 |
#: templates/auto-installation.php:104
|
1347 |
msgid "The installation process has started and may take a few minutes to complete. Please wait until it is done - do not refresh this page."
|
1348 |
-
msgstr "
|
1349 |
|
1350 |
#: templates/auto-installation.php:109
|
1351 |
msgid "Cancel Installation"
|
@@ -1357,7 +1357,7 @@ msgstr "Checkout"
|
|
1357 |
|
1358 |
#: templates/checkout.php:172
|
1359 |
msgid "PCI compliant"
|
1360 |
-
msgstr "PCI
|
1361 |
|
1362 |
#. translators: %s: name (e.g. Hey John,)
|
1363 |
#: templates/connect.php:110
|
@@ -1441,7 +1441,7 @@ msgstr "דלג"
|
|
1441 |
|
1442 |
#: templates/connect.php:305
|
1443 |
msgid "Delegate to Site Admins"
|
1444 |
-
msgstr "
|
1445 |
|
1446 |
#: templates/connect.php:305
|
1447 |
msgid "If you click it, this decision will be delegated to the sites administrators."
|
@@ -1634,7 +1634,7 @@ msgstr "Network Blog"
|
|
1634 |
|
1635 |
#: templates/debug.php:236
|
1636 |
msgid "Network User"
|
1637 |
-
msgstr "
|
1638 |
|
1639 |
#: templates/debug.php:273
|
1640 |
msgctxt "as connection was successful"
|
@@ -1652,7 +1652,7 @@ msgstr "Simulate Trial"
|
|
1652 |
|
1653 |
#: templates/debug.php:322
|
1654 |
msgid "Simulate Network Upgrade"
|
1655 |
-
msgstr "
|
1656 |
|
1657 |
#: templates/debug.php:348
|
1658 |
msgid "%s Installs"
|
@@ -1665,7 +1665,7 @@ msgstr "אתרים"
|
|
1665 |
|
1666 |
#: templates/debug.php356, templates/account/partials/site.php:148
|
1667 |
msgid "Blog ID"
|
1668 |
-
msgstr "
|
1669 |
|
1670 |
#: templates/debug.php421, templates/debug.php499,
|
1671 |
#: templates/account/partials/addon.php:334
|
@@ -1803,7 +1803,7 @@ msgstr "שם עסק"
|
|
1803 |
|
1804 |
#: templates/account/billing.php45, templates/account/billing.php:45
|
1805 |
msgid "Tax / VAT ID"
|
1806 |
-
msgstr "
|
1807 |
|
1808 |
#: templates/account/billing.php48, templates/account/billing.php48,
|
1809 |
#: templates/account/billing.php49, templates/account/billing.php:49
|
@@ -2114,7 +2114,7 @@ msgstr "By clicking \"Opt Out\", we will no longer be sending any data from %s t
|
|
2114 |
|
2115 |
#: templates/forms/premium-versions-upgrade-handler.php:24
|
2116 |
msgid "There is a new version of %s available."
|
2117 |
-
msgstr "
|
2118 |
|
2119 |
#: templates/forms/premium-versions-upgrade-handler.php:25
|
2120 |
msgid " %sRenew your license now%s to access version %s security & feature updates, and support."
|
@@ -2122,11 +2122,11 @@ msgstr " %sRenew your license now%s to access version %s security & feature upda
|
|
2122 |
|
2123 |
#: templates/forms/premium-versions-upgrade-handler.php:34
|
2124 |
msgid "New Version Available"
|
2125 |
-
msgstr "
|
2126 |
|
2127 |
#: templates/forms/premium-versions-upgrade-handler.php:36
|
2128 |
msgid "Renew license"
|
2129 |
-
msgstr "
|
2130 |
|
2131 |
#: templates/forms/premium-versions-upgrade-handler.php:53
|
2132 |
msgctxt "close a window"
|
@@ -2155,34 +2155,34 @@ msgstr "Premium"
|
|
2155 |
|
2156 |
#: templates/partials/network-activation.php:23
|
2157 |
msgid "Activate license on all sites in the network."
|
2158 |
-
msgstr "
|
2159 |
|
2160 |
#: templates/partials/network-activation.php:24
|
2161 |
msgid "Apply on all sites in the network."
|
2162 |
-
msgstr "
|
2163 |
|
2164 |
#: templates/partials/network-activation.php:27
|
2165 |
msgid "Activate license on all pending sites."
|
2166 |
-
msgstr "
|
2167 |
|
2168 |
#: templates/partials/network-activation.php:28
|
2169 |
msgid "Apply on all pending sites."
|
2170 |
-
msgstr "
|
2171 |
|
2172 |
#: templates/partials/network-activation.php36,
|
2173 |
#: templates/partials/network-activation.php:68
|
2174 |
msgid "allow"
|
2175 |
-
msgstr "
|
2176 |
|
2177 |
#: templates/partials/network-activation.php38,
|
2178 |
#: templates/partials/network-activation.php:70
|
2179 |
msgid "delegate"
|
2180 |
-
msgstr "
|
2181 |
|
2182 |
#: templates/partials/network-activation.php41,
|
2183 |
#: templates/partials/network-activation.php:73
|
2184 |
msgid "skip"
|
2185 |
-
msgstr "
|
2186 |
|
2187 |
#: templates/plugin-info/description.php72,
|
2188 |
#: templates/plugin-info/screenshots.php:31
|
@@ -2225,19 +2225,19 @@ msgstr "הפעל את ההרחבה"
|
|
2225 |
|
2226 |
#: templates/account/partials/site.php:181
|
2227 |
msgid "Owner Name"
|
2228 |
-
msgstr "
|
2229 |
|
2230 |
#: templates/account/partials/site.php:193
|
2231 |
msgid "Owner Email"
|
2232 |
-
msgstr "
|
2233 |
|
2234 |
#: templates/account/partials/site.php:205
|
2235 |
msgid "Owner ID"
|
2236 |
-
msgstr "
|
2237 |
|
2238 |
#: templates/account/partials/site.php:270
|
2239 |
msgid "Subscription"
|
2240 |
-
msgstr "
|
2241 |
|
2242 |
#: templates/forms/deactivation/contact.php:19
|
2243 |
msgid "Sorry for the inconvenience and we are here to help if you give us a chance."
|
2 |
# This file is distributed under the same license as the freemius package.
|
3 |
# Translators:
|
4 |
# Rami Yushuvaev <r_a_m_i@hotmail.com>, 2017
|
5 |
+
# Vova Feldman <vova@freemius.com>, 2017-2018
|
6 |
msgid ""
|
7 |
msgstr ""
|
8 |
"Project-Id-Version: WordPress SDK\n"
|
9 |
"Report-Msgid-Bugs-To: https://github.com/Freemius/wordpress-sdk/issues\n"
|
10 |
"POT-Creation-Date: \n"
|
11 |
+
"PO-Revision-Date: 2018-05-27 16:16+0000\n"
|
12 |
"Last-Translator: Vova Feldman <vova@freemius.com>\n"
|
13 |
"Language: he_IL\n"
|
14 |
"Language-Team: Hebrew (Israel) (http://www.transifex.com/freemius/wordpress-sdk/language/he_IL/)\n"
|
32 |
|
33 |
#: includes/class-freemius.php:1871
|
34 |
msgid "I found a better %s"
|
35 |
+
msgstr "מצאתי %s יותר טוב"
|
36 |
|
37 |
#: includes/class-freemius.php:1873
|
38 |
msgid "What's the %s's name?"
|
183 |
#: includes/class-freemius.php4827, includes/class-freemius.php:6660
|
184 |
msgctxt ""
|
185 |
msgid "W00t"
|
186 |
+
msgstr "יש"
|
187 |
|
188 |
#: includes/class-freemius.php:4842
|
189 |
msgid "You have a %s license."
|
382 |
#: includes/class-freemius.php:16910
|
383 |
msgctxt ""
|
384 |
msgid "Hmm"
|
385 |
+
msgstr "אממ"
|
386 |
|
387 |
#: includes/class-freemius.php:16652
|
388 |
msgid "It looks like you are still on the %s plan. If you did upgrade or change your plan, it's probably an issue on our side - sorry."
|
428 |
|
429 |
#: includes/class-freemius.php:16751
|
430 |
msgid "Your free trial has expired. You can still continue using all our free features."
|
431 |
+
msgstr "תקופת הניסיון שלך הסתיימה. הפיטצ'רים החינאמיים עדיין ניתנים לשימוש."
|
432 |
|
433 |
#: includes/class-freemius.php:16753
|
434 |
msgid "Your free trial has expired. %1$sUpgrade now%2$s to continue using the %3$s without interruptions."
|
540 |
|
541 |
#: includes/class-freemius.php:17911
|
542 |
msgid "Thank you!"
|
543 |
+
msgstr "תודה רבה!"
|
544 |
|
545 |
#: includes/class-freemius.php:17918
|
546 |
msgid "We will no longer be sending any usage data of %s on %s to %s."
|
680 |
#: includes/class-fs-plugin-updater.php713,
|
681 |
#: includes/class-fs-plugin-updater.php:727
|
682 |
msgid "Invalid module ID."
|
683 |
+
msgstr "מזהה המודול לא תקני."
|
684 |
|
685 |
#: includes/class-freemius.php19564, includes/class-fs-plugin-updater.php:747
|
686 |
msgid "Premium version already active."
|
687 |
+
msgstr "הגרסה בתשלום כבר פעילה."
|
688 |
|
689 |
#: includes/class-freemius.php:19571
|
690 |
msgid "You do not have a valid license to access the premium version."
|
691 |
+
msgstr "אין ברשותך רישיון בר תוקף לשימוש בגרסת הפרימיום."
|
692 |
|
693 |
#: includes/class-freemius.php:19578
|
694 |
msgid "Plugin is a \"Serviceware\" which means it does not have a premium code version."
|
700 |
|
701 |
#: includes/class-freemius.php:19941
|
702 |
msgid "View paid features"
|
703 |
+
msgstr "צפה בפיטצ'רים שבתשלום"
|
704 |
|
705 |
#: includes/class-freemius.php:20251
|
706 |
msgid "Thank you so much for using %s and its add-ons!"
|
708 |
|
709 |
#: includes/class-freemius.php:20252
|
710 |
msgid "Thank you so much for using %s!"
|
711 |
+
msgstr "אנו מודים לך על היותך כמשתמש של %s!"
|
712 |
|
713 |
#: includes/class-freemius.php:20258
|
714 |
msgid "You've already opted-in to our usage-tracking, which helps us keep improving the %s."
|
716 |
|
717 |
#: includes/class-freemius.php:20262
|
718 |
msgid "Thank you so much for using our products!"
|
719 |
+
msgstr "אנו מודים לך על השימוש במוצרים שלנו!"
|
720 |
|
721 |
#: includes/class-freemius.php:20263
|
722 |
msgid "You've already opted-in to our usage-tracking, which helps us keep improving them."
|
728 |
|
729 |
#: includes/class-freemius.php:20291
|
730 |
msgid "Products"
|
731 |
+
msgstr "מוצרים"
|
732 |
|
733 |
#: includes/class-freemius.php20298, templates/connect.php:259
|
734 |
msgid "Yes"
|
735 |
+
msgstr "כן"
|
736 |
|
737 |
#: includes/class-freemius.php20299, templates/connect.php:260
|
738 |
msgid "send me security & feature updates, educational content and offers."
|
739 |
+
msgstr "תשלחו לי עדכוני אבטחה ופיטצ'רים, תוכן חינוכי, ומידע אודות מבצעים."
|
740 |
|
741 |
#: includes/class-freemius.php20300, templates/connect.php:265
|
742 |
msgid "No"
|
743 |
+
msgstr "לא"
|
744 |
|
745 |
#: includes/class-freemius.php20302, templates/connect.php:267
|
746 |
msgid "do %sNOT%s send me security & feature updates, educational content and offers."
|
747 |
+
msgstr "%sאל%2$s תשלחו לי עדכוני אבטחה, פיטצ'רים, תוכן חינוכי, ומידע על מבצעים."
|
748 |
|
749 |
#: includes/class-freemius.php:20312
|
750 |
msgid "Due to the new %sEU General Data Protection Regulation (GDPR)%s compliance requirements it is required that you provide your explicit consent, again, confirming that you are onboard 🙂"
|
756 |
|
757 |
#: includes/class-freemius.php:20598
|
758 |
msgid "License key is empty."
|
759 |
+
msgstr "מפתח הרישיון ריק."
|
760 |
|
761 |
#: includes/class-fs-plugin-updater.php184,
|
762 |
#: includes/class-fs-plugin-updater.php:219
|
787 |
|
788 |
#: includes/fs-plugin-info-dialog.php:380
|
789 |
msgid "Install Free Version Now"
|
790 |
+
msgstr "התקן גרסה חינאמית עכשיו"
|
791 |
|
792 |
#: includes/fs-plugin-info-dialog.php381, templates/auto-installation.php111,
|
793 |
#: templates/account/partials/addon.php267,
|
808 |
|
809 |
#: includes/fs-plugin-info-dialog.php:403
|
810 |
msgid "Install Free Version Update Now"
|
811 |
+
msgstr "התקן עדכון גרסה חינאמית עכשיו"
|
812 |
|
813 |
#: includes/fs-plugin-info-dialog.php404, templates/account.php:448
|
814 |
msgid "Install Update Now"
|
824 |
|
825 |
#: includes/fs-plugin-info-dialog.php:424
|
826 |
msgid "Latest Free Version Installed"
|
827 |
+
msgstr "גרסה חינאמית עדכנית הותקנה"
|
828 |
|
829 |
#: includes/fs-plugin-info-dialog.php:425
|
830 |
msgid "Latest Version Installed"
|
1017 |
#: includes/fs-plugin-info-dialog.php972,
|
1018 |
#: includes/fs-plugin-info-dialog.php:1054
|
1019 |
msgid "Donate to this plugin"
|
1020 |
+
msgstr "תרום לתוסף"
|
1021 |
|
1022 |
#: includes/fs-plugin-info-dialog.php:979
|
1023 |
msgid "Average Rating"
|
1058 |
|
1059 |
#: includes/fs-plugin-info-dialog.php:1062
|
1060 |
msgid "This plugin has not been tested with your current version of WordPress."
|
1061 |
+
msgstr "תוסף זה לא נבדק עם גרסת הוורדפרס שלך."
|
1062 |
|
1063 |
#: includes/fs-plugin-info-dialog.php:1064
|
1064 |
msgid "This plugin has not been marked as compatible with your version of WordPress."
|
1065 |
+
msgstr "התוסף לא סומן כתואם לגרסת הוורדפרס שלך."
|
1066 |
|
1067 |
#: includes/fs-plugin-info-dialog.php:1083
|
1068 |
msgid "Paid add-on must be deployed to Freemius."
|
1278 |
|
1279 |
#: templates/account.php:501
|
1280 |
msgid "Search by address"
|
1281 |
+
msgstr "חפש לפי כתובת"
|
1282 |
|
1283 |
#: templates/account.php510, templates/account.php558, templates/debug.php226,
|
1284 |
#: templates/debug.php354, templates/debug.php439, templates/debug.php476,
|
1289 |
|
1290 |
#: templates/account.php511, templates/debug.php:357
|
1291 |
msgid "Address"
|
1292 |
+
msgstr "כתובת"
|
1293 |
|
1294 |
#: templates/account.php:512
|
1295 |
msgid "License"
|
1311 |
|
1312 |
#: templates/account.php:665
|
1313 |
msgid "Deactivating your license will block all premium features, but will enable activating the license on another site. Are you sure you want to proceed?"
|
1314 |
+
msgstr "ביטול הרישיון יחסום את כל הפיטצ'רים שבתשלום אך יאפשר להפעיל את הרישיון על אתר אחר. האם תרצו להמשיך בכל זאת?"
|
1315 |
|
1316 |
#: templates/add-ons.php:36
|
1317 |
msgid "Add Ons for %s"
|
1341 |
|
1342 |
#: templates/auto-installation.php:93
|
1343 |
msgid "An automated download and installation of %s (paid version) from %s will start in %s. If you would like to do it manually - click the cancellation button now."
|
1344 |
+
msgstr "הורדה והתקנה אוטומטית של %s (גרסה בתשלום) מ-%2$s תתחיל בעוד %3$s. אם ברצונך לבצע את ההתקנה ידנית - לחץ על כפתור הביטול עכשיו."
|
1345 |
|
1346 |
#: templates/auto-installation.php:104
|
1347 |
msgid "The installation process has started and may take a few minutes to complete. Please wait until it is done - do not refresh this page."
|
1348 |
+
msgstr "תהליך ההתקנה התחיל ויכול לקחת מספר דקות לסיום. אנא המתינו בסבלנות עד לסיום מבלי לרענן את הדפדפן."
|
1349 |
|
1350 |
#: templates/auto-installation.php:109
|
1351 |
msgid "Cancel Installation"
|
1357 |
|
1358 |
#: templates/checkout.php:172
|
1359 |
msgid "PCI compliant"
|
1360 |
+
msgstr "עומד בתקן PCI"
|
1361 |
|
1362 |
#. translators: %s: name (e.g. Hey John,)
|
1363 |
#: templates/connect.php:110
|
1441 |
|
1442 |
#: templates/connect.php:305
|
1443 |
msgid "Delegate to Site Admins"
|
1444 |
+
msgstr "האצלה למנהלי האתרים"
|
1445 |
|
1446 |
#: templates/connect.php:305
|
1447 |
msgid "If you click it, this decision will be delegated to the sites administrators."
|
1634 |
|
1635 |
#: templates/debug.php:236
|
1636 |
msgid "Network User"
|
1637 |
+
msgstr "משתמש רשת"
|
1638 |
|
1639 |
#: templates/debug.php:273
|
1640 |
msgctxt "as connection was successful"
|
1652 |
|
1653 |
#: templates/debug.php:322
|
1654 |
msgid "Simulate Network Upgrade"
|
1655 |
+
msgstr "סמלוץ עדכון לרשת"
|
1656 |
|
1657 |
#: templates/debug.php:348
|
1658 |
msgid "%s Installs"
|
1665 |
|
1666 |
#: templates/debug.php356, templates/account/partials/site.php:148
|
1667 |
msgid "Blog ID"
|
1668 |
+
msgstr "מזהה בלוג"
|
1669 |
|
1670 |
#: templates/debug.php421, templates/debug.php499,
|
1671 |
#: templates/account/partials/addon.php:334
|
1803 |
|
1804 |
#: templates/account/billing.php45, templates/account/billing.php:45
|
1805 |
msgid "Tax / VAT ID"
|
1806 |
+
msgstr "ח.פ."
|
1807 |
|
1808 |
#: templates/account/billing.php48, templates/account/billing.php48,
|
1809 |
#: templates/account/billing.php49, templates/account/billing.php:49
|
2114 |
|
2115 |
#: templates/forms/premium-versions-upgrade-handler.php:24
|
2116 |
msgid "There is a new version of %s available."
|
2117 |
+
msgstr "יש גרסה חדשה עבור ה%s."
|
2118 |
|
2119 |
#: templates/forms/premium-versions-upgrade-handler.php:25
|
2120 |
msgid " %sRenew your license now%s to access version %s security & feature updates, and support."
|
2122 |
|
2123 |
#: templates/forms/premium-versions-upgrade-handler.php:34
|
2124 |
msgid "New Version Available"
|
2125 |
+
msgstr "יש גרסה חדשה"
|
2126 |
|
2127 |
#: templates/forms/premium-versions-upgrade-handler.php:36
|
2128 |
msgid "Renew license"
|
2129 |
+
msgstr "חידוש רישיון"
|
2130 |
|
2131 |
#: templates/forms/premium-versions-upgrade-handler.php:53
|
2132 |
msgctxt "close a window"
|
2155 |
|
2156 |
#: templates/partials/network-activation.php:23
|
2157 |
msgid "Activate license on all sites in the network."
|
2158 |
+
msgstr "הפעלת רישיון על כל האתרים ברשת."
|
2159 |
|
2160 |
#: templates/partials/network-activation.php:24
|
2161 |
msgid "Apply on all sites in the network."
|
2162 |
+
msgstr "יישום על כל האתרים ברשת."
|
2163 |
|
2164 |
#: templates/partials/network-activation.php:27
|
2165 |
msgid "Activate license on all pending sites."
|
2166 |
+
msgstr "הפעלת רישיון על כל האתרים התלויים והעומדים."
|
2167 |
|
2168 |
#: templates/partials/network-activation.php:28
|
2169 |
msgid "Apply on all pending sites."
|
2170 |
+
msgstr "יישום על כל האתרים התלויים והעומדים."
|
2171 |
|
2172 |
#: templates/partials/network-activation.php36,
|
2173 |
#: templates/partials/network-activation.php:68
|
2174 |
msgid "allow"
|
2175 |
+
msgstr "אפשר"
|
2176 |
|
2177 |
#: templates/partials/network-activation.php38,
|
2178 |
#: templates/partials/network-activation.php:70
|
2179 |
msgid "delegate"
|
2180 |
+
msgstr "האצל"
|
2181 |
|
2182 |
#: templates/partials/network-activation.php41,
|
2183 |
#: templates/partials/network-activation.php:73
|
2184 |
msgid "skip"
|
2185 |
+
msgstr "דלג"
|
2186 |
|
2187 |
#: templates/plugin-info/description.php72,
|
2188 |
#: templates/plugin-info/screenshots.php:31
|
2225 |
|
2226 |
#: templates/account/partials/site.php:181
|
2227 |
msgid "Owner Name"
|
2228 |
+
msgstr "שם הבעלים"
|
2229 |
|
2230 |
#: templates/account/partials/site.php:193
|
2231 |
msgid "Owner Email"
|
2232 |
+
msgstr "מייל הבעלים"
|
2233 |
|
2234 |
#: templates/account/partials/site.php:205
|
2235 |
msgid "Owner ID"
|
2236 |
+
msgstr "מזהה הבעלים"
|
2237 |
|
2238 |
#: templates/account/partials/site.php:270
|
2239 |
msgid "Subscription"
|
2240 |
+
msgstr "מנוי"
|
2241 |
|
2242 |
#: templates/forms/deactivation/contact.php:19
|
2243 |
msgid "Sorry for the inconvenience and we are here to help if you give us a chance."
|
sdk/freemius/languages/freemius-it_IT.mo
CHANGED
Binary file
|
sdk/freemius/languages/freemius-it_IT.po
CHANGED
@@ -10,7 +10,7 @@ msgstr ""
|
|
10 |
"Project-Id-Version: WordPress SDK\n"
|
11 |
"Report-Msgid-Bugs-To: https://github.com/Freemius/wordpress-sdk/issues\n"
|
12 |
"POT-Creation-Date: \n"
|
13 |
-
"PO-Revision-Date: 2018-05-
|
14 |
"Last-Translator: Daniele Scasciafratte Mte90 <mte90net@gmail.com>\n"
|
15 |
"Language: it_IT\n"
|
16 |
"Language-Team: Italian (Italy) (http://www.transifex.com/freemius/wordpress-sdk/language/it_IT/)\n"
|
@@ -176,7 +176,7 @@ msgstr "%s non può funzionare senza il plugin."
|
|
176 |
#: includes/class-freemius.php4176, includes/class-freemius.php4201,
|
177 |
#: includes/class-freemius.php:17103
|
178 |
msgid "Unexpected API error. Please contact the %s's author with the following error."
|
179 |
-
msgstr "Errore API inaspettato. Contatta l'autore di
|
180 |
|
181 |
#: includes/class-freemius.php:4815
|
182 |
msgid "Premium %s version was successfully activated."
|
@@ -414,11 +414,11 @@ msgstr "Il piano è stato cambiato con successo a %s."
|
|
414 |
|
415 |
#: includes/class-freemius.php:16705
|
416 |
msgid "Your license has expired. You can still continue using the free %s forever."
|
417 |
-
msgstr "La tua licenza è scaduta. Puoi continuare ad usare la versione gratuita %
|
418 |
|
419 |
#: includes/class-freemius.php:16707
|
420 |
msgid "Your license has expired. %1$sUpgrade now%2$s to continue using the %3$s without interruptions."
|
421 |
-
msgstr "La tua licenza è scaduta. %1$saggiorna ora %2$sper continuare ad utilizzare %3$
|
422 |
|
423 |
#: includes/class-freemius.php:16715
|
424 |
msgid "Your license has been cancelled. If you think it's a mistake, please contact support."
|
@@ -434,7 +434,7 @@ msgstr "La tua versione di prova gratuita è scaduta. Puoi continuare ad usare t
|
|
434 |
|
435 |
#: includes/class-freemius.php:16753
|
436 |
msgid "Your free trial has expired. %1$sUpgrade now%2$s to continue using the %3$s without interruptions."
|
437 |
-
msgstr "La tua versione prova è scaduta.%1$
|
438 |
|
439 |
#: includes/class-freemius.php:16858
|
440 |
msgid "It looks like the license could not be activated."
|
@@ -470,7 +470,7 @@ msgstr "Stiamo avendo qualche problema temporaneo con il downgrade del piano. Ri
|
|
470 |
|
471 |
#: includes/class-freemius.php:17037
|
472 |
msgid "You are already running the %s in a trial mode."
|
473 |
-
msgstr "Stai già usando %
|
474 |
|
475 |
#: includes/class-freemius.php:17048
|
476 |
msgid "You already utilized a trial before."
|
@@ -538,7 +538,7 @@ msgstr "Fantastico"
|
|
538 |
|
539 |
#: includes/class-freemius.php17910, templates/forms/optout.php:32
|
540 |
msgid "We appreciate your help in making the %s better by letting us track some usage data."
|
541 |
-
msgstr "Ti ringraziamo per averci concesso di tracciare alcuni dati di utilizzo al fine di migliorare %s"
|
542 |
|
543 |
#: includes/class-freemius.php:17911
|
544 |
msgid "Thank you!"
|
@@ -571,7 +571,7 @@ msgstr "Siamo spiacenti, non siamo riusciti a completare l'aggiornamento via ema
|
|
571 |
|
572 |
#: includes/class-freemius.php:18067
|
573 |
msgid "If you would like to give up the ownership of the %s's account to %s click the Change Ownership button."
|
574 |
-
msgstr "Puoi abbandonare la proprietà dell'account %
|
575 |
|
576 |
#: includes/class-freemius.php:18074
|
577 |
msgid "Change Ownership"
|
@@ -626,7 +626,7 @@ msgstr "Inizia il periodo di prova gratuito"
|
|
626 |
|
627 |
#: includes/class-freemius.php:18804
|
628 |
msgid "Hey there, did you know that %s has an affiliate program? If you like the %s you can become our ambassador and earn some cash!"
|
629 |
-
msgstr "Ciao, sai che %
|
630 |
|
631 |
#: includes/class-freemius.php:18813
|
632 |
msgid "Learn more"
|
@@ -746,7 +746,7 @@ msgstr "No"
|
|
746 |
|
747 |
#: includes/class-freemius.php20302, templates/connect.php:267
|
748 |
msgid "do %sNOT%s send me security & feature updates, educational content and offers."
|
749 |
-
msgstr "%snon %
|
750 |
|
751 |
#: includes/class-freemius.php:20312
|
752 |
msgid "Due to the new %sEU General Data Protection Regulation (GDPR)%s compliance requirements it is required that you provide your explicit consent, again, confirming that you are onboard 🙂"
|
@@ -1409,11 +1409,11 @@ msgstr "Siamo felici di presentarvi il supporto al sistema multi network di Free
|
|
1409 |
|
1410 |
#: templates/connect.php:231
|
1411 |
msgid "During the update process we detected %d site(s) that are still pending license activation."
|
1412 |
-
msgstr "Durante la procedura di aggiornamento abbiamo individuato%
|
1413 |
|
1414 |
#: templates/connect.php:233
|
1415 |
msgid "If you'd like to use the %s on those sites, please enter your license key below and click the activation button."
|
1416 |
-
msgstr "Se vuoi utilizzare %
|
1417 |
|
1418 |
#: templates/connect.php:235
|
1419 |
msgid "%s's paid features"
|
@@ -1487,7 +1487,7 @@ msgstr "Newsletter"
|
|
1487 |
|
1488 |
#: templates/connect.php378, templates/forms/license-activation.php:38
|
1489 |
msgid "The %1$s will be periodically sending data to %2$s to check for security and feature updates, and verify the validity of your license."
|
1490 |
-
msgstr "%1$
|
1491 |
|
1492 |
#: templates/connect.php:383
|
1493 |
msgid "What permissions are being granted?"
|
@@ -1769,7 +1769,7 @@ msgstr "Timestamp"
|
|
1769 |
|
1770 |
#: templates/secure-https-header.php:28
|
1771 |
msgid "Secure HTTPS %s page, running from an external domain"
|
1772 |
-
msgstr "Metti in sicurezza la pagina HTTPS %
|
1773 |
|
1774 |
#: includes/customizer/class-fs-customizer-support-section.php55,
|
1775 |
#: templates/plugin-info/features.php:43
|
@@ -1982,7 +1982,7 @@ msgstr "Ti piace %s? Diventa il nostro ambasciatore e guadagna denaro ;-)"
|
|
1982 |
|
1983 |
#: templates/forms/affiliation.php:142
|
1984 |
msgid "Refer new customers to our %s and earn %s commission on each successful sale you refer!"
|
1985 |
-
msgstr "Comunica nuovi clienti al nostro %
|
1986 |
|
1987 |
#: templates/forms/affiliation.php:145
|
1988 |
msgid "Program Summary"
|
10 |
"Project-Id-Version: WordPress SDK\n"
|
11 |
"Report-Msgid-Bugs-To: https://github.com/Freemius/wordpress-sdk/issues\n"
|
12 |
"POT-Creation-Date: \n"
|
13 |
+
"PO-Revision-Date: 2018-05-25 22:15+0000\n"
|
14 |
"Last-Translator: Daniele Scasciafratte Mte90 <mte90net@gmail.com>\n"
|
15 |
"Language: it_IT\n"
|
16 |
"Language-Team: Italian (Italy) (http://www.transifex.com/freemius/wordpress-sdk/language/it_IT/)\n"
|
176 |
#: includes/class-freemius.php4176, includes/class-freemius.php4201,
|
177 |
#: includes/class-freemius.php:17103
|
178 |
msgid "Unexpected API error. Please contact the %s's author with the following error."
|
179 |
+
msgstr "Errore API inaspettato. Contatta l'autore di %s con il seguente errore."
|
180 |
|
181 |
#: includes/class-freemius.php:4815
|
182 |
msgid "Premium %s version was successfully activated."
|
414 |
|
415 |
#: includes/class-freemius.php:16705
|
416 |
msgid "Your license has expired. You can still continue using the free %s forever."
|
417 |
+
msgstr "La tua licenza è scaduta. Puoi continuare ad usare la versione gratuita %s per sempre."
|
418 |
|
419 |
#: includes/class-freemius.php:16707
|
420 |
msgid "Your license has expired. %1$sUpgrade now%2$s to continue using the %3$s without interruptions."
|
421 |
+
msgstr "La tua licenza è scaduta. %1$saggiorna ora %2$sper continuare ad utilizzare %3$s senza interruzioni."
|
422 |
|
423 |
#: includes/class-freemius.php:16715
|
424 |
msgid "Your license has been cancelled. If you think it's a mistake, please contact support."
|
434 |
|
435 |
#: includes/class-freemius.php:16753
|
436 |
msgid "Your free trial has expired. %1$sUpgrade now%2$s to continue using the %3$s without interruptions."
|
437 |
+
msgstr "La tua versione prova è scaduta.%1$s aggiorna ora %2$s per continuare ad usare %3$s senza interruzioni."
|
438 |
|
439 |
#: includes/class-freemius.php:16858
|
440 |
msgid "It looks like the license could not be activated."
|
470 |
|
471 |
#: includes/class-freemius.php:17037
|
472 |
msgid "You are already running the %s in a trial mode."
|
473 |
+
msgstr "Stai già usando %s in modalità prova."
|
474 |
|
475 |
#: includes/class-freemius.php:17048
|
476 |
msgid "You already utilized a trial before."
|
538 |
|
539 |
#: includes/class-freemius.php17910, templates/forms/optout.php:32
|
540 |
msgid "We appreciate your help in making the %s better by letting us track some usage data."
|
541 |
+
msgstr "Ti ringraziamo per averci concesso di tracciare alcuni dati di utilizzo al fine di migliorare %s."
|
542 |
|
543 |
#: includes/class-freemius.php:17911
|
544 |
msgid "Thank you!"
|
571 |
|
572 |
#: includes/class-freemius.php:18067
|
573 |
msgid "If you would like to give up the ownership of the %s's account to %s click the Change Ownership button."
|
574 |
+
msgstr "Puoi abbandonare la proprietà dell'account %s a %scliccando il pulsante Cambia proprietario."
|
575 |
|
576 |
#: includes/class-freemius.php:18074
|
577 |
msgid "Change Ownership"
|
626 |
|
627 |
#: includes/class-freemius.php:18804
|
628 |
msgid "Hey there, did you know that %s has an affiliate program? If you like the %s you can become our ambassador and earn some cash!"
|
629 |
+
msgstr "Ciao, sai che %s ha il programma di affiliazione? Se ti piace %s puoi diventare un nostro ambasciatore e guadagnare denaro!"
|
630 |
|
631 |
#: includes/class-freemius.php:18813
|
632 |
msgid "Learn more"
|
746 |
|
747 |
#: includes/class-freemius.php20302, templates/connect.php:267
|
748 |
msgid "do %sNOT%s send me security & feature updates, educational content and offers."
|
749 |
+
msgstr "%snon %s mi invierà aggiornamenti di funzionalità e sicurezza, contenuti formativi e offerte."
|
750 |
|
751 |
#: includes/class-freemius.php:20312
|
752 |
msgid "Due to the new %sEU General Data Protection Regulation (GDPR)%s compliance requirements it is required that you provide your explicit consent, again, confirming that you are onboard 🙂"
|
1409 |
|
1410 |
#: templates/connect.php:231
|
1411 |
msgid "During the update process we detected %d site(s) that are still pending license activation."
|
1412 |
+
msgstr "Durante la procedura di aggiornamento abbiamo individuato%d sito/i che sono in attesa della attivazione della licenza."
|
1413 |
|
1414 |
#: templates/connect.php:233
|
1415 |
msgid "If you'd like to use the %s on those sites, please enter your license key below and click the activation button."
|
1416 |
+
msgstr "Se vuoi utilizzare %s su questi siti, inserisci la tua licenza sotto e fai clic sul pulsante di attivazione."
|
1417 |
|
1418 |
#: templates/connect.php:235
|
1419 |
msgid "%s's paid features"
|
1487 |
|
1488 |
#: templates/connect.php378, templates/forms/license-activation.php:38
|
1489 |
msgid "The %1$s will be periodically sending data to %2$s to check for security and feature updates, and verify the validity of your license."
|
1490 |
+
msgstr " Il %1$s invierà periodicamente dei dati a %2$s per verificare aggiornamenti di sicurezza e di funzionalità e verificare la validità della tua licenza."
|
1491 |
|
1492 |
#: templates/connect.php:383
|
1493 |
msgid "What permissions are being granted?"
|
1769 |
|
1770 |
#: templates/secure-https-header.php:28
|
1771 |
msgid "Secure HTTPS %s page, running from an external domain"
|
1772 |
+
msgstr "Metti in sicurezza la pagina HTTPS %s gestita da un dominio esterno"
|
1773 |
|
1774 |
#: includes/customizer/class-fs-customizer-support-section.php55,
|
1775 |
#: templates/plugin-info/features.php:43
|
1982 |
|
1983 |
#: templates/forms/affiliation.php:142
|
1984 |
msgid "Refer new customers to our %s and earn %s commission on each successful sale you refer!"
|
1985 |
+
msgstr "Comunica nuovi clienti al nostro %s e guadagna %s di commissione per ogni vendita avvenuta!"
|
1986 |
|
1987 |
#: templates/forms/affiliation.php:145
|
1988 |
msgid "Program Summary"
|
sdk/freemius/languages/freemius.pot
CHANGED
@@ -120,602 +120,602 @@ msgstr ""
|
|
120 |
msgid "Freemius Debug"
|
121 |
msgstr ""
|
122 |
|
123 |
-
#: includes/class-freemius.php:
|
124 |
msgid "I don't know what is cURL or how to install it, help me!"
|
125 |
msgstr ""
|
126 |
|
127 |
-
#: includes/class-freemius.php:
|
128 |
msgid "We'll make sure to contact your hosting company and resolve the issue. You will get a follow-up email to %s once we have an update."
|
129 |
msgstr ""
|
130 |
|
131 |
-
#: includes/class-freemius.php:
|
132 |
msgid "Great, please install cURL and enable it in your php.ini file. In addition, search for the 'disable_functions' directive in your php.ini file and remove any disabled methods starting with 'curl_'. To make sure it was successfully activated, use 'phpinfo()'. Once activated, deactivate the %s and reactivate it back again."
|
133 |
msgstr ""
|
134 |
|
135 |
-
#: includes/class-freemius.php:
|
136 |
msgid "Yes - do your thing"
|
137 |
msgstr ""
|
138 |
|
139 |
-
#: includes/class-freemius.php:
|
140 |
msgid "No - just deactivate"
|
141 |
msgstr ""
|
142 |
|
143 |
-
#: includes/class-freemius.php:
|
144 |
msgctxt "exclamation"
|
145 |
msgid "Oops"
|
146 |
msgstr ""
|
147 |
|
148 |
-
#: includes/class-freemius.php:
|
149 |
msgid "Thank for giving us the chance to fix it! A message was just sent to our technical staff. We will get back to you as soon as we have an update to %s. Appreciate your patience."
|
150 |
msgstr ""
|
151 |
|
152 |
-
#: includes/class-freemius.php:
|
153 |
msgctxt "addonX cannot run without pluginY"
|
154 |
msgid "%s cannot run without %s."
|
155 |
msgstr ""
|
156 |
|
157 |
-
#: includes/class-freemius.php:
|
158 |
msgctxt "addonX cannot run..."
|
159 |
msgid "%s cannot run without the plugin."
|
160 |
msgstr ""
|
161 |
|
162 |
-
#: includes/class-freemius.php:
|
163 |
msgid "Unexpected API error. Please contact the %s's author with the following error."
|
164 |
msgstr ""
|
165 |
|
166 |
-
#: includes/class-freemius.php:
|
167 |
msgid "Premium %s version was successfully activated."
|
168 |
msgstr ""
|
169 |
|
170 |
-
#: includes/class-freemius.php:
|
171 |
msgctxt "Used to express elation, enthusiasm, or triumph (especially in electronic communication)."
|
172 |
msgid "W00t"
|
173 |
msgstr ""
|
174 |
|
175 |
-
#: includes/class-freemius.php:
|
176 |
msgid "You have a %s license."
|
177 |
msgstr ""
|
178 |
|
179 |
-
#: includes/class-freemius.php:
|
180 |
msgctxt "interjection expressing joy or exuberance"
|
181 |
msgid "Yee-haw"
|
182 |
msgstr ""
|
183 |
|
184 |
-
#: includes/class-freemius.php:
|
185 |
msgid "%s free trial was successfully cancelled. Since the add-on is premium only it was automatically deactivated. If you like to use it in the future, you'll have to purchase a license."
|
186 |
msgstr ""
|
187 |
|
188 |
-
#: includes/class-freemius.php:
|
189 |
msgid "%s is a premium only add-on. You have to purchase a license first before activating the plugin."
|
190 |
msgstr ""
|
191 |
|
192 |
-
#: includes/class-freemius.php:
|
193 |
msgid "More information about %s"
|
194 |
msgstr ""
|
195 |
|
196 |
-
#: includes/class-freemius.php:
|
197 |
msgid "Purchase License"
|
198 |
msgstr ""
|
199 |
|
200 |
-
#: includes/class-freemius.php:
|
201 |
msgid "You should receive an activation email for %s to your mailbox at %s. Please make sure you click the activation button in that email to %s."
|
202 |
msgstr ""
|
203 |
|
204 |
-
#: includes/class-freemius.php:
|
205 |
msgid "start the trial"
|
206 |
msgstr ""
|
207 |
|
208 |
-
#: includes/class-freemius.php:
|
209 |
msgid "complete the install"
|
210 |
msgstr ""
|
211 |
|
212 |
-
#: includes/class-freemius.php:
|
213 |
msgid "You are just one step away - %s"
|
214 |
msgstr ""
|
215 |
|
216 |
-
#: includes/class-freemius.php:
|
217 |
msgctxt "%s - plugin name. As complete \"PluginX\" activation now"
|
218 |
msgid "Complete \"%s\" Activation Now"
|
219 |
msgstr ""
|
220 |
|
221 |
-
#: includes/class-freemius.php:
|
222 |
msgid "We made a few tweaks to the %s, %s"
|
223 |
msgstr ""
|
224 |
|
225 |
-
#: includes/class-freemius.php:
|
226 |
msgid "Opt in to make \"%s\" Better!"
|
227 |
msgstr ""
|
228 |
|
229 |
-
#: includes/class-freemius.php:
|
230 |
msgid "The upgrade of %s was successfully completed."
|
231 |
msgstr ""
|
232 |
|
233 |
-
#: includes/class-freemius.php:
|
234 |
msgid "Add-On"
|
235 |
msgstr ""
|
236 |
|
237 |
-
#: includes/class-freemius.php:
|
238 |
msgid "Plugin"
|
239 |
msgstr ""
|
240 |
|
241 |
-
#: includes/class-freemius.php:
|
242 |
msgid "Theme"
|
243 |
msgstr ""
|
244 |
|
245 |
-
#: includes/class-freemius.php:
|
246 |
-
msgid "
|
247 |
msgstr ""
|
248 |
|
249 |
-
#: includes/class-freemius.php:
|
250 |
msgid "We couldn't find your email address in the system, are you sure it's the right address?"
|
251 |
msgstr ""
|
252 |
|
253 |
-
#: includes/class-freemius.php:
|
254 |
msgid "We can't see any active licenses associated with that email address, are you sure it's the right address?"
|
255 |
msgstr ""
|
256 |
|
257 |
-
#: includes/class-freemius.php:
|
258 |
msgid "Account is pending activation."
|
259 |
msgstr ""
|
260 |
|
261 |
-
#: includes/class-freemius.php:
|
262 |
msgid "%s activation was successfully completed."
|
263 |
msgstr ""
|
264 |
|
265 |
-
#: includes/class-freemius.php:
|
266 |
msgid "Your account was successfully activated with the %s plan."
|
267 |
msgstr ""
|
268 |
|
269 |
-
#: includes/class-freemius.php:
|
270 |
msgid "Your trial has been successfully started."
|
271 |
msgstr ""
|
272 |
|
273 |
-
#: includes/class-freemius.php:
|
274 |
msgid "Couldn't activate %s."
|
275 |
msgstr ""
|
276 |
|
277 |
-
#: includes/class-freemius.php:
|
278 |
msgid "Please contact us with the following message:"
|
279 |
msgstr ""
|
280 |
|
281 |
-
#: includes/class-freemius.php:
|
282 |
msgid "Upgrade"
|
283 |
msgstr ""
|
284 |
|
285 |
-
#: includes/class-freemius.php:
|
286 |
msgid "Start Trial"
|
287 |
msgstr ""
|
288 |
|
289 |
-
#: includes/class-freemius.php:
|
290 |
msgid "Pricing"
|
291 |
msgstr ""
|
292 |
|
293 |
-
#: includes/class-freemius.php:
|
294 |
msgid "Affiliation"
|
295 |
msgstr ""
|
296 |
|
297 |
-
#: includes/class-freemius.php:
|
298 |
msgid "Account"
|
299 |
msgstr ""
|
300 |
|
301 |
-
#: includes/class-freemius.php:
|
302 |
msgid "Contact Us"
|
303 |
msgstr ""
|
304 |
|
305 |
-
#: includes/class-freemius.php:
|
306 |
msgid "Add-Ons"
|
307 |
msgstr ""
|
308 |
|
309 |
-
#: includes/class-freemius.php:
|
310 |
msgctxt "noun"
|
311 |
msgid "Pricing"
|
312 |
msgstr ""
|
313 |
|
314 |
-
#: includes/class-freemius.php:
|
315 |
msgid "Support Forum"
|
316 |
msgstr ""
|
317 |
|
318 |
-
#: includes/class-freemius.php:
|
319 |
msgid "Your email has been successfully verified - you are AWESOME!"
|
320 |
msgstr ""
|
321 |
|
322 |
-
#: includes/class-freemius.php:
|
323 |
msgctxt "a positive response"
|
324 |
msgid "Right on"
|
325 |
msgstr ""
|
326 |
|
327 |
-
#: includes/class-freemius.php:
|
328 |
msgid "Your %s Add-on plan was successfully upgraded."
|
329 |
msgstr ""
|
330 |
|
331 |
-
#: includes/class-freemius.php:
|
332 |
msgid "%s Add-on was successfully purchased."
|
333 |
msgstr ""
|
334 |
|
335 |
-
#: includes/class-freemius.php:
|
336 |
msgid "Download the latest version"
|
337 |
msgstr ""
|
338 |
|
339 |
-
#: includes/class-freemius.php:
|
340 |
msgctxt "%1s - plugin title, %2s - API domain"
|
341 |
msgid "Your server is blocking the access to Freemius' API, which is crucial for %1s synchronization. Please contact your host to whitelist %2s"
|
342 |
msgstr ""
|
343 |
|
344 |
-
#: includes/class-freemius.php:
|
345 |
msgid "Error received from the server:"
|
346 |
msgstr ""
|
347 |
|
348 |
-
#: includes/class-freemius.php:
|
349 |
msgid "It seems like one of the authentication parameters is wrong. Update your Public Key, Secret Key & User ID, and try again."
|
350 |
msgstr ""
|
351 |
|
352 |
-
#: includes/class-freemius.php:
|
353 |
msgctxt "something somebody says when they are thinking about what you have just said."
|
354 |
msgid "Hmm"
|
355 |
msgstr ""
|
356 |
|
357 |
-
#: includes/class-freemius.php:
|
358 |
msgid "It looks like you are still on the %s plan. If you did upgrade or change your plan, it's probably an issue on our side - sorry."
|
359 |
msgstr ""
|
360 |
|
361 |
-
#: includes/class-freemius.php:
|
362 |
msgctxt "trial period"
|
363 |
msgid "Trial"
|
364 |
msgstr ""
|
365 |
|
366 |
-
#: includes/class-freemius.php:
|
367 |
msgid "I have upgraded my account but when I try to Sync the License, the plan remains %s."
|
368 |
msgstr ""
|
369 |
|
370 |
-
#: includes/class-freemius.php:
|
371 |
msgid "Please contact us here"
|
372 |
msgstr ""
|
373 |
|
374 |
-
#: includes/class-freemius.php:
|
375 |
msgid "Your plan was successfully upgraded."
|
376 |
msgstr ""
|
377 |
|
378 |
-
#: includes/class-freemius.php:
|
379 |
msgid "Your plan was successfully changed to %s."
|
380 |
msgstr ""
|
381 |
|
382 |
-
#: includes/class-freemius.php:
|
383 |
msgid "Your license has expired. You can still continue using the free %s forever."
|
384 |
msgstr ""
|
385 |
|
386 |
-
#: includes/class-freemius.php:
|
387 |
msgid "Your license has expired. %1$sUpgrade now%2$s to continue using the %3$s without interruptions."
|
388 |
msgstr ""
|
389 |
|
390 |
-
#: includes/class-freemius.php:
|
391 |
msgid "Your license has been cancelled. If you think it's a mistake, please contact support."
|
392 |
msgstr ""
|
393 |
|
394 |
-
#: includes/class-freemius.php:
|
395 |
msgid "Your license has expired. You can still continue using all the %s features, but you'll need to renew your license to continue getting updates and support."
|
396 |
msgstr ""
|
397 |
|
398 |
-
#: includes/class-freemius.php:
|
399 |
msgid "Your free trial has expired. You can still continue using all our free features."
|
400 |
msgstr ""
|
401 |
|
402 |
-
#: includes/class-freemius.php:
|
403 |
msgid "Your free trial has expired. %1$sUpgrade now%2$s to continue using the %3$s without interruptions."
|
404 |
msgstr ""
|
405 |
|
406 |
-
#: includes/class-freemius.php:
|
407 |
msgid "It looks like the license could not be activated."
|
408 |
msgstr ""
|
409 |
|
410 |
-
#: includes/class-freemius.php:
|
411 |
msgid "Your license was successfully activated."
|
412 |
msgstr ""
|
413 |
|
414 |
-
#: includes/class-freemius.php:
|
415 |
msgid "It looks like your site currently doesn't have an active license."
|
416 |
msgstr ""
|
417 |
|
418 |
-
#: includes/class-freemius.php:
|
419 |
msgid "It looks like the license deactivation failed."
|
420 |
msgstr ""
|
421 |
|
422 |
-
#: includes/class-freemius.php:
|
423 |
msgid "Your license was successfully deactivated, you are back to the %s plan."
|
424 |
msgstr ""
|
425 |
|
426 |
-
#: includes/class-freemius.php:
|
427 |
msgid "O.K"
|
428 |
msgstr ""
|
429 |
|
430 |
-
#: includes/class-freemius.php:
|
431 |
msgid "Your plan was successfully downgraded. Your %s plan license will expire in %s."
|
432 |
msgstr ""
|
433 |
|
434 |
-
#: includes/class-freemius.php:
|
435 |
msgid "Seems like we are having some temporary issue with your plan downgrade. Please try again in few minutes."
|
436 |
msgstr ""
|
437 |
|
438 |
-
#: includes/class-freemius.php:
|
439 |
msgid "You are already running the %s in a trial mode."
|
440 |
msgstr ""
|
441 |
|
442 |
-
#: includes/class-freemius.php:
|
443 |
msgid "You already utilized a trial before."
|
444 |
msgstr ""
|
445 |
|
446 |
-
#: includes/class-freemius.php:
|
447 |
msgid "Plan %s do not exist, therefore, can't start a trial."
|
448 |
msgstr ""
|
449 |
|
450 |
-
#: includes/class-freemius.php:
|
451 |
msgid "Plan %s does not support a trial period."
|
452 |
msgstr ""
|
453 |
|
454 |
-
#: includes/class-freemius.php:
|
455 |
msgid "None of the %s's plans supports a trial period."
|
456 |
msgstr ""
|
457 |
|
458 |
-
#: includes/class-freemius.php:
|
459 |
msgid "It looks like you are not in trial mode anymore so there's nothing to cancel :)"
|
460 |
msgstr ""
|
461 |
|
462 |
-
#: includes/class-freemius.php:
|
463 |
msgid "Your %s free trial was successfully cancelled."
|
464 |
msgstr ""
|
465 |
|
466 |
-
#: includes/class-freemius.php:
|
467 |
msgid "Seems like we are having some temporary issue with your trial cancellation. Please try again in few minutes."
|
468 |
msgstr ""
|
469 |
|
470 |
-
#: includes/class-freemius.php:
|
471 |
msgid "Version %s was released."
|
472 |
msgstr ""
|
473 |
|
474 |
-
#: includes/class-freemius.php:
|
475 |
msgid "Please download %s."
|
476 |
msgstr ""
|
477 |
|
478 |
-
#: includes/class-freemius.php:
|
479 |
msgid "the latest %s version here"
|
480 |
msgstr ""
|
481 |
|
482 |
-
#: includes/class-freemius.php:
|
483 |
msgid "New"
|
484 |
msgstr ""
|
485 |
|
486 |
-
#: includes/class-freemius.php:
|
487 |
msgid "Seems like you got the latest release."
|
488 |
msgstr ""
|
489 |
|
490 |
-
#: includes/class-freemius.php:
|
491 |
msgid "You are all good!"
|
492 |
msgstr ""
|
493 |
|
494 |
-
#: includes/class-freemius.php:
|
495 |
msgid "Verification mail was just sent to %s. If you can't find it after 5 min, please check your spam box."
|
496 |
msgstr ""
|
497 |
|
498 |
-
#: includes/class-freemius.php:
|
499 |
msgid "Site successfully opted in."
|
500 |
msgstr ""
|
501 |
|
502 |
-
#: includes/class-freemius.php:
|
503 |
msgid "Awesome"
|
504 |
msgstr ""
|
505 |
|
506 |
-
#: includes/class-freemius.php:
|
507 |
msgid "We appreciate your help in making the %s better by letting us track some usage data."
|
508 |
msgstr ""
|
509 |
|
510 |
-
#: includes/class-freemius.php:
|
511 |
msgid "Thank you!"
|
512 |
msgstr ""
|
513 |
|
514 |
-
#: includes/class-freemius.php:
|
515 |
msgid "We will no longer be sending any usage data of %s on %s to %s."
|
516 |
msgstr ""
|
517 |
|
518 |
-
#: includes/class-freemius.php:
|
519 |
msgid "Please check your mailbox, you should receive an email via %s to confirm the ownership change. From security reasons, you must confirm the change within the next 15 min. If you cannot find the email, please check your spam folder."
|
520 |
msgstr ""
|
521 |
|
522 |
-
#: includes/class-freemius.php:
|
523 |
msgid "Thanks for confirming the ownership change. An email was just sent to %s for final approval."
|
524 |
msgstr ""
|
525 |
|
526 |
-
#: includes/class-freemius.php:
|
527 |
msgid "%s is the new owner of the account."
|
528 |
msgstr ""
|
529 |
|
530 |
-
#: includes/class-freemius.php:
|
531 |
msgctxt "as congratulations"
|
532 |
msgid "Congrats"
|
533 |
msgstr ""
|
534 |
|
535 |
-
#: includes/class-freemius.php:
|
536 |
msgid "Sorry, we could not complete the email update. Another user with the same email is already registered."
|
537 |
msgstr ""
|
538 |
|
539 |
-
#: includes/class-freemius.php:
|
540 |
msgid "If you would like to give up the ownership of the %s's account to %s click the Change Ownership button."
|
541 |
msgstr ""
|
542 |
|
543 |
-
#: includes/class-freemius.php:
|
544 |
msgid "Change Ownership"
|
545 |
msgstr ""
|
546 |
|
547 |
-
#: includes/class-freemius.php:
|
548 |
msgid "Your email was successfully updated. You should receive an email with confirmation instructions in few moments."
|
549 |
msgstr ""
|
550 |
|
551 |
-
#: includes/class-freemius.php:
|
552 |
msgid "Please provide your full name."
|
553 |
msgstr ""
|
554 |
|
555 |
-
#: includes/class-freemius.php:
|
556 |
msgid "Your name was successfully updated."
|
557 |
msgstr ""
|
558 |
|
559 |
-
#: includes/class-freemius.php:
|
560 |
msgid "You have successfully updated your %s."
|
561 |
msgstr ""
|
562 |
|
563 |
-
#: includes/class-freemius.php:
|
564 |
msgid "Just letting you know that the add-ons information of %s is being pulled from an external server."
|
565 |
msgstr ""
|
566 |
|
567 |
-
#: includes/class-freemius.php:
|
568 |
msgctxt "advance notice of something that will need attention."
|
569 |
msgid "Heads up"
|
570 |
msgstr ""
|
571 |
|
572 |
-
#: includes/class-freemius.php:
|
573 |
msgctxt "exclamation"
|
574 |
msgid "Hey"
|
575 |
msgstr ""
|
576 |
|
577 |
-
#: includes/class-freemius.php:
|
578 |
msgid "How do you like %s so far? Test all our %s premium features with a %d-day free trial."
|
579 |
msgstr ""
|
580 |
|
581 |
-
#: includes/class-freemius.php:
|
582 |
msgid "No commitment for %s days - cancel anytime!"
|
583 |
msgstr ""
|
584 |
|
585 |
-
#: includes/class-freemius.php:
|
586 |
msgid "No credit card required"
|
587 |
msgstr ""
|
588 |
|
589 |
-
#: includes/class-freemius.php:
|
590 |
msgctxt "call to action"
|
591 |
msgid "Start free trial"
|
592 |
msgstr ""
|
593 |
|
594 |
-
#: includes/class-freemius.php:
|
595 |
msgid "Hey there, did you know that %s has an affiliate program? If you like the %s you can become our ambassador and earn some cash!"
|
596 |
msgstr ""
|
597 |
|
598 |
-
#: includes/class-freemius.php:
|
599 |
msgid "Learn more"
|
600 |
msgstr ""
|
601 |
|
602 |
-
#: includes/class-freemius.php:
|
603 |
msgid "Activate License"
|
604 |
msgstr ""
|
605 |
|
606 |
-
#: includes/class-freemius.php:
|
607 |
msgid "Change License"
|
608 |
msgstr ""
|
609 |
|
610 |
-
#: includes/class-freemius.php:
|
611 |
msgid "Opt Out"
|
612 |
msgstr ""
|
613 |
|
614 |
-
#: includes/class-freemius.php:
|
615 |
msgid "Opt In"
|
616 |
msgstr ""
|
617 |
|
618 |
-
#: includes/class-freemius.php:
|
619 |
msgid "Please follow these steps to complete the upgrade"
|
620 |
msgstr ""
|
621 |
|
622 |
-
#: includes/class-freemius.php:
|
623 |
msgid "Download the latest %s version"
|
624 |
msgstr ""
|
625 |
|
626 |
-
#: includes/class-freemius.php:
|
627 |
msgid "Upload and activate the downloaded version"
|
628 |
msgstr ""
|
629 |
|
630 |
-
#: includes/class-freemius.php:
|
631 |
msgid "How to upload and activate?"
|
632 |
msgstr ""
|
633 |
|
634 |
-
#: includes/class-freemius.php:
|
635 |
msgid "%sClick here%s to choose the sites where you'd like to activate the license on."
|
636 |
msgstr ""
|
637 |
|
638 |
-
#: includes/class-freemius.php:
|
639 |
msgid "Auto installation only works for opted-in users."
|
640 |
msgstr ""
|
641 |
|
642 |
-
#: includes/class-freemius.php:
|
643 |
msgid "Invalid module ID."
|
644 |
msgstr ""
|
645 |
|
646 |
-
#: includes/class-freemius.php:
|
647 |
msgid "Premium version already active."
|
648 |
msgstr ""
|
649 |
|
650 |
-
#: includes/class-freemius.php:
|
651 |
msgid "You do not have a valid license to access the premium version."
|
652 |
msgstr ""
|
653 |
|
654 |
-
#: includes/class-freemius.php:
|
655 |
msgid "Plugin is a \"Serviceware\" which means it does not have a premium code version."
|
656 |
msgstr ""
|
657 |
|
658 |
-
#: includes/class-freemius.php:
|
659 |
msgid "Premium add-on version already installed."
|
660 |
msgstr ""
|
661 |
|
662 |
-
#: includes/class-freemius.php:
|
663 |
msgid "View paid features"
|
664 |
msgstr ""
|
665 |
|
666 |
-
#: includes/class-freemius.php:
|
667 |
msgid "Thank you so much for using %s and its add-ons!"
|
668 |
msgstr ""
|
669 |
|
670 |
-
#: includes/class-freemius.php:
|
671 |
msgid "Thank you so much for using %s!"
|
672 |
msgstr ""
|
673 |
|
674 |
-
#: includes/class-freemius.php:
|
675 |
msgid "You've already opted-in to our usage-tracking, which helps us keep improving the %s."
|
676 |
msgstr ""
|
677 |
|
678 |
-
#: includes/class-freemius.php:
|
679 |
msgid "Thank you so much for using our products!"
|
680 |
msgstr ""
|
681 |
|
682 |
-
#: includes/class-freemius.php:
|
683 |
msgid "You've already opted-in to our usage-tracking, which helps us keep improving them."
|
684 |
msgstr ""
|
685 |
|
686 |
-
#: includes/class-freemius.php:
|
687 |
msgid "%s and its add-ons"
|
688 |
msgstr ""
|
689 |
|
690 |
-
#: includes/class-freemius.php:
|
691 |
msgid "Products"
|
692 |
msgstr ""
|
693 |
|
694 |
-
#: includes/class-freemius.php:
|
695 |
msgid "Yes"
|
696 |
msgstr ""
|
697 |
|
698 |
-
#: includes/class-freemius.php:
|
699 |
msgid "send me security & feature updates, educational content and offers."
|
700 |
msgstr ""
|
701 |
|
702 |
-
#: includes/class-freemius.php:
|
703 |
msgid "No"
|
704 |
msgstr ""
|
705 |
|
706 |
-
#: includes/class-freemius.php:
|
707 |
msgid "do %sNOT%s send me security & feature updates, educational content and offers."
|
708 |
msgstr ""
|
709 |
|
710 |
-
#: includes/class-freemius.php:
|
711 |
msgid "Due to the new %sEU General Data Protection Regulation (GDPR)%s compliance requirements it is required that you provide your explicit consent, again, confirming that you are onboard 🙂"
|
712 |
msgstr ""
|
713 |
|
714 |
-
#: includes/class-freemius.php:
|
715 |
msgid "Please let us know if you'd like us to contact you for security & feature updates, educational content, and occasional offers:"
|
716 |
msgstr ""
|
717 |
|
718 |
-
#: includes/class-freemius.php:
|
719 |
msgid "License key is empty."
|
720 |
msgstr ""
|
721 |
|
@@ -766,7 +766,7 @@ msgstr ""
|
|
766 |
msgid "Install Free Version Update Now"
|
767 |
msgstr ""
|
768 |
|
769 |
-
#: includes/fs-plugin-info-dialog.php:404, templates/account.php:
|
770 |
msgid "Install Update Now"
|
771 |
msgstr ""
|
772 |
|
@@ -925,7 +925,7 @@ msgstr ""
|
|
925 |
msgid "Last Updated"
|
926 |
msgstr ""
|
927 |
|
928 |
-
#: includes/fs-plugin-info-dialog.php:915
|
929 |
msgctxt "x-ago"
|
930 |
msgid "%s ago"
|
931 |
msgstr ""
|
@@ -1167,71 +1167,75 @@ msgstr ""
|
|
1167 |
msgid "not verified"
|
1168 |
msgstr ""
|
1169 |
|
1170 |
-
#: templates/account.php:
|
|
|
|
|
|
|
|
|
1171 |
msgid "Premium version"
|
1172 |
msgstr ""
|
1173 |
|
1174 |
-
#: templates/account.php:
|
1175 |
msgid "Free version"
|
1176 |
msgstr ""
|
1177 |
|
1178 |
-
#: templates/account.php:
|
1179 |
msgid "Verify Email"
|
1180 |
msgstr ""
|
1181 |
|
1182 |
-
#: templates/account.php:
|
1183 |
msgid "Download %s Version"
|
1184 |
msgstr ""
|
1185 |
|
1186 |
-
#: templates/account.php:
|
1187 |
msgctxt "verb"
|
1188 |
msgid "Show"
|
1189 |
msgstr ""
|
1190 |
|
1191 |
-
#: templates/account.php:
|
1192 |
msgid "What is your %s?"
|
1193 |
msgstr ""
|
1194 |
|
1195 |
-
#: templates/account.php:
|
1196 |
msgctxt "verb"
|
1197 |
msgid "Edit"
|
1198 |
msgstr ""
|
1199 |
|
1200 |
-
#: templates/account.php:
|
1201 |
msgid "Sites"
|
1202 |
msgstr ""
|
1203 |
|
1204 |
-
#: templates/account.php:
|
1205 |
msgid "Search by address"
|
1206 |
msgstr ""
|
1207 |
|
1208 |
-
#: templates/account.php:
|
1209 |
msgid "ID"
|
1210 |
msgstr ""
|
1211 |
|
1212 |
-
#: templates/account.php:
|
1213 |
msgid "Address"
|
1214 |
msgstr ""
|
1215 |
|
1216 |
-
#: templates/account.php:
|
1217 |
msgid "License"
|
1218 |
msgstr ""
|
1219 |
|
1220 |
-
#: templates/account.php:
|
1221 |
msgid "Plan"
|
1222 |
msgstr ""
|
1223 |
|
1224 |
-
#: templates/account.php:
|
1225 |
msgctxt "as software license"
|
1226 |
msgid "License"
|
1227 |
msgstr ""
|
1228 |
|
1229 |
-
#: templates/account.php:
|
1230 |
msgctxt "verb"
|
1231 |
msgid "Hide"
|
1232 |
msgstr ""
|
1233 |
|
1234 |
-
#: templates/account.php:
|
1235 |
msgid "Deactivating your license will block all premium features, but will enable activating the license on another site. Are you sure you want to proceed?"
|
1236 |
msgstr ""
|
1237 |
|
@@ -2113,10 +2117,6 @@ msgstr ""
|
|
2113 |
msgid "Cancelled"
|
2114 |
msgstr ""
|
2115 |
|
2116 |
-
#: templates/account/partials/addon.php:116
|
2117 |
-
msgid "Expired"
|
2118 |
-
msgstr ""
|
2119 |
-
|
2120 |
#: templates/account/partials/addon.php:121
|
2121 |
msgid "No expiration"
|
2122 |
msgstr ""
|
120 |
msgid "Freemius Debug"
|
121 |
msgstr ""
|
122 |
|
123 |
+
#: includes/class-freemius.php:3453
|
124 |
msgid "I don't know what is cURL or how to install it, help me!"
|
125 |
msgstr ""
|
126 |
|
127 |
+
#: includes/class-freemius.php:3455
|
128 |
msgid "We'll make sure to contact your hosting company and resolve the issue. You will get a follow-up email to %s once we have an update."
|
129 |
msgstr ""
|
130 |
|
131 |
+
#: includes/class-freemius.php:3462
|
132 |
msgid "Great, please install cURL and enable it in your php.ini file. In addition, search for the 'disable_functions' directive in your php.ini file and remove any disabled methods starting with 'curl_'. To make sure it was successfully activated, use 'phpinfo()'. Once activated, deactivate the %s and reactivate it back again."
|
133 |
msgstr ""
|
134 |
|
135 |
+
#: includes/class-freemius.php:3567
|
136 |
msgid "Yes - do your thing"
|
137 |
msgstr ""
|
138 |
|
139 |
+
#: includes/class-freemius.php:3572
|
140 |
msgid "No - just deactivate"
|
141 |
msgstr ""
|
142 |
|
143 |
+
#: includes/class-freemius.php:3617, includes/class-freemius.php:4117, includes/class-freemius.php:5178, includes/class-freemius.php:10992, includes/class-freemius.php:14256, includes/class-freemius.php:14308, includes/class-freemius.php:14370, includes/class-freemius.php:16500, includes/class-freemius.php:16510, includes/class-freemius.php:17066, includes/class-freemius.php:17084, includes/class-freemius.php:17182, includes/class-freemius.php:17925, templates/add-ons.php:43
|
144 |
msgctxt "exclamation"
|
145 |
msgid "Oops"
|
146 |
msgstr ""
|
147 |
|
148 |
+
#: includes/class-freemius.php:3686
|
149 |
msgid "Thank for giving us the chance to fix it! A message was just sent to our technical staff. We will get back to you as soon as we have an update to %s. Appreciate your patience."
|
150 |
msgstr ""
|
151 |
|
152 |
+
#: includes/class-freemius.php:4114
|
153 |
msgctxt "addonX cannot run without pluginY"
|
154 |
msgid "%s cannot run without %s."
|
155 |
msgstr ""
|
156 |
|
157 |
+
#: includes/class-freemius.php:4115
|
158 |
msgctxt "addonX cannot run..."
|
159 |
msgid "%s cannot run without the plugin."
|
160 |
msgstr ""
|
161 |
|
162 |
+
#: includes/class-freemius.php:4227, includes/class-freemius.php:4252, includes/class-freemius.php:17155
|
163 |
msgid "Unexpected API error. Please contact the %s's author with the following error."
|
164 |
msgstr ""
|
165 |
|
166 |
+
#: includes/class-freemius.php:4866
|
167 |
msgid "Premium %s version was successfully activated."
|
168 |
msgstr ""
|
169 |
|
170 |
+
#: includes/class-freemius.php:4878, includes/class-freemius.php:6711
|
171 |
msgctxt "Used to express elation, enthusiasm, or triumph (especially in electronic communication)."
|
172 |
msgid "W00t"
|
173 |
msgstr ""
|
174 |
|
175 |
+
#: includes/class-freemius.php:4893
|
176 |
msgid "You have a %s license."
|
177 |
msgstr ""
|
178 |
|
179 |
+
#: includes/class-freemius.php:4897, includes/class-freemius.php:13677, includes/class-freemius.php:13688, includes/class-freemius.php:16428, includes/class-freemius.php:16728, includes/class-freemius.php:16793, includes/class-freemius.php:16943
|
180 |
msgctxt "interjection expressing joy or exuberance"
|
181 |
msgid "Yee-haw"
|
182 |
msgstr ""
|
183 |
|
184 |
+
#: includes/class-freemius.php:5161
|
185 |
msgid "%s free trial was successfully cancelled. Since the add-on is premium only it was automatically deactivated. If you like to use it in the future, you'll have to purchase a license."
|
186 |
msgstr ""
|
187 |
|
188 |
+
#: includes/class-freemius.php:5165
|
189 |
msgid "%s is a premium only add-on. You have to purchase a license first before activating the plugin."
|
190 |
msgstr ""
|
191 |
|
192 |
+
#: includes/class-freemius.php:5174, templates/add-ons.php:99, templates/account/partials/addon.php:283
|
193 |
msgid "More information about %s"
|
194 |
msgstr ""
|
195 |
|
196 |
+
#: includes/class-freemius.php:5175
|
197 |
msgid "Purchase License"
|
198 |
msgstr ""
|
199 |
|
200 |
+
#: includes/class-freemius.php:6086, templates/connect.php:161
|
201 |
msgid "You should receive an activation email for %s to your mailbox at %s. Please make sure you click the activation button in that email to %s."
|
202 |
msgstr ""
|
203 |
|
204 |
+
#: includes/class-freemius.php:6090
|
205 |
msgid "start the trial"
|
206 |
msgstr ""
|
207 |
|
208 |
+
#: includes/class-freemius.php:6091, templates/connect.php:165
|
209 |
msgid "complete the install"
|
210 |
msgstr ""
|
211 |
|
212 |
+
#: includes/class-freemius.php:6198
|
213 |
msgid "You are just one step away - %s"
|
214 |
msgstr ""
|
215 |
|
216 |
+
#: includes/class-freemius.php:6201
|
217 |
msgctxt "%s - plugin name. As complete \"PluginX\" activation now"
|
218 |
msgid "Complete \"%s\" Activation Now"
|
219 |
msgstr ""
|
220 |
|
221 |
+
#: includes/class-freemius.php:6278
|
222 |
msgid "We made a few tweaks to the %s, %s"
|
223 |
msgstr ""
|
224 |
|
225 |
+
#: includes/class-freemius.php:6282
|
226 |
msgid "Opt in to make \"%s\" Better!"
|
227 |
msgstr ""
|
228 |
|
229 |
+
#: includes/class-freemius.php:6710
|
230 |
msgid "The upgrade of %s was successfully completed."
|
231 |
msgstr ""
|
232 |
|
233 |
+
#: includes/class-freemius.php:8435, includes/class-fs-plugin-updater.php:581, includes/class-fs-plugin-updater.php:733, includes/class-fs-plugin-updater.php:739, templates/auto-installation.php:32
|
234 |
msgid "Add-On"
|
235 |
msgstr ""
|
236 |
|
237 |
+
#: includes/class-freemius.php:8437, templates/debug.php:349, templates/debug.php:510
|
238 |
msgid "Plugin"
|
239 |
msgstr ""
|
240 |
|
241 |
+
#: includes/class-freemius.php:8438, templates/debug.php:349, templates/debug.php:510, templates/forms/deactivation/form.php:64
|
242 |
msgid "Theme"
|
243 |
msgstr ""
|
244 |
|
245 |
+
#: includes/class-freemius.php:10859
|
246 |
+
msgid "Invalid site details collection."
|
247 |
msgstr ""
|
248 |
|
249 |
+
#: includes/class-freemius.php:10979
|
250 |
msgid "We couldn't find your email address in the system, are you sure it's the right address?"
|
251 |
msgstr ""
|
252 |
|
253 |
+
#: includes/class-freemius.php:10981
|
254 |
msgid "We can't see any active licenses associated with that email address, are you sure it's the right address?"
|
255 |
msgstr ""
|
256 |
|
257 |
+
#: includes/class-freemius.php:11217
|
258 |
msgid "Account is pending activation."
|
259 |
msgstr ""
|
260 |
|
261 |
+
#: includes/class-freemius.php:13659
|
262 |
msgid "%s activation was successfully completed."
|
263 |
msgstr ""
|
264 |
|
265 |
+
#: includes/class-freemius.php:13673
|
266 |
msgid "Your account was successfully activated with the %s plan."
|
267 |
msgstr ""
|
268 |
|
269 |
+
#: includes/class-freemius.php:13684, includes/class-freemius.php:16789
|
270 |
msgid "Your trial has been successfully started."
|
271 |
msgstr ""
|
272 |
|
273 |
+
#: includes/class-freemius.php:14254, includes/class-freemius.php:14306, includes/class-freemius.php:14368
|
274 |
msgid "Couldn't activate %s."
|
275 |
msgstr ""
|
276 |
|
277 |
+
#: includes/class-freemius.php:14255, includes/class-freemius.php:14307, includes/class-freemius.php:14369
|
278 |
msgid "Please contact us with the following message:"
|
279 |
msgstr ""
|
280 |
|
281 |
+
#: includes/class-freemius.php:14718, includes/class-freemius.php:18988
|
282 |
msgid "Upgrade"
|
283 |
msgstr ""
|
284 |
|
285 |
+
#: includes/class-freemius.php:14724
|
286 |
msgid "Start Trial"
|
287 |
msgstr ""
|
288 |
|
289 |
+
#: includes/class-freemius.php:14726
|
290 |
msgid "Pricing"
|
291 |
msgstr ""
|
292 |
|
293 |
+
#: includes/class-freemius.php:14786, includes/class-freemius.php:14788
|
294 |
msgid "Affiliation"
|
295 |
msgstr ""
|
296 |
|
297 |
+
#: includes/class-freemius.php:14808, includes/class-freemius.php:14810, templates/account.php:146, templates/debug.php:314
|
298 |
msgid "Account"
|
299 |
msgstr ""
|
300 |
|
301 |
+
#: includes/class-freemius.php:14821, includes/class-freemius.php:14823, includes/customizer/class-fs-customizer-support-section.php:60
|
302 |
msgid "Contact Us"
|
303 |
msgstr ""
|
304 |
|
305 |
+
#: includes/class-freemius.php:14833, includes/class-freemius.php:14835, includes/class-freemius.php:18998, templates/account.php:96, templates/account/partials/addon.php:37
|
306 |
msgid "Add-Ons"
|
307 |
msgstr ""
|
308 |
|
309 |
+
#: includes/class-freemius.php:14867, templates/pricing.php:97
|
310 |
msgctxt "noun"
|
311 |
msgid "Pricing"
|
312 |
msgstr ""
|
313 |
|
314 |
+
#: includes/class-freemius.php:15061, includes/customizer/class-fs-customizer-support-section.php:67
|
315 |
msgid "Support Forum"
|
316 |
msgstr ""
|
317 |
|
318 |
+
#: includes/class-freemius.php:15846
|
319 |
msgid "Your email has been successfully verified - you are AWESOME!"
|
320 |
msgstr ""
|
321 |
|
322 |
+
#: includes/class-freemius.php:15847
|
323 |
msgctxt "a positive response"
|
324 |
msgid "Right on"
|
325 |
msgstr ""
|
326 |
|
327 |
+
#: includes/class-freemius.php:16419
|
328 |
msgid "Your %s Add-on plan was successfully upgraded."
|
329 |
msgstr ""
|
330 |
|
331 |
+
#: includes/class-freemius.php:16421
|
332 |
msgid "%s Add-on was successfully purchased."
|
333 |
msgstr ""
|
334 |
|
335 |
+
#: includes/class-freemius.php:16424
|
336 |
msgid "Download the latest version"
|
337 |
msgstr ""
|
338 |
|
339 |
+
#: includes/class-freemius.php:16496
|
340 |
msgctxt "%1s - plugin title, %2s - API domain"
|
341 |
msgid "Your server is blocking the access to Freemius' API, which is crucial for %1s synchronization. Please contact your host to whitelist %2s"
|
342 |
msgstr ""
|
343 |
|
344 |
+
#: includes/class-freemius.php:16499, includes/class-freemius.php:16914, includes/class-freemius.php:16979
|
345 |
msgid "Error received from the server:"
|
346 |
msgstr ""
|
347 |
|
348 |
+
#: includes/class-freemius.php:16509
|
349 |
msgid "It seems like one of the authentication parameters is wrong. Update your Public Key, Secret Key & User ID, and try again."
|
350 |
msgstr ""
|
351 |
|
352 |
+
#: includes/class-freemius.php:16691, includes/class-freemius.php:16919, includes/class-freemius.php:16962
|
353 |
msgctxt "something somebody says when they are thinking about what you have just said."
|
354 |
msgid "Hmm"
|
355 |
msgstr ""
|
356 |
|
357 |
+
#: includes/class-freemius.php:16704
|
358 |
msgid "It looks like you are still on the %s plan. If you did upgrade or change your plan, it's probably an issue on our side - sorry."
|
359 |
msgstr ""
|
360 |
|
361 |
+
#: includes/class-freemius.php:16705, templates/account.php:98, templates/add-ons.php:130, templates/account/partials/addon.php:39
|
362 |
msgctxt "trial period"
|
363 |
msgid "Trial"
|
364 |
msgstr ""
|
365 |
|
366 |
+
#: includes/class-freemius.php:16710
|
367 |
msgid "I have upgraded my account but when I try to Sync the License, the plan remains %s."
|
368 |
msgstr ""
|
369 |
|
370 |
+
#: includes/class-freemius.php:16714, includes/class-freemius.php:16771
|
371 |
msgid "Please contact us here"
|
372 |
msgstr ""
|
373 |
|
374 |
+
#: includes/class-freemius.php:16724
|
375 |
msgid "Your plan was successfully upgraded."
|
376 |
msgstr ""
|
377 |
|
378 |
+
#: includes/class-freemius.php:16741
|
379 |
msgid "Your plan was successfully changed to %s."
|
380 |
msgstr ""
|
381 |
|
382 |
+
#: includes/class-freemius.php:16757
|
383 |
msgid "Your license has expired. You can still continue using the free %s forever."
|
384 |
msgstr ""
|
385 |
|
386 |
+
#: includes/class-freemius.php:16759
|
387 |
msgid "Your license has expired. %1$sUpgrade now%2$s to continue using the %3$s without interruptions."
|
388 |
msgstr ""
|
389 |
|
390 |
+
#: includes/class-freemius.php:16767
|
391 |
msgid "Your license has been cancelled. If you think it's a mistake, please contact support."
|
392 |
msgstr ""
|
393 |
|
394 |
+
#: includes/class-freemius.php:16780
|
395 |
msgid "Your license has expired. You can still continue using all the %s features, but you'll need to renew your license to continue getting updates and support."
|
396 |
msgstr ""
|
397 |
|
398 |
+
#: includes/class-freemius.php:16803
|
399 |
msgid "Your free trial has expired. You can still continue using all our free features."
|
400 |
msgstr ""
|
401 |
|
402 |
+
#: includes/class-freemius.php:16805
|
403 |
msgid "Your free trial has expired. %1$sUpgrade now%2$s to continue using the %3$s without interruptions."
|
404 |
msgstr ""
|
405 |
|
406 |
+
#: includes/class-freemius.php:16910
|
407 |
msgid "It looks like the license could not be activated."
|
408 |
msgstr ""
|
409 |
|
410 |
+
#: includes/class-freemius.php:16940
|
411 |
msgid "Your license was successfully activated."
|
412 |
msgstr ""
|
413 |
|
414 |
+
#: includes/class-freemius.php:16966
|
415 |
msgid "It looks like your site currently doesn't have an active license."
|
416 |
msgstr ""
|
417 |
|
418 |
+
#: includes/class-freemius.php:16978
|
419 |
msgid "It looks like the license deactivation failed."
|
420 |
msgstr ""
|
421 |
|
422 |
+
#: includes/class-freemius.php:17006
|
423 |
msgid "Your license was successfully deactivated, you are back to the %s plan."
|
424 |
msgstr ""
|
425 |
|
426 |
+
#: includes/class-freemius.php:17007
|
427 |
msgid "O.K"
|
428 |
msgstr ""
|
429 |
|
430 |
+
#: includes/class-freemius.php:17055
|
431 |
msgid "Your plan was successfully downgraded. Your %s plan license will expire in %s."
|
432 |
msgstr ""
|
433 |
|
434 |
+
#: includes/class-freemius.php:17065
|
435 |
msgid "Seems like we are having some temporary issue with your plan downgrade. Please try again in few minutes."
|
436 |
msgstr ""
|
437 |
|
438 |
+
#: includes/class-freemius.php:17089
|
439 |
msgid "You are already running the %s in a trial mode."
|
440 |
msgstr ""
|
441 |
|
442 |
+
#: includes/class-freemius.php:17100
|
443 |
msgid "You already utilized a trial before."
|
444 |
msgstr ""
|
445 |
|
446 |
+
#: includes/class-freemius.php:17114
|
447 |
msgid "Plan %s do not exist, therefore, can't start a trial."
|
448 |
msgstr ""
|
449 |
|
450 |
+
#: includes/class-freemius.php:17125
|
451 |
msgid "Plan %s does not support a trial period."
|
452 |
msgstr ""
|
453 |
|
454 |
+
#: includes/class-freemius.php:17136
|
455 |
msgid "None of the %s's plans supports a trial period."
|
456 |
msgstr ""
|
457 |
|
458 |
+
#: includes/class-freemius.php:17186
|
459 |
msgid "It looks like you are not in trial mode anymore so there's nothing to cancel :)"
|
460 |
msgstr ""
|
461 |
|
462 |
+
#: includes/class-freemius.php:17237
|
463 |
msgid "Your %s free trial was successfully cancelled."
|
464 |
msgstr ""
|
465 |
|
466 |
+
#: includes/class-freemius.php:17242
|
467 |
msgid "Seems like we are having some temporary issue with your trial cancellation. Please try again in few minutes."
|
468 |
msgstr ""
|
469 |
|
470 |
+
#: includes/class-freemius.php:17533
|
471 |
msgid "Version %s was released."
|
472 |
msgstr ""
|
473 |
|
474 |
+
#: includes/class-freemius.php:17533
|
475 |
msgid "Please download %s."
|
476 |
msgstr ""
|
477 |
|
478 |
+
#: includes/class-freemius.php:17540
|
479 |
msgid "the latest %s version here"
|
480 |
msgstr ""
|
481 |
|
482 |
+
#: includes/class-freemius.php:17545
|
483 |
msgid "New"
|
484 |
msgstr ""
|
485 |
|
486 |
+
#: includes/class-freemius.php:17550
|
487 |
msgid "Seems like you got the latest release."
|
488 |
msgstr ""
|
489 |
|
490 |
+
#: includes/class-freemius.php:17551
|
491 |
msgid "You are all good!"
|
492 |
msgstr ""
|
493 |
|
494 |
+
#: includes/class-freemius.php:17817
|
495 |
msgid "Verification mail was just sent to %s. If you can't find it after 5 min, please check your spam box."
|
496 |
msgstr ""
|
497 |
|
498 |
+
#: includes/class-freemius.php:17952
|
499 |
msgid "Site successfully opted in."
|
500 |
msgstr ""
|
501 |
|
502 |
+
#: includes/class-freemius.php:17953, includes/class-freemius.php:18730
|
503 |
msgid "Awesome"
|
504 |
msgstr ""
|
505 |
|
506 |
+
#: includes/class-freemius.php:17969, templates/forms/optout.php:32
|
507 |
msgid "We appreciate your help in making the %s better by letting us track some usage data."
|
508 |
msgstr ""
|
509 |
|
510 |
+
#: includes/class-freemius.php:17970
|
511 |
msgid "Thank you!"
|
512 |
msgstr ""
|
513 |
|
514 |
+
#: includes/class-freemius.php:17977
|
515 |
msgid "We will no longer be sending any usage data of %s on %s to %s."
|
516 |
msgstr ""
|
517 |
|
518 |
+
#: includes/class-freemius.php:18092
|
519 |
msgid "Please check your mailbox, you should receive an email via %s to confirm the ownership change. From security reasons, you must confirm the change within the next 15 min. If you cannot find the email, please check your spam folder."
|
520 |
msgstr ""
|
521 |
|
522 |
+
#: includes/class-freemius.php:18098
|
523 |
msgid "Thanks for confirming the ownership change. An email was just sent to %s for final approval."
|
524 |
msgstr ""
|
525 |
|
526 |
+
#: includes/class-freemius.php:18103
|
527 |
msgid "%s is the new owner of the account."
|
528 |
msgstr ""
|
529 |
|
530 |
+
#: includes/class-freemius.php:18105
|
531 |
msgctxt "as congratulations"
|
532 |
msgid "Congrats"
|
533 |
msgstr ""
|
534 |
|
535 |
+
#: includes/class-freemius.php:18125
|
536 |
msgid "Sorry, we could not complete the email update. Another user with the same email is already registered."
|
537 |
msgstr ""
|
538 |
|
539 |
+
#: includes/class-freemius.php:18126
|
540 |
msgid "If you would like to give up the ownership of the %s's account to %s click the Change Ownership button."
|
541 |
msgstr ""
|
542 |
|
543 |
+
#: includes/class-freemius.php:18133
|
544 |
msgid "Change Ownership"
|
545 |
msgstr ""
|
546 |
|
547 |
+
#: includes/class-freemius.php:18141
|
548 |
msgid "Your email was successfully updated. You should receive an email with confirmation instructions in few moments."
|
549 |
msgstr ""
|
550 |
|
551 |
+
#: includes/class-freemius.php:18153
|
552 |
msgid "Please provide your full name."
|
553 |
msgstr ""
|
554 |
|
555 |
+
#: includes/class-freemius.php:18158
|
556 |
msgid "Your name was successfully updated."
|
557 |
msgstr ""
|
558 |
|
559 |
+
#: includes/class-freemius.php:18219
|
560 |
msgid "You have successfully updated your %s."
|
561 |
msgstr ""
|
562 |
|
563 |
+
#: includes/class-freemius.php:18359
|
564 |
msgid "Just letting you know that the add-ons information of %s is being pulled from an external server."
|
565 |
msgstr ""
|
566 |
|
567 |
+
#: includes/class-freemius.php:18360
|
568 |
msgctxt "advance notice of something that will need attention."
|
569 |
msgid "Heads up"
|
570 |
msgstr ""
|
571 |
|
572 |
+
#: includes/class-freemius.php:18770
|
573 |
msgctxt "exclamation"
|
574 |
msgid "Hey"
|
575 |
msgstr ""
|
576 |
|
577 |
+
#: includes/class-freemius.php:18770
|
578 |
msgid "How do you like %s so far? Test all our %s premium features with a %d-day free trial."
|
579 |
msgstr ""
|
580 |
|
581 |
+
#: includes/class-freemius.php:18778
|
582 |
msgid "No commitment for %s days - cancel anytime!"
|
583 |
msgstr ""
|
584 |
|
585 |
+
#: includes/class-freemius.php:18779
|
586 |
msgid "No credit card required"
|
587 |
msgstr ""
|
588 |
|
589 |
+
#: includes/class-freemius.php:18786, templates/forms/trial-start.php:53
|
590 |
msgctxt "call to action"
|
591 |
msgid "Start free trial"
|
592 |
msgstr ""
|
593 |
|
594 |
+
#: includes/class-freemius.php:18863
|
595 |
msgid "Hey there, did you know that %s has an affiliate program? If you like the %s you can become our ambassador and earn some cash!"
|
596 |
msgstr ""
|
597 |
|
598 |
+
#: includes/class-freemius.php:18872
|
599 |
msgid "Learn more"
|
600 |
msgstr ""
|
601 |
|
602 |
+
#: includes/class-freemius.php:19022, templates/account.php:398, templates/account.php:501, templates/connect.php:169, templates/connect.php:408, templates/forms/license-activation.php:24, templates/account/partials/addon.php:230
|
603 |
msgid "Activate License"
|
604 |
msgstr ""
|
605 |
|
606 |
+
#: includes/class-freemius.php:19023, templates/account.php:461, templates/account.php:500, templates/account/partials/site.php:256
|
607 |
msgid "Change License"
|
608 |
msgstr ""
|
609 |
|
610 |
+
#: includes/class-freemius.php:19105, templates/account/partials/site.php:161
|
611 |
msgid "Opt Out"
|
612 |
msgstr ""
|
613 |
|
614 |
+
#: includes/class-freemius.php:19107, includes/class-freemius.php:19112, templates/account/partials/site.php:43, templates/account/partials/site.php:161
|
615 |
msgid "Opt In"
|
616 |
msgstr ""
|
617 |
|
618 |
+
#: includes/class-freemius.php:19304
|
619 |
msgid "Please follow these steps to complete the upgrade"
|
620 |
msgstr ""
|
621 |
|
622 |
+
#: includes/class-freemius.php:19308
|
623 |
msgid "Download the latest %s version"
|
624 |
msgstr ""
|
625 |
|
626 |
+
#: includes/class-freemius.php:19312
|
627 |
msgid "Upload and activate the downloaded version"
|
628 |
msgstr ""
|
629 |
|
630 |
+
#: includes/class-freemius.php:19314
|
631 |
msgid "How to upload and activate?"
|
632 |
msgstr ""
|
633 |
|
634 |
+
#: includes/class-freemius.php:19443
|
635 |
msgid "%sClick here%s to choose the sites where you'd like to activate the license on."
|
636 |
msgstr ""
|
637 |
|
638 |
+
#: includes/class-freemius.php:19604
|
639 |
msgid "Auto installation only works for opted-in users."
|
640 |
msgstr ""
|
641 |
|
642 |
+
#: includes/class-freemius.php:19614, includes/class-freemius.php:19647, includes/class-fs-plugin-updater.php:713, includes/class-fs-plugin-updater.php:727
|
643 |
msgid "Invalid module ID."
|
644 |
msgstr ""
|
645 |
|
646 |
+
#: includes/class-freemius.php:19623, includes/class-fs-plugin-updater.php:747
|
647 |
msgid "Premium version already active."
|
648 |
msgstr ""
|
649 |
|
650 |
+
#: includes/class-freemius.php:19630
|
651 |
msgid "You do not have a valid license to access the premium version."
|
652 |
msgstr ""
|
653 |
|
654 |
+
#: includes/class-freemius.php:19637
|
655 |
msgid "Plugin is a \"Serviceware\" which means it does not have a premium code version."
|
656 |
msgstr ""
|
657 |
|
658 |
+
#: includes/class-freemius.php:19655, includes/class-fs-plugin-updater.php:746
|
659 |
msgid "Premium add-on version already installed."
|
660 |
msgstr ""
|
661 |
|
662 |
+
#: includes/class-freemius.php:20000
|
663 |
msgid "View paid features"
|
664 |
msgstr ""
|
665 |
|
666 |
+
#: includes/class-freemius.php:20310
|
667 |
msgid "Thank you so much for using %s and its add-ons!"
|
668 |
msgstr ""
|
669 |
|
670 |
+
#: includes/class-freemius.php:20311
|
671 |
msgid "Thank you so much for using %s!"
|
672 |
msgstr ""
|
673 |
|
674 |
+
#: includes/class-freemius.php:20317
|
675 |
msgid "You've already opted-in to our usage-tracking, which helps us keep improving the %s."
|
676 |
msgstr ""
|
677 |
|
678 |
+
#: includes/class-freemius.php:20321
|
679 |
msgid "Thank you so much for using our products!"
|
680 |
msgstr ""
|
681 |
|
682 |
+
#: includes/class-freemius.php:20322
|
683 |
msgid "You've already opted-in to our usage-tracking, which helps us keep improving them."
|
684 |
msgstr ""
|
685 |
|
686 |
+
#: includes/class-freemius.php:20341
|
687 |
msgid "%s and its add-ons"
|
688 |
msgstr ""
|
689 |
|
690 |
+
#: includes/class-freemius.php:20350
|
691 |
msgid "Products"
|
692 |
msgstr ""
|
693 |
|
694 |
+
#: includes/class-freemius.php:20357, templates/connect.php:259
|
695 |
msgid "Yes"
|
696 |
msgstr ""
|
697 |
|
698 |
+
#: includes/class-freemius.php:20358, templates/connect.php:260
|
699 |
msgid "send me security & feature updates, educational content and offers."
|
700 |
msgstr ""
|
701 |
|
702 |
+
#: includes/class-freemius.php:20359, templates/connect.php:265
|
703 |
msgid "No"
|
704 |
msgstr ""
|
705 |
|
706 |
+
#: includes/class-freemius.php:20361, templates/connect.php:267
|
707 |
msgid "do %sNOT%s send me security & feature updates, educational content and offers."
|
708 |
msgstr ""
|
709 |
|
710 |
+
#: includes/class-freemius.php:20371
|
711 |
msgid "Due to the new %sEU General Data Protection Regulation (GDPR)%s compliance requirements it is required that you provide your explicit consent, again, confirming that you are onboard 🙂"
|
712 |
msgstr ""
|
713 |
|
714 |
+
#: includes/class-freemius.php:20373, templates/connect.php:274
|
715 |
msgid "Please let us know if you'd like us to contact you for security & feature updates, educational content, and occasional offers:"
|
716 |
msgstr ""
|
717 |
|
718 |
+
#: includes/class-freemius.php:20657
|
719 |
msgid "License key is empty."
|
720 |
msgstr ""
|
721 |
|
766 |
msgid "Install Free Version Update Now"
|
767 |
msgstr ""
|
768 |
|
769 |
+
#: includes/fs-plugin-info-dialog.php:404, templates/account.php:452
|
770 |
msgid "Install Update Now"
|
771 |
msgstr ""
|
772 |
|
925 |
msgid "Last Updated"
|
926 |
msgstr ""
|
927 |
|
928 |
+
#: includes/fs-plugin-info-dialog.php:915, templates/account.php:368
|
929 |
msgctxt "x-ago"
|
930 |
msgid "%s ago"
|
931 |
msgstr ""
|
1167 |
msgid "not verified"
|
1168 |
msgstr ""
|
1169 |
|
1170 |
+
#: templates/account.php:368, templates/account/partials/addon.php:116
|
1171 |
+
msgid "Expired"
|
1172 |
+
msgstr ""
|
1173 |
+
|
1174 |
+
#: templates/account.php:420
|
1175 |
msgid "Premium version"
|
1176 |
msgstr ""
|
1177 |
|
1178 |
+
#: templates/account.php:422
|
1179 |
msgid "Free version"
|
1180 |
msgstr ""
|
1181 |
|
1182 |
+
#: templates/account.php:434
|
1183 |
msgid "Verify Email"
|
1184 |
msgstr ""
|
1185 |
|
1186 |
+
#: templates/account.php:445
|
1187 |
msgid "Download %s Version"
|
1188 |
msgstr ""
|
1189 |
|
1190 |
+
#: templates/account.php:459, templates/account.php:640, templates/account/partials/site.php:237, templates/account/partials/site.php:255
|
1191 |
msgctxt "verb"
|
1192 |
msgid "Show"
|
1193 |
msgstr ""
|
1194 |
|
1195 |
+
#: templates/account.php:473
|
1196 |
msgid "What is your %s?"
|
1197 |
msgstr ""
|
1198 |
|
1199 |
+
#: templates/account.php:481, templates/account/billing.php:27
|
1200 |
msgctxt "verb"
|
1201 |
msgid "Edit"
|
1202 |
msgstr ""
|
1203 |
|
1204 |
+
#: templates/account.php:494
|
1205 |
msgid "Sites"
|
1206 |
msgstr ""
|
1207 |
|
1208 |
+
#: templates/account.php:505
|
1209 |
msgid "Search by address"
|
1210 |
msgstr ""
|
1211 |
|
1212 |
+
#: templates/account.php:514, templates/account.php:562, templates/debug.php:226, templates/debug.php:354, templates/debug.php:439, templates/debug.php:476, templates/debug.php:514, templates/debug.php:587, templates/account/payments.php:35, templates/debug/logger.php:21
|
1213 |
msgid "ID"
|
1214 |
msgstr ""
|
1215 |
|
1216 |
+
#: templates/account.php:515, templates/debug.php:357
|
1217 |
msgid "Address"
|
1218 |
msgstr ""
|
1219 |
|
1220 |
+
#: templates/account.php:516
|
1221 |
msgid "License"
|
1222 |
msgstr ""
|
1223 |
|
1224 |
+
#: templates/account.php:517
|
1225 |
msgid "Plan"
|
1226 |
msgstr ""
|
1227 |
|
1228 |
+
#: templates/account.php:565
|
1229 |
msgctxt "as software license"
|
1230 |
msgid "License"
|
1231 |
msgstr ""
|
1232 |
|
1233 |
+
#: templates/account.php:634
|
1234 |
msgctxt "verb"
|
1235 |
msgid "Hide"
|
1236 |
msgstr ""
|
1237 |
|
1238 |
+
#: templates/account.php:669
|
1239 |
msgid "Deactivating your license will block all premium features, but will enable activating the license on another site. Are you sure you want to proceed?"
|
1240 |
msgstr ""
|
1241 |
|
2117 |
msgid "Cancelled"
|
2118 |
msgstr ""
|
2119 |
|
|
|
|
|
|
|
|
|
2120 |
#: templates/account/partials/addon.php:121
|
2121 |
msgid "No expiration"
|
2122 |
msgstr ""
|
sdk/freemius/start.php
CHANGED
@@ -15,7 +15,7 @@
|
|
15 |
*
|
16 |
* @var string
|
17 |
*/
|
18 |
-
$this_sdk_version = '2.1.
|
19 |
|
20 |
#region SDK Selection Logic --------------------------------------------------------------------
|
21 |
|
@@ -179,6 +179,16 @@
|
|
179 |
} else {
|
180 |
$current_theme = wp_get_theme();
|
181 |
$is_newest_sdk_plugin_active = ( $current_theme->stylesheet === $fs_newest_sdk->plugin_path );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
182 |
}
|
183 |
|
184 |
if ( $is_current_sdk_newest &&
|
15 |
*
|
16 |
* @var string
|
17 |
*/
|
18 |
+
$this_sdk_version = '2.1.2';
|
19 |
|
20 |
#region SDK Selection Logic --------------------------------------------------------------------
|
21 |
|
179 |
} else {
|
180 |
$current_theme = wp_get_theme();
|
181 |
$is_newest_sdk_plugin_active = ( $current_theme->stylesheet === $fs_newest_sdk->plugin_path );
|
182 |
+
|
183 |
+
$current_theme_parent = $current_theme->parent();
|
184 |
+
|
185 |
+
/**
|
186 |
+
* If the current theme is a child of the theme that has the newest SDK, this prevents a redirects loop
|
187 |
+
* from happening by keeping the SDK info stored in the `fs_active_plugins` option.
|
188 |
+
*/
|
189 |
+
if ( ! $is_newest_sdk_plugin_active && $current_theme_parent instanceof WP_Theme ) {
|
190 |
+
$is_newest_sdk_plugin_active = ( $fs_newest_sdk->plugin_path === $current_theme_parent->stylesheet );
|
191 |
+
}
|
192 |
}
|
193 |
|
194 |
if ( $is_current_sdk_newest &&
|
sdk/freemius/templates/account.php
CHANGED
@@ -364,8 +364,12 @@
|
|
364 |
<?php endif ?>
|
365 |
<?php if ( is_object( $license ) && ! $license->is_lifetime() ) : ?>
|
366 |
<?php if ( ! $is_active_subscription && ! $license->is_first_payment_pending() ) : ?>
|
|
|
|
|
367 |
<label
|
368 |
-
class="fs-tag
|
|
|
|
|
369 |
<?php elseif ( $is_active_subscription && ! $subscription->is_first_payment_pending() ) : ?>
|
370 |
<label class="fs-tag fs-success"><?php echo esc_html( sprintf( $renews_in_text, human_time_diff( time(), strtotime( $subscription->next_payment ) ) ) ) ?></label>
|
371 |
<?php endif ?>
|
364 |
<?php endif ?>
|
365 |
<?php if ( is_object( $license ) && ! $license->is_lifetime() ) : ?>
|
366 |
<?php if ( ! $is_active_subscription && ! $license->is_first_payment_pending() ) : ?>
|
367 |
+
<?php $is_license_expired = $license->is_expired() ?>
|
368 |
+
<?php $expired_ago_text = ( fs_text_inline( 'Expired', 'expired', $slug ) . ' ' . fs_text_x_inline( '%s ago', 'x-ago', $slug ) ) ?>
|
369 |
<label
|
370 |
+
class="fs-tag <?php echo $is_license_expired ? 'fs-error' : 'fs-warn' ?>"><?php
|
371 |
+
echo esc_html( sprintf( $is_license_expired ? $expired_ago_text : $expires_in_text, human_time_diff( time(), strtotime( $license->expiration ) ) ) )
|
372 |
+
?></label>
|
373 |
<?php elseif ( $is_active_subscription && ! $subscription->is_first_payment_pending() ) : ?>
|
374 |
<label class="fs-tag fs-success"><?php echo esc_html( sprintf( $renews_in_text, human_time_diff( time(), strtotime( $subscription->next_payment ) ) ) ) ?></label>
|
375 |
<?php endif ?>
|
sdk/freemius/templates/account/partials/addon.php
CHANGED
@@ -61,7 +61,7 @@
|
|
61 |
$plan = $fs_addon->get_plan();
|
62 |
$is_active_subscription = ( is_object( $subscription ) && $subscription->is_active() );
|
63 |
$is_paid_trial = $fs_addon->is_paid_trial();
|
64 |
-
$show_upgrade = ( ! $is_paying && ! $is_paid_trial && ! $fs_addon->_has_premium_license() );
|
65 |
$is_current_license_expired = is_object( $license ) && $license->is_expired();
|
66 |
}
|
67 |
?>
|
@@ -220,7 +220,7 @@
|
|
220 |
}
|
221 |
|
222 |
if ( 0 == count( $buttons ) ) {
|
223 |
-
if ( $fs_addon->is_premium() ) {
|
224 |
$fs_addon->_add_license_activation_dialog_box();
|
225 |
|
226 |
$buttons[] = fs_ui_get_action_button(
|
61 |
$plan = $fs_addon->get_plan();
|
62 |
$is_active_subscription = ( is_object( $subscription ) && $subscription->is_active() );
|
63 |
$is_paid_trial = $fs_addon->is_paid_trial();
|
64 |
+
$show_upgrade = ( $fs_addon->has_paid_plan() && ! $is_paying && ! $is_paid_trial && ! $fs_addon->_has_premium_license() );
|
65 |
$is_current_license_expired = is_object( $license ) && $license->is_expired();
|
66 |
}
|
67 |
?>
|
220 |
}
|
221 |
|
222 |
if ( 0 == count( $buttons ) ) {
|
223 |
+
if ( $show_upgrade && $fs_addon->is_premium() ) {
|
224 |
$fs_addon->_add_license_activation_dialog_box();
|
225 |
|
226 |
$buttons[] = fs_ui_get_action_button(
|
sdk/freemius/templates/add-ons.php
CHANGED
@@ -55,7 +55,7 @@
|
|
55 |
$has_free_plan = false;
|
56 |
$has_paid_plan = false;
|
57 |
|
58 |
-
$result = $fs->get_api_plugin_scope()->get( "/addons/{$addon->id}/pricing.json?type=visible" );
|
59 |
if ( ! isset( $result->error ) ) {
|
60 |
$plans = $result->plans;
|
61 |
|
@@ -89,6 +89,10 @@
|
|
89 |
|
90 |
}
|
91 |
}
|
|
|
|
|
|
|
|
|
92 |
}
|
93 |
?>
|
94 |
<li class="fs-card fs-addon" data-slug="<?php echo $addon->slug ?>">
|
55 |
$has_free_plan = false;
|
56 |
$has_paid_plan = false;
|
57 |
|
58 |
+
$result = $fs->get_api_plugin_scope()->get( $fs->add_show_pending( "/addons/{$addon->id}/pricing.json?type=visible" ) );
|
59 |
if ( ! isset( $result->error ) ) {
|
60 |
$plans = $result->plans;
|
61 |
|
89 |
|
90 |
}
|
91 |
}
|
92 |
+
|
93 |
+
if ( ! $has_paid_plan && ! $has_free_plan ) {
|
94 |
+
continue;
|
95 |
+
}
|
96 |
}
|
97 |
?>
|
98 |
<li class="fs-card fs-addon" data-slug="<?php echo $addon->slug ?>">
|
sdk/freemius/templates/checkout.php
CHANGED
@@ -121,7 +121,7 @@
|
|
121 |
|
122 |
$fs_user = Freemius::_get_user_by_email( $current_user->user_email );
|
123 |
|
124 |
-
if ( is_object( $fs_user ) ) {
|
125 |
$context_params = array_merge( $context_params, FS_Security::instance()->get_context_params(
|
126 |
$fs_user,
|
127 |
$timestamp,
|
@@ -233,7 +233,7 @@
|
|
233 |
// passed via query string or hard coded into the child page, it depends on your needs).
|
234 |
src = base_url + '/?<?php echo http_build_query( $query_params ) ?>#' + encodeURIComponent(document.location.href),
|
235 |
// Append the i-frame into the DOM.
|
236 |
-
frame = $('<i' + 'frame " src="' + src + '" width="100%" height="' + frame_height + 'px" scrolling="no" frameborder="0" style="background: transparent;"><\/i' + 'frame>')
|
237 |
.appendTo('#frame');
|
238 |
|
239 |
FS.PostMessage.init(base_url, [frame[0]]);
|
121 |
|
122 |
$fs_user = Freemius::_get_user_by_email( $current_user->user_email );
|
123 |
|
124 |
+
if ( is_object( $fs_user ) && $fs_user->is_verified() ) {
|
125 |
$context_params = array_merge( $context_params, FS_Security::instance()->get_context_params(
|
126 |
$fs_user,
|
127 |
$timestamp,
|
233 |
// passed via query string or hard coded into the child page, it depends on your needs).
|
234 |
src = base_url + '/?<?php echo http_build_query( $query_params ) ?>#' + encodeURIComponent(document.location.href),
|
235 |
// Append the i-frame into the DOM.
|
236 |
+
frame = $('<i' + 'frame " src="' + src + '" width="100%" height="' + frame_height + 'px" scrolling="no" frameborder="0" style="background: transparent; width: 1px; min-width: 100%;"><\/i' + 'frame>')
|
237 |
.appendTo('#frame');
|
238 |
|
239 |
FS.PostMessage.init(base_url, [frame[0]]);
|
sdk/freemius/templates/connect.php
CHANGED
@@ -253,6 +253,17 @@
|
|
253 |
<a class="show-license-resend-modal show-license-resend-modal-<?php echo $fs->get_unique_affix() ?>"
|
254 |
href="#"><?php fs_esc_html_echo_inline( "Can't find your license key?", 'cant-find-license-key', $slug ); ?></a>
|
255 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
256 |
<?php
|
257 |
$send_updates_text = sprintf(
|
258 |
'%s<span class="action-description"> - %s</span>',
|
@@ -718,11 +729,14 @@
|
|
718 |
// Redirect to the "Account" page and sync the license.
|
719 |
window.location.href = resultObj.next_page;
|
720 |
} else {
|
|
|
|
|
721 |
// Show error.
|
722 |
$('.fs-content').prepend('<p class="fs-error">' + (resultObj.error.message ? resultObj.error.message : resultObj.error) + '</p>');
|
723 |
-
|
724 |
-
resetLoadingMode();
|
725 |
}
|
|
|
|
|
|
|
726 |
}
|
727 |
});
|
728 |
|
253 |
<a class="show-license-resend-modal show-license-resend-modal-<?php echo $fs->get_unique_affix() ?>"
|
254 |
href="#"><?php fs_esc_html_echo_inline( "Can't find your license key?", 'cant-find-license-key', $slug ); ?></a>
|
255 |
</div>
|
256 |
+
|
257 |
+
<?php
|
258 |
+
/**
|
259 |
+
* Allows developers to include custom HTML after the license input container.
|
260 |
+
*
|
261 |
+
* @author Vova Feldman
|
262 |
+
* @since 2.1.2
|
263 |
+
*/
|
264 |
+
$fs->do_action( 'connect/after_license_input' );
|
265 |
+
?>
|
266 |
+
|
267 |
<?php
|
268 |
$send_updates_text = sprintf(
|
269 |
'%s<span class="action-description"> - %s</span>',
|
729 |
// Redirect to the "Account" page and sync the license.
|
730 |
window.location.href = resultObj.next_page;
|
731 |
} else {
|
732 |
+
resetLoadingMode();
|
733 |
+
|
734 |
// Show error.
|
735 |
$('.fs-content').prepend('<p class="fs-error">' + (resultObj.error.message ? resultObj.error.message : resultObj.error) + '</p>');
|
|
|
|
|
736 |
}
|
737 |
+
},
|
738 |
+
error: function () {
|
739 |
+
resetLoadingMode();
|
740 |
}
|
741 |
});
|
742 |
|
sdk/freemius/templates/contact.php
CHANGED
@@ -98,7 +98,7 @@
|
|
98 |
src = base_url + '/contact/?<?php echo http_build_query($query_params) ?>#' + encodeURIComponent(document.location.href),
|
99 |
|
100 |
// Append the i-frame into the DOM.
|
101 |
-
frame = $('<i' + 'frame " src="' + src + '" width="100%" height="' + frame_height + 'px" scrolling="no" frameborder="0" style="background: transparent;"><\/i' + 'frame>')
|
102 |
.appendTo('#frame');
|
103 |
|
104 |
FS.PostMessage.init(base_url);
|
98 |
src = base_url + '/contact/?<?php echo http_build_query($query_params) ?>#' + encodeURIComponent(document.location.href),
|
99 |
|
100 |
// Append the i-frame into the DOM.
|
101 |
+
frame = $('<i' + 'frame " src="' + src + '" width="100%" height="' + frame_height + 'px" scrolling="no" frameborder="0" style="background: transparent; width: 1px; min-width: 100%;"><\/i' + 'frame>')
|
102 |
.appendTo('#frame');
|
103 |
|
104 |
FS.PostMessage.init(base_url);
|
sdk/freemius/templates/pricing.php
CHANGED
@@ -127,7 +127,7 @@
|
|
127 |
src = base_url + '/pricing/?<?php echo http_build_query( $query_params ) ?>#' + encodeURIComponent(document.location.href),
|
128 |
|
129 |
// Append the I-frame into the DOM.
|
130 |
-
frame = $('<i' + 'frame " src="' + src + '" width="100%" height="' + frame_height + 'px" scrolling="no" frameborder="0" style="background: transparent;"><\/i' + 'frame>')
|
131 |
.appendTo('#frame');
|
132 |
|
133 |
FS.PostMessage.init(base_url, [frame[0]]);
|
127 |
src = base_url + '/pricing/?<?php echo http_build_query( $query_params ) ?>#' + encodeURIComponent(document.location.href),
|
128 |
|
129 |
// Append the I-frame into the DOM.
|
130 |
+
frame = $('<i' + 'frame " src="' + src + '" width="100%" height="' + frame_height + 'px" scrolling="no" frameborder="0" style="background: transparent; width: 1px; min-width: 100%;"><\/i' + 'frame>')
|
131 |
.appendTo('#frame');
|
132 |
|
133 |
FS.PostMessage.init(base_url, [frame[0]]);
|
sdk/freemius/templates/tabs.php
CHANGED
@@ -26,7 +26,11 @@
|
|
26 |
foreach ( $menu_items as $priority => $items ) {
|
27 |
foreach ( $items as $item ) {
|
28 |
if ( ! $item['show_submenu'] ) {
|
29 |
-
|
|
|
|
|
|
|
|
|
30 |
continue;
|
31 |
}
|
32 |
}
|
26 |
foreach ( $menu_items as $priority => $items ) {
|
27 |
foreach ( $items as $item ) {
|
28 |
if ( ! $item['show_submenu'] ) {
|
29 |
+
$submenu_name = ('wp-support-forum' === $item['menu_slug']) ?
|
30 |
+
'support' :
|
31 |
+
$item['menu_slug'];
|
32 |
+
|
33 |
+
if ( ! $is_free_wp_org_theme || ! $fs->is_submenu_item_visible( $submenu_name, true ) ) {
|
34 |
continue;
|
35 |
}
|
36 |
}
|
sdk/wsal-freemius.php
CHANGED
@@ -32,27 +32,32 @@ if ( file_exists( dirname( __FILE__ ) . '/freemius/start.php' ) ) {
|
|
32 |
require_once dirname( __FILE__ ) . '/freemius/start.php';
|
33 |
|
34 |
// Check anonymous mode.
|
35 |
-
// $is_anonymous = ( true === get_site_option( 'wpsal_anonymous_mode', true ) );
|
36 |
$freemius_state = get_site_option( 'wsal_freemius_state', 'anonymous' );
|
37 |
$is_anonymous = ( 'anonymous' === $freemius_state || 'skipped' === $freemius_state );
|
38 |
$is_premium = false;
|
39 |
$is_anonymous = $is_premium ? false : $is_anonymous;
|
40 |
|
41 |
$wsal_freemius = fs_dynamic_init( array(
|
42 |
-
'id'
|
43 |
-
'slug'
|
44 |
-
'type'
|
45 |
-
'public_key'
|
46 |
-
'is_premium'
|
47 |
-
'has_addons'
|
48 |
-
'has_paid_plans'
|
49 |
-
'
|
50 |
-
'
|
51 |
-
'
|
52 |
-
'network' => true,
|
53 |
),
|
54 |
-
'
|
55 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
) );
|
57 |
}
|
58 |
|
32 |
require_once dirname( __FILE__ ) . '/freemius/start.php';
|
33 |
|
34 |
// Check anonymous mode.
|
|
|
35 |
$freemius_state = get_site_option( 'wsal_freemius_state', 'anonymous' );
|
36 |
$is_anonymous = ( 'anonymous' === $freemius_state || 'skipped' === $freemius_state );
|
37 |
$is_premium = false;
|
38 |
$is_anonymous = $is_premium ? false : $is_anonymous;
|
39 |
|
40 |
$wsal_freemius = fs_dynamic_init( array(
|
41 |
+
'id' => '94',
|
42 |
+
'slug' => 'wp-security-audit-log',
|
43 |
+
'type' => 'plugin',
|
44 |
+
'public_key' => 'pk_d602740d3088272d75906045af9fa',
|
45 |
+
'is_premium' => $is_premium,
|
46 |
+
'has_addons' => false,
|
47 |
+
'has_paid_plans' => true,
|
48 |
+
'trial' => array(
|
49 |
+
'days' => 7,
|
50 |
+
'is_require_payment' => false,
|
|
|
51 |
),
|
52 |
+
'has_affiliation' => false,
|
53 |
+
'menu' => array(
|
54 |
+
'slug' => 'wsal-auditlog',
|
55 |
+
'support' => false,
|
56 |
+
'affiliation' => false,
|
57 |
+
'network' => true,
|
58 |
+
),
|
59 |
+
'anonymous_mode' => $is_anonymous,
|
60 |
+
'live' => true,
|
61 |
) );
|
62 |
}
|
63 |
|
wp-security-audit-log.php
CHANGED
@@ -4,7 +4,7 @@
|
|
4 |
* Plugin URI: http://www.wpsecurityauditlog.com/
|
5 |
* Description: Identify WordPress security issues before they become a problem. Keep track of everything happening on your WordPress including WordPress users activity. Similar to Windows Event Log and Linux Syslog, WP Security Audit Log generates a security alert for everything that happens on your WordPress blogs and websites. Use the Audit Log Viewer included in the plugin to see all the security alerts.
|
6 |
* Author: WP White Security
|
7 |
-
* Version: 3.2.
|
8 |
* Text Domain: wp-security-audit-log
|
9 |
* Author URI: http://www.wpsecurityauditlog.com/
|
10 |
* License: GPL2
|
@@ -39,7 +39,7 @@ if ( ! function_exists( 'wsal_freemius' ) ) {
|
|
39 |
* @since 2.7.0
|
40 |
*/
|
41 |
if ( file_exists( plugin_dir_path( __FILE__ ) . '/sdk/wsal-freemius.php' ) ) {
|
42 |
-
require_once
|
43 |
}
|
44 |
|
45 |
/**
|
@@ -54,12 +54,12 @@ if ( ! function_exists( 'wsal_freemius' ) ) {
|
|
54 |
*
|
55 |
* @var string
|
56 |
*/
|
57 |
-
public $version = '3.2.
|
58 |
|
59 |
// Plugin constants.
|
60 |
-
const PLG_CLS_PRFX
|
61 |
const MIN_PHP_VERSION = '5.3.0';
|
62 |
-
const OPT_PRFX
|
63 |
|
64 |
/**
|
65 |
* Views supervisor.
|
@@ -187,13 +187,13 @@ if ( ! function_exists( 'wsal_freemius' ) ) {
|
|
187 |
$this->autoloader->Register( self::PLG_CLS_PRFX, $this->GetBaseDir() . 'classes' . DIRECTORY_SEPARATOR );
|
188 |
|
189 |
// Load dependencies.
|
190 |
-
$this->views
|
191 |
-
$this->alerts
|
192 |
-
$this->sensors
|
193 |
-
$this->settings
|
194 |
$this->constants = new WSAL_ConstantManager( $this );
|
195 |
$this->licensing = new WSAL_LicenseManager( $this );
|
196 |
-
$this->widgets
|
197 |
|
198 |
// Listen for installation event.
|
199 |
register_activation_hook( __FILE__, array( $this, 'Install' ) );
|
@@ -237,6 +237,9 @@ if ( ! function_exists( 'wsal_freemius' ) ) {
|
|
237 |
// Add filters to customize freemius welcome message.
|
238 |
wsal_freemius()->add_filter( 'connect_message', array( $this, 'wsal_freemius_connect_message' ), 10, 6 );
|
239 |
wsal_freemius()->add_filter( 'connect_message_on_update', array( $this, 'wsal_freemius_update_connect_message' ), 10, 6 );
|
|
|
|
|
|
|
240 |
}
|
241 |
|
242 |
/**
|
@@ -251,9 +254,15 @@ if ( ! function_exists( 'wsal_freemius' ) ) {
|
|
251 |
// Redirect to main page.
|
252 |
$redirect = '';
|
253 |
if ( ! $this->IsMultisite() ) {
|
254 |
-
|
|
|
255 |
} else {
|
256 |
-
|
|
|
|
|
|
|
|
|
|
|
257 |
}
|
258 |
wp_safe_redirect( $redirect );
|
259 |
exit();
|
@@ -268,15 +277,15 @@ if ( ! function_exists( 'wsal_freemius' ) ) {
|
|
268 |
public function set_allowed_html_tags() {
|
269 |
// Set allowed HTML tags.
|
270 |
$this->allowed_html_tags = array(
|
271 |
-
'a'
|
272 |
-
'href'
|
273 |
-
'title'
|
274 |
'target' => array(),
|
275 |
),
|
276 |
-
'br'
|
277 |
-
'em'
|
278 |
'strong' => array(),
|
279 |
-
'p'
|
280 |
'class' => array(),
|
281 |
),
|
282 |
);
|
@@ -325,9 +334,10 @@ if ( ! function_exists( 'wsal_freemius' ) ) {
|
|
325 |
* @param string $freemius_link - Freemius link.
|
326 |
* @return string
|
327 |
*/
|
328 |
-
function wsal_freemius_connect_message( $message, $user_first_name, $plugin_title, $user_login, $site_link, $freemius_link ) {
|
329 |
$freemius_link = '<a href="https://www.wpsecurityauditlog.com/support-documentation/what-is-freemius/" target="_blank" tabindex="1">freemius.com</a>';
|
330 |
return sprintf(
|
|
|
331 |
esc_html__( 'Hey %1$s', 'wp-security-audit-log' ) . ',<br>' .
|
332 |
esc_html__( 'Never miss an important update! Opt-in to our security and feature updates notifications, and non-sensitive diagnostic tracking with freemius.com.', 'wp-security-audit-log' ) .
|
333 |
'<br /><br /><strong>' . esc_html__( 'Note: ', 'wp-security-audit-log' ) . '</strong>' .
|
@@ -351,10 +361,12 @@ if ( ! function_exists( 'wsal_freemius' ) ) {
|
|
351 |
* @param string $freemius_link - Freemius link.
|
352 |
* @return string
|
353 |
*/
|
354 |
-
function wsal_freemius_update_connect_message( $message, $user_first_name, $plugin_title, $user_login, $site_link, $freemius_link ) {
|
355 |
$freemius_link = '<a href="https://www.wpsecurityauditlog.com/support-documentation/what-is-freemius/" target="_blank" tabindex="1">freemius.com</a>';
|
356 |
return sprintf(
|
|
|
357 |
esc_html__( 'Hey %1$s', 'wp-security-audit-log' ) . ',<br>' .
|
|
|
358 |
esc_html__( 'Please help us improve %2$s! If you opt-in, some non-sensitive data about your usage of %2$s will be sent to %5$s, a diagnostic tracking service we use. If you skip this, that\'s okay! %2$s will still work just fine.', 'wp-security-audit-log' ) .
|
359 |
'<br /><br /><strong>' . esc_html__( 'Note: ', 'wp-security-audit-log' ) . '</strong>' .
|
360 |
esc_html__( 'NO AUDIT LOG ACTIVITY & DATA IS SENT BACK TO OUR SERVERS.', 'wp-security-audit-log' ),
|
@@ -366,6 +378,45 @@ if ( ! function_exists( 'wsal_freemius' ) ) {
|
|
366 |
);
|
367 |
}
|
368 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
369 |
/**
|
370 |
* Start to trigger the events after installation.
|
371 |
*
|
@@ -373,13 +424,13 @@ if ( ! function_exists( 'wsal_freemius' ) ) {
|
|
373 |
*/
|
374 |
public function Init() {
|
375 |
// Start listening to events.
|
376 |
-
|
377 |
|
378 |
if ( $this->settings->IsArchivingEnabled() ) {
|
379 |
// Check the current page.
|
380 |
$get_page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
|
381 |
if ( ( ! isset( $get_page ) || 'wsal-auditlog' !== $get_page ) && ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) ) {
|
382 |
-
$selected_db
|
383 |
$selected_db_user = (int) get_transient( 'wsal_wp_selected_db_user' );
|
384 |
if ( $selected_db && ( get_current_user_id() === $selected_db_user ) ) {
|
385 |
// Delete the transient.
|
@@ -496,15 +547,10 @@ if ( ! function_exists( 'wsal_freemius' ) ) {
|
|
496 |
$options_table = new WSAL_Models_Option();
|
497 |
if ( ! $options_table->IsInstalled() ) {
|
498 |
$options_table->Install();
|
|
|
499 |
// Setting the prunig date with the old value or the default value.
|
500 |
$pruning_date = $this->settings->GetPruningDate();
|
501 |
$this->settings->SetPruningDate( $pruning_date );
|
502 |
-
|
503 |
-
$pruning_enabled = $this->settings->IsPruningLimitEnabled();
|
504 |
-
$this->settings->SetPruningLimitEnabled( $pruning_enabled );
|
505 |
-
// Setting the prunig limit with the old value or the default value.
|
506 |
-
$pruning_limit = $this->settings->GetPruningLimit();
|
507 |
-
$this->settings->SetPruningLimit( $pruning_limit );
|
508 |
}
|
509 |
$log_404 = $this->GetGlobalOption( 'log-404' );
|
510 |
// If old setting is empty enable 404 logging by default.
|
@@ -591,14 +637,8 @@ if ( ! function_exists( 'wsal_freemius' ) ) {
|
|
591 |
}
|
592 |
|
593 |
// Setting the prunig date with the old value or the default value.
|
594 |
-
$pruning_date = $this->settings->GetPruningDate();
|
595 |
-
$this->settings->SetPruningDate( $pruning_date );
|
596 |
-
|
597 |
-
// $pruning_enabled = $this->settings->IsPruningLimitEnabled();
|
598 |
-
$this->settings->SetPruningLimitEnabled( true );
|
599 |
-
// Setting the prunig limit with the old value or the default value.
|
600 |
-
$pruning_limit = $this->settings->GetPruningLimit();
|
601 |
-
$this->settings->SetPruningLimit( $pruning_limit );
|
602 |
|
603 |
$old_disabled = $this->GetGlobalOption( 'disabled-alerts' );
|
604 |
// If old setting is empty disable alert 2099 by default.
|
@@ -641,17 +681,24 @@ if ( ! function_exists( 'wsal_freemius' ) ) {
|
|
641 |
// Do version-to-version specific changes.
|
642 |
if ( '0.0.0' !== $old_version && -1 === version_compare( $old_version, $new_version ) ) {
|
643 |
/**
|
644 |
-
*
|
645 |
-
*
|
646 |
-
*
|
|
|
647 |
*/
|
648 |
if ( version_compare( $old_version, '2.6.5', '<' ) && version_compare( $new_version, '2.6.4', '>' ) ) {
|
649 |
// Update External DB password on plugin update.
|
650 |
$this->update_external_db_password();
|
651 |
}
|
652 |
|
653 |
-
// Update pruning alerts option.
|
654 |
-
$this->settings->
|
|
|
|
|
|
|
|
|
|
|
|
|
655 |
|
656 |
// Dismiss privacy notice.
|
657 |
$this->views->FindByClassName( 'WSAL_Views_AuditLog' )->DismissNotice( 'wsal-privacy-notice-3.2' );
|
@@ -659,22 +706,63 @@ if ( ! function_exists( 'wsal_freemius' ) ) {
|
|
659 |
/**
|
660 |
* IMPORTANT: VERSION SPECIFIC UPDATE
|
661 |
*
|
662 |
-
* It only needs to run when old version of the plugin is
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
663 |
*
|
664 |
* @since 3.2.2.2
|
665 |
*/
|
666 |
if ( version_compare( $old_version, '3.0.0', '>' ) ) {
|
667 |
-
//
|
668 |
-
if (
|
669 |
-
//
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
674 |
}
|
675 |
-
|
676 |
-
// Remove connect account notice of Freemius.
|
677 |
-
FS_Admin_Notices::instance( 'wp-security-audit-log' )->remove_sticky( 'connect_account' );
|
678 |
}
|
679 |
}
|
680 |
}
|
@@ -869,8 +957,6 @@ if ( ! function_exists( 'wsal_freemius' ) ) {
|
|
869 |
get_option( 'WPPH_PLUGIN_ALLOW_ACCESS' )
|
870 |
);
|
871 |
$s = get_option( 'wpph_plugin_settings' );
|
872 |
-
// $this->settings->SetPruningDate(($s->daysToKeep ? $s->daysToKeep : 30) . ' days');
|
873 |
-
// $this->settings->SetPruningLimit(min($s->eventsToKeep, 1));
|
874 |
$this->settings->SetViewPerPage( max( $s->showEventsViewList, 5 ) );
|
875 |
$this->settings->SetWidgetsEnabled( ! ! $s->showDW );
|
876 |
}
|
4 |
* Plugin URI: http://www.wpsecurityauditlog.com/
|
5 |
* Description: Identify WordPress security issues before they become a problem. Keep track of everything happening on your WordPress including WordPress users activity. Similar to Windows Event Log and Linux Syslog, WP Security Audit Log generates a security alert for everything that happens on your WordPress blogs and websites. Use the Audit Log Viewer included in the plugin to see all the security alerts.
|
6 |
* Author: WP White Security
|
7 |
+
* Version: 3.2.3
|
8 |
* Text Domain: wp-security-audit-log
|
9 |
* Author URI: http://www.wpsecurityauditlog.com/
|
10 |
* License: GPL2
|
39 |
* @since 2.7.0
|
40 |
*/
|
41 |
if ( file_exists( plugin_dir_path( __FILE__ ) . '/sdk/wsal-freemius.php' ) ) {
|
42 |
+
require_once plugin_dir_path( __FILE__ ) . '/sdk/wsal-freemius.php';
|
43 |
}
|
44 |
|
45 |
/**
|
54 |
*
|
55 |
* @var string
|
56 |
*/
|
57 |
+
public $version = '3.2.3';
|
58 |
|
59 |
// Plugin constants.
|
60 |
+
const PLG_CLS_PRFX = 'WSAL_';
|
61 |
const MIN_PHP_VERSION = '5.3.0';
|
62 |
+
const OPT_PRFX = 'wsal-';
|
63 |
|
64 |
/**
|
65 |
* Views supervisor.
|
187 |
$this->autoloader->Register( self::PLG_CLS_PRFX, $this->GetBaseDir() . 'classes' . DIRECTORY_SEPARATOR );
|
188 |
|
189 |
// Load dependencies.
|
190 |
+
$this->views = new WSAL_ViewManager( $this );
|
191 |
+
$this->alerts = new WSAL_AlertManager( $this );
|
192 |
+
$this->sensors = new WSAL_SensorManager( $this );
|
193 |
+
$this->settings = new WSAL_Settings( $this );
|
194 |
$this->constants = new WSAL_ConstantManager( $this );
|
195 |
$this->licensing = new WSAL_LicenseManager( $this );
|
196 |
+
$this->widgets = new WSAL_WidgetManager( $this );
|
197 |
|
198 |
// Listen for installation event.
|
199 |
register_activation_hook( __FILE__, array( $this, 'Install' ) );
|
237 |
// Add filters to customize freemius welcome message.
|
238 |
wsal_freemius()->add_filter( 'connect_message', array( $this, 'wsal_freemius_connect_message' ), 10, 6 );
|
239 |
wsal_freemius()->add_filter( 'connect_message_on_update', array( $this, 'wsal_freemius_update_connect_message' ), 10, 6 );
|
240 |
+
wsal_freemius()->add_filter( 'trial_promotion_message', array( $this, 'freemius_trial_promotion_message' ), 10, 1 );
|
241 |
+
wsal_freemius()->add_filter( 'show_first_trial_after_n_sec', array( $this, 'change_show_first_trial_period' ), 10, 1 );
|
242 |
+
wsal_freemius()->add_filter( 'reshow_trial_after_every_n_sec', array( $this, 'change_reshow_trial_period' ), 10, 1 );
|
243 |
}
|
244 |
|
245 |
/**
|
254 |
// Redirect to main page.
|
255 |
$redirect = '';
|
256 |
if ( ! $this->IsMultisite() ) {
|
257 |
+
// By default, set it to wizard setup page.
|
258 |
+
$redirect = add_query_arg( 'page', 'wsal-setup', admin_url( 'index.php' ) );
|
259 |
} else {
|
260 |
+
// Only allow super-admins on multisite to view wizard.
|
261 |
+
if ( $this->settings->CurrentUserCan( 'edit' ) ) {
|
262 |
+
$redirect = add_query_arg( 'page', 'wsal-setup', admin_url( 'index.php' ) );
|
263 |
+
} else {
|
264 |
+
$redirect = add_query_arg( 'page', 'wsal-auditlog', admin_url( 'admin.php' ) );
|
265 |
+
}
|
266 |
}
|
267 |
wp_safe_redirect( $redirect );
|
268 |
exit();
|
277 |
public function set_allowed_html_tags() {
|
278 |
// Set allowed HTML tags.
|
279 |
$this->allowed_html_tags = array(
|
280 |
+
'a' => array(
|
281 |
+
'href' => array(),
|
282 |
+
'title' => array(),
|
283 |
'target' => array(),
|
284 |
),
|
285 |
+
'br' => array(),
|
286 |
+
'em' => array(),
|
287 |
'strong' => array(),
|
288 |
+
'p' => array(
|
289 |
'class' => array(),
|
290 |
),
|
291 |
);
|
334 |
* @param string $freemius_link - Freemius link.
|
335 |
* @return string
|
336 |
*/
|
337 |
+
public function wsal_freemius_connect_message( $message, $user_first_name, $plugin_title, $user_login, $site_link, $freemius_link ) {
|
338 |
$freemius_link = '<a href="https://www.wpsecurityauditlog.com/support-documentation/what-is-freemius/" target="_blank" tabindex="1">freemius.com</a>';
|
339 |
return sprintf(
|
340 |
+
/* translators: Username */
|
341 |
esc_html__( 'Hey %1$s', 'wp-security-audit-log' ) . ',<br>' .
|
342 |
esc_html__( 'Never miss an important update! Opt-in to our security and feature updates notifications, and non-sensitive diagnostic tracking with freemius.com.', 'wp-security-audit-log' ) .
|
343 |
'<br /><br /><strong>' . esc_html__( 'Note: ', 'wp-security-audit-log' ) . '</strong>' .
|
361 |
* @param string $freemius_link - Freemius link.
|
362 |
* @return string
|
363 |
*/
|
364 |
+
public function wsal_freemius_update_connect_message( $message, $user_first_name, $plugin_title, $user_login, $site_link, $freemius_link ) {
|
365 |
$freemius_link = '<a href="https://www.wpsecurityauditlog.com/support-documentation/what-is-freemius/" target="_blank" tabindex="1">freemius.com</a>';
|
366 |
return sprintf(
|
367 |
+
/* translators: Username */
|
368 |
esc_html__( 'Hey %1$s', 'wp-security-audit-log' ) . ',<br>' .
|
369 |
+
/* translators: 1: Plugin name. 2: Freemius link. */
|
370 |
esc_html__( 'Please help us improve %2$s! If you opt-in, some non-sensitive data about your usage of %2$s will be sent to %5$s, a diagnostic tracking service we use. If you skip this, that\'s okay! %2$s will still work just fine.', 'wp-security-audit-log' ) .
|
371 |
'<br /><br /><strong>' . esc_html__( 'Note: ', 'wp-security-audit-log' ) . '</strong>' .
|
372 |
esc_html__( 'NO AUDIT LOG ACTIVITY & DATA IS SENT BACK TO OUR SERVERS.', 'wp-security-audit-log' ),
|
378 |
);
|
379 |
}
|
380 |
|
381 |
+
/**
|
382 |
+
* Filter trial message of Freemius.
|
383 |
+
*
|
384 |
+
* @param string $message – Trial message.
|
385 |
+
* @return string
|
386 |
+
* @since 3.2.3
|
387 |
+
*/
|
388 |
+
public function freemius_trial_promotion_message( $message ) {
|
389 |
+
return sprintf(
|
390 |
+
/* translators: Plugin name */
|
391 |
+
__( 'Get a free 7-day trial of the premium edition of %s. No credit card required, no commitments!', 'wp-security-audit-log' ),
|
392 |
+
'<strong>' . __( 'WP Security Audit Log', 'wp-security-audit-log' ) . '</strong>'
|
393 |
+
);
|
394 |
+
}
|
395 |
+
|
396 |
+
/**
|
397 |
+
* Filter the time period to show the first trial message.
|
398 |
+
* Display it after 20 days.
|
399 |
+
*
|
400 |
+
* @param int $day_in_sec – Time period in seconds.
|
401 |
+
* @return int
|
402 |
+
* @since 3.2.3
|
403 |
+
*/
|
404 |
+
public function change_show_first_trial_period( $day_in_sec ) {
|
405 |
+
return 20 * DAY_IN_SECONDS;
|
406 |
+
}
|
407 |
+
|
408 |
+
/**
|
409 |
+
* Filter the time period to re-show the trial message.
|
410 |
+
* Display it after 60 days.
|
411 |
+
*
|
412 |
+
* @param int $thirty_days_in_sec – Time period in seconds.
|
413 |
+
* @return int
|
414 |
+
* @since 3.2.3
|
415 |
+
*/
|
416 |
+
public function change_reshow_trial_period( $thirty_days_in_sec ) {
|
417 |
+
return 60 * DAY_IN_SECONDS;
|
418 |
+
}
|
419 |
+
|
420 |
/**
|
421 |
* Start to trigger the events after installation.
|
422 |
*
|
424 |
*/
|
425 |
public function Init() {
|
426 |
// Start listening to events.
|
427 |
+
self::GetInstance()->sensors->HookEvents();
|
428 |
|
429 |
if ( $this->settings->IsArchivingEnabled() ) {
|
430 |
// Check the current page.
|
431 |
$get_page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
|
432 |
if ( ( ! isset( $get_page ) || 'wsal-auditlog' !== $get_page ) && ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) ) {
|
433 |
+
$selected_db = get_transient( 'wsal_wp_selected_db' );
|
434 |
$selected_db_user = (int) get_transient( 'wsal_wp_selected_db_user' );
|
435 |
if ( $selected_db && ( get_current_user_id() === $selected_db_user ) ) {
|
436 |
// Delete the transient.
|
547 |
$options_table = new WSAL_Models_Option();
|
548 |
if ( ! $options_table->IsInstalled() ) {
|
549 |
$options_table->Install();
|
550 |
+
|
551 |
// Setting the prunig date with the old value or the default value.
|
552 |
$pruning_date = $this->settings->GetPruningDate();
|
553 |
$this->settings->SetPruningDate( $pruning_date );
|
|
|
|
|
|
|
|
|
|
|
|
|
554 |
}
|
555 |
$log_404 = $this->GetGlobalOption( 'log-404' );
|
556 |
// If old setting is empty enable 404 logging by default.
|
637 |
}
|
638 |
|
639 |
// Setting the prunig date with the old value or the default value.
|
640 |
+
// $pruning_date = $this->settings->GetPruningDate();
|
641 |
+
// $this->settings->SetPruningDate( $pruning_date );
|
|
|
|
|
|
|
|
|
|
|
|
|
642 |
|
643 |
$old_disabled = $this->GetGlobalOption( 'disabled-alerts' );
|
644 |
// If old setting is empty disable alert 2099 by default.
|
681 |
// Do version-to-version specific changes.
|
682 |
if ( '0.0.0' !== $old_version && -1 === version_compare( $old_version, $new_version ) ) {
|
683 |
/**
|
684 |
+
* IMPORTANT: VERSION SPECIFIC UPDATE
|
685 |
+
*
|
686 |
+
* It only needs to run when old version of the plugin is less than 2.6.5
|
687 |
+
* & the plugin is being updated to version 2.6.5 or later versions.
|
688 |
*/
|
689 |
if ( version_compare( $old_version, '2.6.5', '<' ) && version_compare( $new_version, '2.6.4', '>' ) ) {
|
690 |
// Update External DB password on plugin update.
|
691 |
$this->update_external_db_password();
|
692 |
}
|
693 |
|
694 |
+
// Update pruning alerts option if purning limit is enabled for backwards compatibility.
|
695 |
+
if ( $this->settings->IsPruningLimitEnabled() ) {
|
696 |
+
$pruning_date = '6';
|
697 |
+
$pruning_unit = 'months';
|
698 |
+
$this->settings->SetPruningDate( $pruning_date . ' ' . $pruning_unit );
|
699 |
+
$this->settings->SetPruningDateEnabled( true );
|
700 |
+
$this->settings->SetPruningLimitEnabled( false );
|
701 |
+
}
|
702 |
|
703 |
// Dismiss privacy notice.
|
704 |
$this->views->FindByClassName( 'WSAL_Views_AuditLog' )->DismissNotice( 'wsal-privacy-notice-3.2' );
|
706 |
/**
|
707 |
* IMPORTANT: VERSION SPECIFIC UPDATE
|
708 |
*
|
709 |
+
* It only needs to run when old version of the plugin is less than 3.2.3
|
710 |
+
* & the plugin is being updated to version 3.2.3 or later versions.
|
711 |
+
*
|
712 |
+
* @since 3.2.3
|
713 |
+
*/
|
714 |
+
if ( version_compare( $old_version, '3.2.3', '<' ) && version_compare( $new_version, '3.2.2', '>' ) ) {
|
715 |
+
$this->getConnector()->getAdapter( 'Option' )->update_value_column();
|
716 |
+
|
717 |
+
// Migrate file scan options to WSAL Options table.
|
718 |
+
$initial_scan_option = 'wsal_is_initial_scan_';
|
719 |
+
$initial_scan_option_migrate = 'is_initial_scan_';
|
720 |
+
$local_scan_files = 'wsal_local_files_';
|
721 |
+
$local_scan_files_migrate = 'local_files_';
|
722 |
+
|
723 |
+
for ( $index = 0; $index < 7; $index++ ) {
|
724 |
+
// Initial scan option.
|
725 |
+
$initial_option_value = get_site_option( $initial_scan_option . $index, 'yes' );
|
726 |
+
delete_site_option( $initial_scan_option . $index );
|
727 |
+
|
728 |
+
// If option already does not exist then create it.
|
729 |
+
if ( ! $this->GetGlobalOption( $initial_scan_option_migrate . $index, false ) ) {
|
730 |
+
$this->SetGlobalOption( $initial_scan_option_migrate . $index, $initial_option_value );
|
731 |
+
}
|
732 |
+
|
733 |
+
// Local files option.
|
734 |
+
$local_files_value = get_site_option( $local_scan_files . $index, array() );
|
735 |
+
delete_site_option( $local_scan_files . $index );
|
736 |
+
|
737 |
+
// If option already does not exist then create it.
|
738 |
+
if ( ! $this->GetGlobalOption( $local_scan_files_migrate . $index, false ) ) {
|
739 |
+
$this->SetGlobalOption( $local_scan_files_migrate . $index, $local_files_value );
|
740 |
+
}
|
741 |
+
}
|
742 |
+
}
|
743 |
+
|
744 |
+
/**
|
745 |
+
* IMPORTANT: VERSION SPECIFIC UPDATE
|
746 |
+
*
|
747 |
+
* It only needs to run when old version of the plugin is later than 3.0.0.
|
748 |
*
|
749 |
* @since 3.2.2.2
|
750 |
*/
|
751 |
if ( version_compare( $old_version, '3.0.0', '>' ) ) {
|
752 |
+
// If the freemius state option does not exists then run this update.
|
753 |
+
if ( false === get_site_option( 'wsal_freemius_state', false ) ) {
|
754 |
+
// Check if the user has opted-in.
|
755 |
+
if ( wsal_freemius()->is_registered() ) {
|
756 |
+
// Update freemius state.
|
757 |
+
update_site_option( 'wsal_freemius_state', 'in' );
|
758 |
+
} else {
|
759 |
+
// Update freemius state.
|
760 |
+
update_site_option( 'wsal_freemius_state', 'skipped' );
|
761 |
+
}
|
762 |
+
|
763 |
+
// Remove connect account notice of Freemius.
|
764 |
+
FS_Admin_Notices::instance( 'wp-security-audit-log' )->remove_sticky( 'connect_account' );
|
765 |
}
|
|
|
|
|
|
|
766 |
}
|
767 |
}
|
768 |
}
|
957 |
get_option( 'WPPH_PLUGIN_ALLOW_ACCESS' )
|
958 |
);
|
959 |
$s = get_option( 'wpph_plugin_settings' );
|
|
|
|
|
960 |
$this->settings->SetViewPerPage( max( $s->showEventsViewList, 5 ) );
|
961 |
$this->settings->SetWidgetsEnabled( ! ! $s->showDW );
|
962 |
}
|