diff --git a/.claude/settings.local.json b/.claude/settings.local.json index bea9a805..df07712a 100755 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -70,7 +70,10 @@ "Bash(git -C /var/www/html add:*)", "Bash(git -C /var/www/html diff --cached --stat)", "Bash(git -C /var/www/html commit -m \"$\\(cat <<''EOF''\nAdd 6 reusable page templates with ACF integration\n\nIntroduces layout-focused templates for marketing pages:\n- Content with Sidebar: 70/30 grid with callout boxes\n- Alternating Blocks: Zigzag image/text sections\n- Service Detail: Hero + features grid + FAQ accordion\n- Card Grid: Configurable 2/3/4 column card layouts\n- Long-Form Article: Clean reading layout with related links\n- Landing Page: Conversion-focused with benefits and testimonial\n\nEach template has corresponding ACF field groups for content\nmanagement. Sample pages created under /page-template-examples/.\n\nšŸ¤– Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")", - "Bash(cat:*)" + "Bash(cat:*)", + "Bash(rsync -av /var/www/vhosts/homeprozrealestate.com/httpdocs/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-query.php /var/www/vhosts/homeprozrealestate.com/staging/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-query.php && rsync -av /var/www/vhosts/homeprozrealestate.com/httpdocs/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-cluster.php /var/www/vhosts/homeprozrealestate.com/staging/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-cluster.php)", + "Bash(crontab:*)", + "Bash(rsync:*)" ], "deny": [], "ask": [] diff --git a/.gitignore b/.gitignore index 5a473d30..af4cdfd7 100755 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,15 @@ Thumbs.db # Debug wp-content/debug.log +wp-content/debug.log.* + +# Runtime image caches (regenerable, capped by mls-image-cache-cap) +wp-content/cache/transformed-images/ +wp-content/uploads/mls-thumbnails/ +wp-content/uploads/mls-listings/ + +# Local Claude CLI tooling +node_modules/claude-cli/ # Vite *.local diff --git a/CLAUDE.md b/CLAUDE.md index ed2ed1da..5da1b8f0 100755 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,6 +13,18 @@ Custom WordPress theme for HomeProz Real Estate (Albert Lea, MN). Dark/rust bran 7. **No custom animations** - keep it static and fast 8. **ASK before architectural decisions** 9. **No git commits unless asked** - commits are for checkpoints before major work or major milestones, not for small single-file changes +10. **Sync to staging** - after modifying theme or plugin files, sync them to `/var/www/vhosts/homeprozrealestate.com/staging/` using rsync + +## Version Control Policy + +Git is a snapshot tool and the historical record of what changed on the site. **If it's not in git, it may as well not exist.** + +When asked to commit, commit **everything except build artifacts** — do not pick a "scope" or hand-select files. The point is the snapshot. + +- **Commit:** all source (PHP, SCSS, JS), configs, `package.json`/`package-lock.json`, `db_content_updates/`, `node_modules/`, `dist/`, DB snapshots (`*.sql.gz`), plugins, themes, `CLAUDE.md`. `node_modules/` and `dist/` are tracked intentionally — see comments in `.gitignore`. +- **Do not commit:** runtime caches (`wp-content/cache/transformed-images/`), log files (`wp-content/debug.log*`), and other transient/regenerable runtime output. These belong in `.gitignore`. + +If you find untracked files in scope of a commit, include them. If something looks ambiguous, default to committing it — under-tracking loses history; over-tracking is reversible. ## Build @@ -73,3 +85,23 @@ $url = add_query_arg('property', urlencode($title), home_url('/contact/')); ## Page Classes `Home_Page`, `Properties_Archive`, `Single_Property`, `About_Page`, `Contact_Page`, `Blog_Archive`, `Single_Post`, `Agents_Archive`, `Single_Agent`, `Search_Page`, `Error_404` + +## MLS Property Overrides + +### Force a non-HomeProz listing to appear as HomeProz + +Some properties (e.g., LandProz listings) may need to appear on the HomeProz site. The `is_homeproz` flag overrides the office name check. + +1. Find the property's `listing_key`: +```bash +wp --allow-root db query "SELECT listing_key, listing_id, street_name, city, list_office_name, is_homeproz FROM wp_mls_properties WHERE listing_id LIKE '%%'" +``` + +2. Set the override flag: +```bash +wp --allow-root db query "UPDATE wp_mls_properties SET is_homeproz = 1 WHERE listing_key = ''" +``` + +3. Document the change in `db_content_updates/` per the Database Content Changes policy. + +**Example**: 121 Main St, Glenville (NST7785198) is listed under "LandProz Real Estate, LLC" but appears on HomeProz via `is_homeproz = 1`. diff --git a/db_content_updates/2026-01-05_SEO_albert_lea_landing_page.md b/db_content_updates/2026-01-05_SEO_albert_lea_landing_page.md old mode 100644 new mode 100755 diff --git a/db_content_updates/2026-01-06_agent-testimonials.md b/db_content_updates/2026-01-06_agent-testimonials.md old mode 100644 new mode 100755 diff --git a/db_content_updates/2026-01-06_favicon-management.md b/db_content_updates/2026-01-06_favicon-management.md old mode 100644 new mode 100755 diff --git a/db_content_updates/2026-01-06_mls-ssl-skip-config.md b/db_content_updates/2026-01-06_mls-ssl-skip-config.md old mode 100644 new mode 100755 diff --git a/db_content_updates/2026-01-12_22-37_property-inquiry-form-reorder.md b/db_content_updates/2026-01-12_22-37_property-inquiry-form-reorder.md new file mode 100755 index 00000000..6c10a124 --- /dev/null +++ b/db_content_updates/2026-01-12_22-37_property-inquiry-form-reorder.md @@ -0,0 +1,138 @@ +# Property Inquiry Form Field Reorder + +**Date:** 2026-01-12 +**Purpose:** Reorder Contact Form 7 "Property Inquiry Form" fields so Additional Comments appears after Name/Email/Phone +**Status:** Applied to dev on 2026-01-12 + +## Background + +The property inquiry form should have this field order: +1. Your Inquiry (readonly display message) +2. Your Name +3. Email / Phone (side by side) +4. Additional Comments +5. Submit button + +Previously, Additional Comments was above the contact fields. + +## Changes Required + +### Via WP Admin (Recommended) + +1. Go to WP Admin > Contact > Forms +2. Edit "Property Inquiry Form" +3. Reorder the form fields as shown below +4. Save the form + +### New Form Structure + +``` +
+ +
+
+ +[hidden listing-key] +[hidden listing-id] +[hidden property-address] +[hidden property-price] +[hidden property-url] +[hidden default-message] +[hidden agent-email] +[hidden agent-name] + +
+
+ + [text* your-name] +
+
+ +
+
+ + [email* your-email] +
+
+ + [tel* your-phone] +
+
+ +
+ + [textarea comments placeholder "Any specific questions or information you'd like to know..."] +
+ +[submit class:btn class:btn-primary class:btn-lg "Send Inquiry"] +``` + +### Via SQL (Alternative) + +**Important:** CF7 stores the form structure in `wp_postmeta._form`, not `wp_posts.post_content`. + +First, find the form ID: +```sql +SELECT ID, post_title FROM wp_posts +WHERE post_type = 'wpcf7_contact_form' +AND post_title = 'Property Inquiry Form'; +-- Result: ID = 156 (in dev) +``` + +Then update the `_form` meta with the new form structure: +```sql +UPDATE wp_postmeta +SET meta_value = '
+ +
+
+ +[hidden listing-key] +[hidden listing-id] +[hidden property-address] +[hidden property-price] +[hidden property-url] +[hidden default-message] +[hidden agent-email] +[hidden agent-name] + +
+
+ + [text* your-name] +
+
+ +
+
+ + [email* your-email] +
+
+ + [tel* your-phone] +
+
+ +
+ + [textarea comments placeholder "Any specific questions or information you would like to know..."] +
+ +[submit class:btn class:btn-primary class:btn-lg "Send Inquiry"]' +WHERE post_id = (SELECT ID FROM wp_posts WHERE post_type = 'wpcf7_contact_form' AND post_title = 'Property Inquiry Form') +AND meta_key = '_form'; +``` + +## Related Code Changes + +The following theme files were also updated to support this change: +- `page-property-inquiry.php` - Updated fallback form field order, added agent lookup, split display vs submission messages +- `inc/wpcf7-hooks.php` - Updated HomeProz listing detection to use office name +- `template-parts/property/property-agent.php` - Updated to use listing key for inquiry URL + +## Why + +- Better UX: Users should enter their contact info before typing additional comments +- The display message shown to users no longer includes MLS# (cleaner) +- The submitted message includes MLS#, property URL, and user comments for agent reference diff --git a/db_content_updates/2026-01-12_agent-mls-id-assignments.md b/db_content_updates/2026-01-12_agent-mls-id-assignments.md new file mode 100755 index 00000000..7fc5e08a --- /dev/null +++ b/db_content_updates/2026-01-12_agent-mls-id-assignments.md @@ -0,0 +1,35 @@ +# Agent MLS ID Assignments + +**Date:** 2026-01-12 +**Purpose:** Assign HomeProz agent MLS IDs to agent profiles + +## Changes Made + +Updated `agent_mls_id` ACF field for agents to match MLS Grid listing agent IDs. + +## SQL Commands + +```sql +-- Assign NST503517070 to Davy Villarreal (ID 129) and Jordan Mullenbach (ID 130) +UPDATE wp_postmeta +SET meta_value = 'NST503517070' +WHERE post_id IN (129, 130) +AND meta_key = 'agent_mls_id'; +``` + +## Final State + +| Agent ID | Agent Name | MLS ID | +|----------|------------|--------| +| 128 | Anna Rahn | NST503517068 | +| 129 | Davy Villarreal | NST503517070 | +| 130 | Jordan Mullenbach | NST503517070 | +| 131 | Lily Dulitz | NST503517068 | + +## Why + +HomeProz has 2 listing agent MLS IDs in the MLS Grid data: +- NST503517068 (2 properties) +- NST503517070 (2 properties) + +These were assigned to agents so property cards can display the correct agent information. diff --git a/db_content_updates/2026-01-20_remove-legacy-property-posts.md b/db_content_updates/2026-01-20_remove-legacy-property-posts.md new file mode 100755 index 00000000..71de7b49 --- /dev/null +++ b/db_content_updates/2026-01-20_remove-legacy-property-posts.md @@ -0,0 +1,65 @@ +# Remove Legacy Property Posts + +**Date**: 2026-01-20 +**Type**: Content Deletion +**Priority**: Required before or after code deployment + +## Summary + +The legacy manual property entry system has been deprecated. All properties now come exclusively from the MLS sync. This requires deleting the manually-created property posts and their associated data. + +## What Changed + +The following legacy system components were removed from the codebase: +- `property` custom post type registration +- `single-property.php` template +- `property-card.php` template part +- ACF "Property Details" field group +- Agent listings section from `single-agent.php` + +## Database Changes Required on Production + +### 1. Delete Legacy Property Posts + +Run this WP-CLI command to delete the legacy property posts: + +```bash +wp --allow-root post delete 24 35 60 85 125 --force +``` + +These were the legacy posts: +- ID 24: "Geneva, MN - Double Lot with Shop" +- ID 35: "115 N Newton Ave, Albert Lea, MN" +- ID 60: "411 Court St, Albert Lea, MN" +- ID 85: "1224 Saint Joseph Ave, Albert Lea, MN" +- ID 125: "15131 800th Ave, Glenville, MN" + +### 2. Clean Up Orphaned Post Meta + +After deleting the posts, clean up any orphaned meta data: + +```bash +wp --allow-root db query "DELETE pm FROM wp_postmeta pm LEFT JOIN wp_posts p ON pm.post_id = p.ID WHERE p.ID IS NULL" +``` + +### 3. Flush Rewrite Rules + +After code deployment, flush rewrite rules to remove the property slug: + +```bash +wp --allow-root rewrite flush +``` + +## Verification + +After completing these steps, verify: + +1. The `/properties/` archive page still works (MLS-based) +2. Agent profile pages no longer show a "Current Listings" section (expected - removed) +3. No 404 errors from old property URLs (will naturally 404 since posts deleted) + +## Notes + +- The `/properties/` URL now exclusively serves MLS data via `archive-property.php` +- Individual property URLs use the `?listing=XXXXX` query parameter for MLS listings +- Agent pages no longer display properties; this was intentional as the legacy linking system is deprecated diff --git a/db_content_updates/2026-01-21_17-34_split-about-team-pages.md b/db_content_updates/2026-01-21_17-34_split-about-team-pages.md new file mode 100755 index 00000000..d87afe35 --- /dev/null +++ b/db_content_updates/2026-01-21_17-34_split-about-team-pages.md @@ -0,0 +1,130 @@ +# Split About and Team Pages + Blog Menu + +**Date**: 2026-01-21 +**Type**: Page Template Split + New Page Creation + Menu Updates +**Status**: IMPLEMENTED IN DEV + +## Summary + +The About page has been split into two separate pages: +- **About Page** - Company story, additional WYSIWYG content area, and CTA +- **Team Page** - Agent grid, broker info, and CTA + +Additionally: +- **Blog** added to navigation menu +- Blog templates updated to use consistent archive-hero styling + +## Code Changes + +- Created `page-team.php` - New Team Page template +- Modified `page-about.php` - Removed team/broker sections, added WYSIWYG content section +- Created `template-parts/content/content-team.scss` - Team page styles +- Updated `template-parts/content/content-about.scss` - Added styles for additional content section +- Updated `inc/template-functions.php` - Added Team_Page body class +- Updated `src/main.scss` - Added team SCSS import +- Updated `home.php` - Blog index uses archive-hero for consistency +- Updated `archive.php` - Category/tag archives use archive-hero for consistency +- Created `page-results.php` - Results Page template for sold properties +- Created `template-parts/content/content-results.scss` - Results page styles + +## Database Changes (Already Applied in Dev) + +The following changes were made directly to the dev database and need to be replicated in production: + +### 1. Team Page Created + +**Page ID**: 256 +**Title**: Our Team +**Slug**: team +**Template**: page-team.php + +```sql +-- Create page +INSERT INTO wp_posts (post_author, post_date, post_date_gmt, post_content, post_title, post_excerpt, post_status, comment_status, ping_status, post_name, post_type, post_modified, post_modified_gmt, to_ping, pinged, post_content_filtered) +VALUES (1, NOW(), UTC_TIMESTAMP(), '', 'Our Team', '', 'publish', 'closed', 'closed', 'team', 'page', NOW(), UTC_TIMESTAMP(), '', '', ''); + +-- Set page template (use the actual page ID from above) +INSERT INTO wp_postmeta (post_id, meta_key, meta_value) VALUES (LAST_INSERT_ID(), '_wp_page_template', 'page-team.php'); +``` + +### 2. Menu Item Added to Primary Menu + +Team added after About in the Primary Menu: + +**Menu Order**: +1. Properties (0) +2. About (3) +3. Team (4) - NEW +4. Results (5) - NEW +5. Resources (6) +6. Blog (7) - NEW +7. Contact (8) + +```sql +-- Shift existing items down (adjust IDs for production) +-- Resources menu item: update menu_order from 4 to 5 +-- Contact menu item: update menu_order from 5 to 6 + +-- Create nav_menu_item for Team (adjust page ID for production) +INSERT INTO wp_posts (post_author, post_date, post_date_gmt, post_content, post_title, post_excerpt, post_status, comment_status, ping_status, post_name, post_type, menu_order, post_modified, post_modified_gmt, to_ping, pinged, post_content_filtered) +VALUES (1, NOW(), UTC_TIMESTAMP(), '', 'Team', '', 'publish', 'closed', 'closed', 'team-menu', 'nav_menu_item', 4, NOW(), UTC_TIMESTAMP(), '', '', ''); + +-- Add to Primary Menu term relationship +-- Add required meta: _menu_item_type, _menu_item_object_id, _menu_item_object, etc. +``` + +### 3. Blog Menu Item Added + +Blog page (ID 9, already exists) added to Primary Menu. + +### 4. Results Page Created + +**Page ID**: 259 +**Title**: Our Results +**Slug**: results +**Template**: page-results.php + +Displays sold/closed properties from MLS sync and manual entries, sorted by close date (most recent first). + +## Production Deployment Steps + +1. Deploy code changes (theme files) +2. Run `npm run build` in theme directory +3. Either: + - **Option A**: Manually create Team page in WordPress admin, assign template, add to menu + - **Option B**: Run SQL statements above with adjusted IDs + +### Manual Steps (Option A - Recommended) + +1. Go to **Pages > Add New** +2. Title: `Our Team` +3. Slug: `team` +4. Template: **Team Page** +5. Publish + +6. Go to **Appearance > Menus** +7. Select Primary Menu +8. Add "Our Team" page (set custom label to "Team") +9. Add "Blog" page +10. Order: Properties, About, Team, Resources, Blog, Contact +11. Save Menu + +## Optional ACF Fields for Team Page + +| Field | Default Value | +|-------|---------------| +| `hero_title` | "Our Team" | +| `hero_subtitle` | "A dedicated group of real estate professionals committed to your success." | +| `hero_background` | (none) | +| `broker_title` | "Broker Information" | +| `broker_text` | HomeProz broker details | +| `cta_title` | "Ready to Work With Us?" | +| `cta_text` | "Contact our team today..." | +| `cta_button_text` | "Get in Touch" | +| `cta_button_url` | /contact/ | + +## Notes + +- Agent ordering on Team page respects the `menu_order` field (drag-drop sortable in admin) +- Disabled agents are automatically excluded +- The About page retains its existing ACF fields diff --git a/db_content_updates/2026-01-21_18-15_blog-enhancements.md b/db_content_updates/2026-01-21_18-15_blog-enhancements.md new file mode 100755 index 00000000..bc6ab2f0 --- /dev/null +++ b/db_content_updates/2026-01-21_18-15_blog-enhancements.md @@ -0,0 +1,67 @@ +# Blog Enhancements + +**Date**: 2026-01-21 +**Type**: Template Updates + ACF Field Addition +**Status**: IMPLEMENTED IN DEV + +## Summary + +Enhanced single blog post pages with additional sections and added Agent author capability. + +## Code Changes + +### Templates +- `single.php` - Added three new sections below post content: + 1. Enhanced Next/Prev navigation with thumbnails + 2. Related Posts section (always shows, falls back to recent posts) + 3. Featured Properties section (3 active MLS listings) + +- `template-parts/content/content-single.php` - Added agent author display in post meta + +- `template-parts/content/content-single.scss` - Added styles for: + - Post navigation with thumbnails + - Featured properties grid + - Author meta styling + +### ACF Fields +- Added "Post Author" field group for blog posts: + - Field: `post_agent_author` (post_object linking to Agent CPT) + - Location: Sidebar of post edit screen + - Only shows active (non-disabled) agents in dropdown + +### Functions +- Added `homeproz_filter_agent_post_object()` filter to exclude disabled agents from author dropdown +- Removed comments functionality site-wide + +## Features + +### Agent Author on Blog Posts +- In post editor sidebar, select an agent as the post author +- Author name displays in post meta with link to agent profile +- If agent is later disabled, name still shows but link is removed +- Only active agents appear in the dropdown selector + +### Enhanced Post Navigation +- Shows Previous/Next post with thumbnail images +- Falls back to placeholder icon if no featured image +- Responsive grid layout + +### Related Posts +- Shows 3 posts from same category +- Falls back to 3 recent posts if no category matches +- Always displays something (unless only 1 post exists) + +### Featured Properties +- Shows 3 active MLS listings below blog content +- "View All Properties" button links to /properties/ +- Helps drive traffic from blog to listings + +## Agent Disabled Flag Behavior + +The existing `agent_disabled` ACF field controls: +1. **Team Page**: Disabled agents hidden from grid +2. **Agent Archive**: Disabled agents excluded +3. **Agent Profile**: Returns 404 for disabled agents +4. **Property Cards**: Shows office contact instead of disabled agent +5. **Blog Author Dropdown**: Only active agents shown (NEW) +6. **Blog Author Display**: Disabled agent names show without link (NEW) diff --git a/db_content_updates/2026-01-21_manual-property-system.md b/db_content_updates/2026-01-21_manual-property-system.md new file mode 100755 index 00000000..6122dd2a --- /dev/null +++ b/db_content_updates/2026-01-21_manual-property-system.md @@ -0,0 +1,77 @@ +# Manual Property Entry System + +**Date**: 2026-01-21 +**Type**: Schema Change + New Feature + +## Summary + +Added the ability to manually enter properties that integrate seamlessly with MLS-synced listings. Manual properties can override MLS listings (same MLS ID), support cloning from existing MLS data, and include geocoding for addresses. + +## Schema Changes + +New table `wp_mls_properties_manual` created automatically by the MLS plugin on activation/upgrade. + +The table will be created automatically when the plugin runs - no manual SQL needed. + +## New Custom Post Type + +**CPT**: `manual_property` +**Menu**: "Manual Properties" in WordPress admin + +## ACF Field Group + +ACF fields are registered programmatically (no JSON import needed). Fields will appear automatically on the Manual Property edit screen. + +## How to Use + +### Add a Manual Property + +1. Go to **Manual Properties > Add Property** in WordPress admin +2. Fill in property details across the tabs: + - Basic Info: Status, Price, Type, HomeProz checkbox, Featured toggle + - Location: Address (geocoded automatically), City, State, ZIP + - Details: Beds, Baths, Square Feet, etc. + - Description: Public remarks + - Media: Upload property photos + - Agent: Select from Agent CPT + - Dates: List date, close date, etc. +3. Publish the property + +### Clone from MLS + +1. Go to **Manual Properties > Add Property** +2. Enter an MLS # in the "Clone from MLS Listing" box +3. Click "Clone Listing" +4. Images will be downloaded and fields pre-populated +5. Review and modify as needed, then publish + +### Override an MLS Listing + +1. Create a manual property +2. Set the MLS # field to the MLS ID you want to override +3. Publish +4. The manual version will appear in search results instead of the MLS-synced version + +## Dependencies + +- ACF Pro (already installed) +- MLS by HansonXyz plugin (updated in this release) + +## Files Changed + +Plugin files (MLS plugin): +- `mls-by-hansonxyz.php` - Added table constant, class includes +- `includes/class-mls-db.php` - Added manual properties table schema +- `includes/class-mls-query.php` - Modified to include manual properties in queries +- `includes/class-mls-image-endpoint.php` - Handle manual property images +- `includes/class-mls-manual-property.php` - NEW: CPT, ACF fields, sync logic +- `includes/class-mls-geocoder.php` - NEW: Address geocoding via Nominatim +- `admin/js/manual-property.js` - NEW: Clone from MLS functionality +- `admin/css/manual-property.css` - NEW: Admin styles + +## Notes + +- Manual properties use WordPress Media Library for images (not MLS media cache) +- Geocoding uses free Nominatim API (rate limited, cached for 30 days) +- Manual property listing keys follow format: `MANUAL-{post_id}` +- Properties with `listing_id` set will override MLS listings with matching ID diff --git a/db_content_updates/2026-01-23_about-page-acf-fields.md b/db_content_updates/2026-01-23_about-page-acf-fields.md new file mode 100644 index 00000000..73fbdef1 --- /dev/null +++ b/db_content_updates/2026-01-23_about-page-acf-fields.md @@ -0,0 +1,37 @@ +# About Page ACF Fields Update + +**Date:** 2026-01-23 +**Author:** Claude Code + +## Summary + +Added a new ACF WYSIWYG field to the About page to separate the second content section from the main page body. Previously, the page body content was appearing in both sections (duplicate content). + +## Changes + +### Content Structure (After) + +- **Top Story Section** (next to image): Uses standard WordPress page body content (`the_content()`) +- **Additional Content Section** (below): Uses new ACF field `about_additional_content` + +### ACF Field Added + +**Additional Content** - `about_additional_content` +- WYSIWYG field +- Displayed in a separate section below the story section +- For extended company information + +## Production Sync Instructions + +1. Deploy the updated files: + - `wp-content/themes/homeproz/inc/acf-fields.php` + - `wp-content/themes/homeproz/page-about.php` + +2. In WordPress Admin, edit the About page: + - Keep the main story content in the standard WordPress page body editor + - Add any additional content to the new "Additional Content" ACF field below + +## Files Modified + +- `wp-content/themes/homeproz/inc/acf-fields.php` - Added `about_additional_content` field +- `wp-content/themes/homeproz/page-about.php` - Top section now uses `the_content()`, bottom section uses ACF field diff --git a/db_content_updates/README.md b/db_content_updates/README.md old mode 100644 new mode 100755 diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json index be757be2..d2842b1d 100755 --- a/node_modules/.package-lock.json +++ b/node_modules/.package-lock.json @@ -1,5 +1,5 @@ { - "name": "html", + "name": "httpdocs", "lockfileVersion": 3, "requires": true, "packages": { @@ -19,6 +19,13 @@ "node": ">=18" } }, + "node_modules/claude-cli": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/claude-cli/-/claude-cli-1.0.5.tgz", + "integrity": "sha512-v/8f6BKedfus1npGTyX8AIYp0ldRo5FMwzRbPCen0zv2m+00Qrna46czEoYK6tupJcrbnzVwrQYRbKOxmhv36A==", + "deprecated": "The official Claude Code package is available at @anthropic-ai/claude-code", + "license": "ISC" + }, "node_modules/playwright": { "version": "1.57.0", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.57.0.tgz", diff --git a/package-lock.json b/package-lock.json index 683130cf..4331746c 100755 --- a/package-lock.json +++ b/package-lock.json @@ -1,9 +1,12 @@ { - "name": "html", + "name": "httpdocs", "lockfileVersion": 3, "requires": true, "packages": { "": { + "dependencies": { + "claude-cli": "^1.0.5" + }, "devDependencies": { "@playwright/test": "^1.57.0" } @@ -24,6 +27,13 @@ "node": ">=18" } }, + "node_modules/claude-cli": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/claude-cli/-/claude-cli-1.0.5.tgz", + "integrity": "sha512-v/8f6BKedfus1npGTyX8AIYp0ldRo5FMwzRbPCen0zv2m+00Qrna46czEoYK6tupJcrbnzVwrQYRbKOxmhv36A==", + "deprecated": "The official Claude Code package is available at @anthropic-ai/claude-code", + "license": "ISC" + }, "node_modules/fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", diff --git a/package.json b/package.json index a67ae416..6cc7620f 100755 --- a/package.json +++ b/package.json @@ -1,5 +1,8 @@ { "devDependencies": { "@playwright/test": "^1.57.0" + }, + "dependencies": { + "claude-cli": "^1.0.5" } } diff --git a/wordpress-20260104.sql.gz b/wordpress-20260104.sql.gz old mode 100644 new mode 100755 diff --git a/wp-content/cache/transformed-images/e5215a1698b82c652e6d53647619cac7.webp b/wp-content/cache/transformed-images/e5215a1698b82c652e6d53647619cac7.webp deleted file mode 100755 index 63e6c16c..00000000 Binary files a/wp-content/cache/transformed-images/e5215a1698b82c652e6d53647619cac7.webp and /dev/null differ diff --git a/wp-content/plugins/mls-by-hansonxyz/README.md b/wp-content/plugins/mls-by-hansonxyz/README.md index 30ecb51a..1a211b86 100755 --- a/wp-content/plugins/mls-by-hansonxyz/README.md +++ b/wp-content/plugins/mls-by-hansonxyz/README.md @@ -22,10 +22,12 @@ WordPress plugin for syncing MLS Grid API data (NorthStar MLS) into a local data ## Features - Syncs Active and Pending property listings from MLS Grid API +- **HomeProz Listing Persistence**: Sold HomeProz listings are retained for historical viewing - Automatic incremental updates via replication - On-demand image fetching and local caching +- **Persistent Image Cache**: HomeProz listing images are permanently cached - Automatic WebP conversion for cached images -- Disk space garbage collection for image cache +- Disk space garbage collection for image cache (excludes HomeProz images) - Self-healing sync with automatic error recovery - Rate limit compliance (MLS Grid limits enforced) - Resume capability for interrupted syncs @@ -462,6 +464,30 @@ Per MLS Grid rules, media URLs cannot be used directly on websites. Images must - Automatic re-fetch if cache cleared - Works with MLS Grid's URL expiration +### HomeProz Persistent Cache + +HomeProz listings receive special treatment to preserve images even after properties are sold: + +**How it works:** + +1. HomeProz listings are identified by `ListOfficeMlsId` matching the configured HomeProz office ID +2. During sync, ALL images for HomeProz listings are automatically downloaded +3. Images are stored in the persistent cache: `wp-content/uploads/mls-listings-persistent/` +4. The persistent cache is NEVER subject to garbage collection +5. Images remain available indefinitely, even after the listing is sold and removed from MLS + +**Cache Directories:** + +| Directory | Purpose | Garbage Collected | +|-----------|---------|-------------------| +| `mls-listings/` | Standard cache (non-HomeProz) | Yes | +| `mls-listings-persistent/` | HomeProz listings | No | + +**Benefits:** +- Sold HomeProz listings can be displayed on a "Sold Homes" page +- No loss of images when listings are removed from MLS feed +- Historical record of HomeProz sales preserved + ### Pre-caching Images To pre-cache images for specific listings: @@ -482,6 +508,8 @@ Shows total media records, cached count, and uncached count. The plugin includes automatic garbage collection to prevent disk space from filling up with cached MLS images. +**Important:** Garbage collection ONLY affects the standard cache (`mls-listings/`). The persistent cache (`mls-listings-persistent/`) containing HomeProz listing images is NEVER touched. + ### Enabling Garbage Collection Add to `wp-config.php`: @@ -497,11 +525,12 @@ If `MLS_GC_DISK_THRESHOLD` is not defined, garbage collection is disabled. 1. After each sync (`wp mls run`), the plugin checks free disk space on the volume hosting MLS images 2. If free space is below the threshold, cleanup begins -3. Directories older than 24 hours are deleted, oldest first +3. Directories older than 24 hours are deleted from the standard cache, oldest first 4. Cleanup stops when: - Free space reaches 5GB, OR - 2GB has been deleted in this run 5. Directories modified within the last 24 hours are never deleted (protects recently accessed images) +6. HomeProz images in the persistent cache are NEVER deleted ### Behavior Summary @@ -552,6 +581,33 @@ define('MLS_GC_DISK_THRESHOLD', 10 * 1024 * 1024 * 1024); When a deleted image is requested again, it is automatically re-fetched from MLS Grid and cached. This is the normal on-demand fetching behavior - garbage collection simply clears old cached files to free disk space. +## HomeProz Listing Persistence + +HomeProz listings (properties listed by the configured HomeProz office) receive special handling to preserve them even after they are sold. + +### Retention Rules + +| Listing Type | Active | Pending | Sold | Other Statuses | +|--------------|--------|---------|------|----------------| +| HomeProz | Retained | Retained | Retained | Deleted | +| Non-HomeProz | Retained | Retained | Deleted | Deleted | + +### How It Works + +1. **Identification**: Listings are identified as HomeProz by matching `ListOfficeMlsId` to `MLS_HOMEPROZ_OFFICE_ID` (configured in plugin constants) +2. **Sync Behavior**: HomeProz listings with Active, Pending, or Sold status are kept in the database +3. **Image Caching**: All images for HomeProz listings are automatically downloaded during sync +4. **Persistent Storage**: Images are stored in `mls-listings-persistent/` which is never garbage collected +5. **Future Use**: Sold HomeProz listings can be displayed on a "Sold Homes" page + +### Configuration + +The HomeProz office ID is defined in the main plugin file: + +```php +define('MLS_HOMEPROZ_OFFICE_ID', 'NST253235'); +``` + ## Sync Strategy ### Initial Import (Full Sync) @@ -568,8 +624,10 @@ When a deleted image is requested again, it is automatically re-fetched from MLS - No filter on status (need to detect changes) - For each record: - If `MlgCanView = false`: DELETE from local DB - - If `StandardStatus` not Active/Pending: DELETE from local DB + - If HomeProz listing: DELETE only if status not Active/Pending/Sold + - If non-HomeProz listing: DELETE if status not Active/Pending - Otherwise: INSERT or UPDATE +- HomeProz images are auto-downloaded during sync ### Why This Approach? diff --git a/wp-content/plugins/mls-by-hansonxyz/admin/css/manual-property.css b/wp-content/plugins/mls-by-hansonxyz/admin/css/manual-property.css new file mode 100755 index 00000000..30657b8d --- /dev/null +++ b/wp-content/plugins/mls-by-hansonxyz/admin/css/manual-property.css @@ -0,0 +1,86 @@ +/* Manual Property Admin Styles */ + +#mls-clone-section { + background: #f0f0f1; + border: 1px solid #c3c4c7; + padding: 15px 20px; + margin-bottom: 20px; + border-radius: 4px; +} + +#mls-clone-section h3 { + margin-top: 0; + margin-bottom: 10px; + font-size: 14px; +} + +#mls-clone-section p { + margin-bottom: 12px; + color: #50575e; +} + +#mls-clone-search { + width: 200px; + margin-right: 8px; +} + +#mls-clone-btn { + vertical-align: middle; +} + +#mls-clone-status { + display: inline-block; + margin-left: 10px; + font-style: italic; +} + +/* Admin list table columns */ +.column-mp_status { + width: 80px; +} + +.column-mp_price { + width: 100px; +} + +.column-mp_city { + width: 120px; +} + +.column-mp_homeproz, +.column-mp_featured { + width: 70px; +} + +.column-mp_view { + width: 50px; +} + +/* Status badges */ +.mp-status-badge { + display: inline-block; + padding: 2px 8px; + border-radius: 3px; + font-size: 12px; + font-weight: 500; + color: #fff; +} + +.mp-status-badge.active { + background-color: #28a745; +} + +.mp-status-badge.pending { + background-color: #ffc107; + color: #212529; +} + +.mp-status-badge.sold { + background-color: #6c757d; +} + +.mp-status-badge.cancelled, +.mp-status-badge.expired, +.mp-status-badge.withdrawn { + background-color: #dc3545; +} diff --git a/wp-content/plugins/mls-by-hansonxyz/admin/js/manual-property.js b/wp-content/plugins/mls-by-hansonxyz/admin/js/manual-property.js new file mode 100755 index 00000000..148aed67 --- /dev/null +++ b/wp-content/plugins/mls-by-hansonxyz/admin/js/manual-property.js @@ -0,0 +1,110 @@ +(function($) { + 'use strict'; + + $(document).ready(function() { + var $searchInput = $('#mls-clone-search'); + var $cloneBtn = $('#mls-clone-btn'); + var $status = $('#mls-clone-status'); + + if (!$searchInput.length) { + return; + } + + $cloneBtn.on('click', function() { + var mlsId = $searchInput.val().trim(); + + if (!mlsId) { + $status.text('Please enter an MLS ID').css('color', '#dc3545'); + return; + } + + $status.text('Searching...').css('color', '#666'); + $cloneBtn.prop('disabled', true); + + // First search for the listing + $.ajax({ + url: mlsManualProperty.ajaxUrl, + type: 'POST', + data: { + action: 'mls_search_for_clone', + nonce: mlsManualProperty.nonce, + mls_id: mlsId + }, + success: function(response) { + if (response.success) { + // Found - confirm and clone + var listing = response.data; + var confirmMsg = 'Found listing:\n\n' + + 'MLS #: ' + listing.listing_id + '\n' + + 'Address: ' + listing.address + ', ' + listing.city + '\n' + + 'Price: $' + Number(listing.price).toLocaleString() + '\n\n' + + 'Clone this listing?'; + + if (confirm(confirmMsg)) { + cloneListing(listing.listing_key); + } else { + $status.text('').css('color', ''); + $cloneBtn.prop('disabled', false); + } + } else { + $status.text(response.data || 'Listing not found').css('color', '#dc3545'); + $cloneBtn.prop('disabled', false); + } + }, + error: function() { + $status.text('Error searching for listing').css('color', '#dc3545'); + $cloneBtn.prop('disabled', false); + } + }); + }); + + // Allow Enter key to trigger search + $searchInput.on('keypress', function(e) { + if (e.which === 13) { + e.preventDefault(); + $cloneBtn.click(); + } + }); + + function cloneListing(listingKey) { + $status.text('Cloning listing and downloading images...').css('color', '#666'); + + // Get post ID from URL or hidden field + var postId = $('#post_ID').val() || getUrlParam('post'); + + $.ajax({ + url: mlsManualProperty.ajaxUrl, + type: 'POST', + data: { + action: 'mls_clone_listing', + nonce: mlsManualProperty.nonce, + listing_key: listingKey, + post_id: postId + }, + success: function(response) { + if (response.success) { + $status.html('Success! ' + + response.data.images_imported + ' images imported. Redirecting to edit page...'); + + // Redirect to the edit page of the cloned post (not reload, which creates a new auto-draft) + setTimeout(function() { + window.location.href = 'post.php?post=' + postId + '&action=edit'; + }, 1500); + } else { + $status.text(response.data || 'Clone failed').css('color', '#dc3545'); + $cloneBtn.prop('disabled', false); + } + }, + error: function() { + $status.text('Error cloning listing').css('color', '#dc3545'); + $cloneBtn.prop('disabled', false); + } + }); + } + + function getUrlParam(name) { + var results = new RegExp('[\\?&]' + name + '=([^&#]*)').exec(window.location.href); + return results ? results[1] : null; + } + }); +})(jQuery); diff --git a/wp-content/plugins/mls-by-hansonxyz/cli/class-mls-cli.php b/wp-content/plugins/mls-by-hansonxyz/cli/class-mls-cli.php index d43f78f8..a4b2983d 100755 --- a/wp-content/plugins/mls-by-hansonxyz/cli/class-mls-cli.php +++ b/wp-content/plugins/mls-by-hansonxyz/cli/class-mls-cli.php @@ -40,6 +40,7 @@ class MLS_CLI { WP_CLI::add_command('mls recovery', array($instance, 'recovery')); WP_CLI::add_command('mls media', array($instance, 'media')); WP_CLI::add_command('mls geo', array($instance, 'geo')); + WP_CLI::add_command('mls property', array($instance, 'property')); } /** @@ -256,7 +257,7 @@ class MLS_CLI { * ## OPTIONS * * - * : Sync type: full, incremental, media, or resume + * : Sync type: full, incremental, media-refresh, or resume * * [--dry-run] * : Show what would be synced without making changes @@ -267,8 +268,8 @@ class MLS_CLI { * [--id=] * : Sync state ID to resume (for resume command) * - * [--force] - * : Force re-download of media (for media command) + * [--days=] + * : Days ahead to check for expiring media (for incremental and media-refresh, default: 3) * * [--quiet] * : Suppress progress output @@ -281,8 +282,10 @@ class MLS_CLI { * wp mls sync full * wp mls sync full --dry-run --limit=10 * wp mls sync incremental + * wp mls sync incremental --days=7 * wp mls sync incremental --verbose - * wp mls sync media --limit=100 + * wp mls sync media-refresh + * wp mls sync media-refresh --days=7 * wp mls sync resume --id=5 * * @subcommand sync @@ -375,6 +378,22 @@ class MLS_CLI { echo "\n"; } $this->output_sync_result($result); + + // Run media refresh after successful incremental sync + if ($result['success'] && !$dry_run) { + $days = isset($assoc_args['days']) ? (int) $assoc_args['days'] : 3; + WP_CLI::line(''); + WP_CLI::line("Running media refresh (properties expiring within {$days} days)..."); + if (!$quiet) { + $this->print_progress_legend($verbose); + } + + $media_result = $sync_engine->run_media_refresh_sync($days, false, $progress_callback); + if (!$quiet) { + echo "\n"; + } + $this->output_sync_result($media_result); + } break; case 'media': @@ -384,6 +403,24 @@ class MLS_CLI { WP_CLI::line(''); WP_CLI::line('Use "wp mls media status" to see cache statistics.'); WP_CLI::line('Use "wp mls media fetch --listing=" to pre-cache a specific listing.'); + WP_CLI::line('Use "wp mls sync media-refresh" to proactively refresh expiring media URLs.'); + break; + + case 'media-refresh': + $days = isset($assoc_args['days']) ? (int) $assoc_args['days'] : 3; + WP_CLI::line("Starting media refresh sync (properties expiring within {$days} days)..."); + if ($dry_run) { + WP_CLI::line('DRY RUN - No changes will be made'); + } + if (!$quiet) { + $this->print_progress_legend($verbose); + } + + $result = $sync_engine->run_media_refresh_sync($days, $dry_run, $progress_callback); + if (!$quiet) { + echo "\n"; + } + $this->output_sync_result($result); break; case 'resume': @@ -405,7 +442,7 @@ class MLS_CLI { break; default: - WP_CLI::error("Unknown sync type: {$type}. Use 'full', 'incremental', 'media', or 'resume'."); + WP_CLI::error("Unknown sync type: {$type}. Use 'full', 'incremental', 'media-refresh', or 'resume'."); } } @@ -1306,4 +1343,113 @@ class MLS_CLI { WP_CLI::log("... and " . ($total - 100) . " more."); } } + + /** + * Fetch a property directly from the MLS API and dump the response. + * + * ## OPTIONS + * + * + * : The MLS listing ID (e.g., NST6755550 or 6755550) + * + * [--format=] + * : Output format: json, table, or fields (default: fields) + * + * [--fields=] + * : Comma-separated list of fields to show (for fields format) + * + * ## EXAMPLES + * + * wp mls property 6755550 + * wp mls property NST6755550 --format=json + * wp mls property 6755550 --fields=StandardStatus,ListPrice,CloseDate + * + * @subcommand property + */ + public function property($args, $assoc_args) { + $listing_id = isset($args[0]) ? $args[0] : null; + + if (!$listing_id) { + WP_CLI::error('Please provide a listing ID'); + } + + // Add NST prefix if not present + if (!preg_match('/^[A-Z]{3}/', $listing_id)) { + $listing_id = 'NST' . $listing_id; + } + + WP_CLI::line("Fetching property {$listing_id} from MLS API..."); + + $api_client = $this->plugin->get_api_client(); + $result = $api_client->get_property_media($listing_id); + + if (is_wp_error($result)) { + WP_CLI::error('API Error: ' . $result->get_error_message()); + } + + if (!$result) { + WP_CLI::error("Property {$listing_id} not found in MLS"); + } + + $format = isset($assoc_args['format']) ? $assoc_args['format'] : 'fields'; + + switch ($format) { + case 'json': + echo json_encode($result, JSON_PRETTY_PRINT) . "\n"; + break; + + case 'table': + // Flatten for table display + $flat = array(); + foreach ($result as $key => $value) { + if (!is_array($value)) { + $flat[$key] = $value; + } + } + WP_CLI\Utils\format_items('table', array($flat), array_keys($flat)); + break; + + case 'fields': + default: + // Show key fields + $key_fields = array( + 'ListingId', + 'ListingKey', + 'StandardStatus', + 'MlsStatus', + 'ListPrice', + 'ClosePrice', + 'CloseDate', + 'ListOfficeName', + 'ListAgentFullName', + 'StreetNumber', + 'StreetName', + 'City', + 'StateOrProvince', + 'ModificationTimestamp', + ); + + // Allow custom fields + if (isset($assoc_args['fields'])) { + $key_fields = explode(',', $assoc_args['fields']); + } + + WP_CLI::line(''); + WP_CLI::line('=== Property Details from MLS API ==='); + WP_CLI::line(''); + + foreach ($key_fields as $field) { + $field = trim($field); + $value = isset($result[$field]) ? $result[$field] : '(not set)'; + if (is_array($value)) { + $value = json_encode($value); + } + WP_CLI::line(sprintf(' %-25s %s', $field . ':', $value)); + } + + WP_CLI::line(''); + WP_CLI::line('Use --format=json to see full response'); + break; + } + } } diff --git a/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-api-client.php b/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-api-client.php index 02e6c196..15e80c93 100755 --- a/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-api-client.php +++ b/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-api-client.php @@ -128,11 +128,12 @@ class MLS_API_Client { * @param string $endpoint API endpoint (relative to base URL) * @param array $params Query parameters * @param int $retry Current retry attempt + * @param string $channel Rate limit channel ('general' or 'image') * @return array|WP_Error Response data or error */ - public function request($endpoint, $params = array(), $retry = 0) { - // Check and wait for rate limits - $this->rate_limiter->check_and_wait(true); + public function request($endpoint, $params = array(), $retry = 0, $channel = 'general') { + // Check and wait for rate limits (uses global advisory lock coordination) + $this->rate_limiter->check_and_wait(true, $channel); $url = $this->build_url($endpoint, $params); @@ -172,7 +173,7 @@ class MLS_API_Client { // Retry on transient errors if ($retry < self::MAX_RETRIES) { sleep(pow(2, $retry)); // Exponential backoff - return $this->request($endpoint, $params, $retry + 1); + return $this->request($endpoint, $params, $retry + 1, $channel); } return $response; @@ -195,7 +196,7 @@ class MLS_API_Client { if (($status_code === 429 || $status_code >= 500) && $retry < self::MAX_RETRIES) { $wait = $status_code === 429 ? 60 : pow(2, $retry); sleep($wait); - return $this->request($endpoint, $params, $retry + 1); + return $this->request($endpoint, $params, $retry + 1, $channel); } return new WP_Error('api_error', $error_message, array('status' => $status_code)); @@ -382,7 +383,8 @@ class MLS_API_Client { * Get a single property by listing ID with media * * Used to refresh media URLs for a specific listing without - * fetching the entire dataset. + * fetching the entire dataset. Uses the 'image' rate limit channel + * with a 2-second interval for on-demand image requests. * * Note: MLS Grid only allows filtering by ListingId (not ListingKey) * for the Property resource. The caller must provide the listing_id. @@ -400,7 +402,8 @@ class MLS_API_Client { $params['$expand'] = 'Media'; $params['$top'] = 1; - $response = $this->request('Property', $params); + // Use 'image' channel with 2-second rate limiting for on-demand media fetches + $response = $this->request('Property', $params, 0, 'image'); if (is_wp_error($response)) { return $response; @@ -414,6 +417,41 @@ class MLS_API_Client { return null; } + /** + * Get multiple properties by listing IDs with media (batched) + * + * Fetches up to 25 properties in a single API request using OData 'in' filter. + * Used for efficient media URL refresh without making individual API calls. + * Uses the 'image' rate limit channel with 2-second interval. + * + * @param array $listing_ids Array of MLS listing IDs (max 25) + * @return array|WP_Error Array of property data with Media, or error + */ + public function get_properties_by_ids($listing_ids) { + if (empty($listing_ids)) { + return array('value' => array()); + } + + // Limit to 25 (MLS Grid's max with $expand) + $listing_ids = array_slice($listing_ids, 0, 25); + + $params = array(); + $system = $this->options->get_originating_system(); + + // Build 'in' filter: ListingId in ('ID1', 'ID2', 'ID3') + $escaped_ids = array_map(function($id) { + return "'" . addslashes($id) . "'"; + }, $listing_ids); + $in_list = implode(',', $escaped_ids); + + $params['$filter'] = "OriginatingSystemName eq '{$system}' and ListingId in ({$in_list})"; + $params['$expand'] = 'Media'; + $params['$top'] = 25; + + // Use 'image' channel with 2-second rate limiting for media fetches + return $this->request('Property', $params, 0, 'image'); + } + /** * Get next page of results * diff --git a/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-cluster.php b/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-cluster.php index a2cccccb..07b8ccf3 100755 --- a/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-cluster.php +++ b/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-cluster.php @@ -41,16 +41,31 @@ class MLS_Cluster { /** * Minimum properties before any grouping kicks in - * Below this, always show individual markers + * Below this, always show individual markers regardless of zoom */ const MIN_FOR_GROUPING = 30; + /** + * Viewport-aware marker threshold + * If viewport contains fewer than this many properties AND zoom >= 9, + * show individual markers instead of clusters. + * This helps mobile viewports which show smaller geographic areas. + */ + const VIEWPORT_MARKER_THRESHOLD = 120; + + /** + * Minimum zoom level for viewport-aware marker display + * Below this zoom, always use density/cluster mode even with few properties + * (prevents showing 100+ scattered markers across entire state) + */ + const MIN_ZOOM_FOR_VIEWPORT_MARKERS = 9; + /** * Zoom thresholds for visualization modes */ const ZOOM_DENSE_MAX = 5; // 1-5: density dots (40% more dense) const ZOOM_DENSITY_MAX = 8; // 6-8: density dots (normal) - const ZOOM_CLUSTER_MAX = 15; // 9-15: numbered clusters + const ZOOM_CLUSTER_MAX = 15; // 9-15: numbered clusters (unless viewport threshold met) // 16+: individual markers /** @@ -269,8 +284,15 @@ class MLS_Cluster { } if ($args['property_type']) { - $where[] = 'property_type = %s'; - $values[] = $args['property_type']; + $types = array_filter(array_map('trim', explode(',', $args['property_type']))); + if (count($types) === 1) { + $where[] = 'property_type = %s'; + $values[] = $types[0]; + } elseif (count($types) > 1) { + $placeholders = implode(',', array_fill(0, count($types), '%s')); + $where[] = "property_type IN ({$placeholders})"; + $values = array_merge($values, $types); + } } if ($args['city']) { @@ -314,7 +336,7 @@ class MLS_Cluster { $total = (int) $wpdb->get_var($count_sql); } - // If few properties, always show individual markers (no grouping) + // If very few properties, always show individual markers (no grouping) if ($total <= self::MIN_FOR_GROUPING) { return $this->get_individual_markers($where_sql, $values, $total); } @@ -327,19 +349,34 @@ class MLS_Cluster { $zoom = (int) $args['zoom']; - // Determine visualization mode based on zoom level - // Zoom 1-5: Density dots (40% more dense) + // Determine visualization mode based on zoom level AND viewport property count + // + // Priority order: + // 1. Very zoomed out (zoom 1-5): Always density dots (dense) + // 2. Zoomed out (zoom 6-8): Always density dots (normal) + // 3. Medium zoom (9-15) with FEW properties in viewport: Individual markers + // 4. Medium zoom (9-15) with MANY properties: Clusters + // 5. Very zoomed in (16+): Always individual markers + + // Zoom 1-5: Density dots (40% more dense) - always, regardless of count if ($zoom <= self::ZOOM_DENSE_MAX) { return $this->get_density_data($where_sql, $values, $zoom, $center_lat, $total, self::DENSITY_DOT_SPACING_DENSE); } - // Zoom 6-11: Density dots (normal spacing) + // Zoom 6-8: Density dots (normal spacing) - always, regardless of count if ($zoom <= self::ZOOM_DENSITY_MAX) { return $this->get_density_data($where_sql, $values, $zoom, $center_lat, $total, self::DENSITY_DOT_SPACING); } - // Zoom 9-15: Always use server-side clusters (let server handle grouping) + // Zoom 9-15: Use viewport-aware threshold + // If viewport has relatively few properties, show individual markers + // This helps mobile viewports which show smaller geographic areas at same zoom level if ($zoom <= self::ZOOM_CLUSTER_MAX) { + if ($total <= self::VIEWPORT_MARKER_THRESHOLD) { + // Few enough properties in viewport - show individual markers + return $this->get_individual_markers($where_sql, $values, $total); + } + // Many properties - use clusters return $this->get_cluster_data($where_sql, $values, $zoom, $center_lat, $total); } diff --git a/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-db.php b/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-db.php index ba8e481e..18ce4f67 100755 --- a/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-db.php +++ b/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-db.php @@ -13,7 +13,7 @@ class MLS_DB { * Schema version for index migrations * Increment this when adding new indexes or columns */ - const SCHEMA_VERSION = 5; + const SCHEMA_VERSION = 6; /** * Get table name with prefix @@ -82,6 +82,13 @@ class MLS_DB { return $this->get_table_name(MLS_TABLE_GEO_ZIPCODES); } + /** + * Get manual properties table name + */ + public function manual_properties_table() { + return $this->get_table_name(MLS_TABLE_MANUAL_PROPERTIES); + } + /** * Create all database tables */ @@ -143,6 +150,7 @@ class MLS_DB { is_homeproz TINYINT(1) NOT NULL DEFAULT 0, photos_count INT(5) DEFAULT 0, + media_expires_at DATETIME DEFAULT NULL, modification_timestamp DATETIME NOT NULL, photos_change_timestamp DATETIME DEFAULT NULL, listing_contract_date DATE DEFAULT NULL, @@ -332,6 +340,83 @@ class MLS_DB { dbDelta($sql_geo_zipcodes); + // Manual properties table (for manually entered listings) + $table_manual = $wpdb->prefix . MLS_TABLE_MANUAL_PROPERTIES; + $sql_manual = "CREATE TABLE {$table_manual} ( + id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, + wp_post_id BIGINT(20) UNSIGNED NOT NULL, + listing_key VARCHAR(50) NOT NULL, + listing_id VARCHAR(50) DEFAULT NULL, + + standard_status VARCHAR(30) NOT NULL DEFAULT 'Active', + list_price DECIMAL(15,2) DEFAULT NULL, + original_list_price DECIMAL(15,2) DEFAULT NULL, + close_price DECIMAL(15,2) DEFAULT NULL, + + street_number VARCHAR(20) DEFAULT NULL, + street_name VARCHAR(100) DEFAULT NULL, + street_suffix VARCHAR(30) DEFAULT NULL, + unit_number VARCHAR(20) DEFAULT NULL, + full_address VARCHAR(255) DEFAULT NULL, + city VARCHAR(100) DEFAULT NULL, + state_or_province VARCHAR(50) DEFAULT 'MN', + postal_code VARCHAR(20) DEFAULT NULL, + county VARCHAR(100) DEFAULT NULL, + latitude DECIMAL(10,8) DEFAULT NULL, + longitude DECIMAL(11,8) DEFAULT NULL, + + property_type VARCHAR(50) DEFAULT NULL, + property_sub_type VARCHAR(50) DEFAULT NULL, + bedrooms_total INT(3) DEFAULT NULL, + bathrooms_total DECIMAL(4,1) DEFAULT NULL, + bathrooms_full INT(3) DEFAULT NULL, + bathrooms_half INT(3) DEFAULT NULL, + living_area INT(10) DEFAULT NULL, + lot_size_area DECIMAL(12,4) DEFAULT NULL, + lot_size_units VARCHAR(20) DEFAULT 'Acres', + year_built INT(4) DEFAULT NULL, + stories INT(3) DEFAULT NULL, + garage_spaces INT(3) DEFAULT NULL, + architectural_style VARCHAR(100) DEFAULT NULL, + + public_remarks TEXT DEFAULT NULL, + private_remarks TEXT DEFAULT NULL, + directions TEXT DEFAULT NULL, + + list_agent_post_id BIGINT(20) UNSIGNED DEFAULT NULL, + co_list_agent_post_id BIGINT(20) UNSIGNED DEFAULT NULL, + is_homeproz TINYINT(1) NOT NULL DEFAULT 0, + is_featured TINYINT(1) NOT NULL DEFAULT 0, + + virtual_tour_url VARCHAR(500) DEFAULT NULL, + association_fee DECIMAL(10,2) DEFAULT NULL, + + list_date DATE DEFAULT NULL, + contract_date DATE DEFAULT NULL, + close_date DATE DEFAULT NULL, + expiration_date DATE DEFAULT NULL, + + photos_count INT(5) DEFAULT 0, + + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + + PRIMARY KEY (id), + UNIQUE KEY listing_key (listing_key), + UNIQUE KEY wp_post_id (wp_post_id), + KEY listing_id (listing_id), + KEY standard_status (standard_status), + KEY city (city), + KEY property_type (property_type), + KEY list_price (list_price), + KEY is_homeproz (is_homeproz), + KEY is_featured (is_featured), + KEY latitude (latitude), + KEY longitude (longitude) + ) {$charset_collate};"; + + dbDelta($sql_manual); + // Run index migrations self::run_index_migrations(); } @@ -473,8 +558,66 @@ class MLS_DB { update_option('mls_schema_version', 5); } + // Migration to schema version 6: Add media_expires_at column for proactive URL refresh + if ($current_schema < 6) { + $table_properties = $wpdb->prefix . MLS_TABLE_PROPERTIES; + + // Check if column exists + $column_exists = $wpdb->get_var($wpdb->prepare( + "SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = %s AND TABLE_NAME = %s AND COLUMN_NAME = 'media_expires_at'", + DB_NAME, + $table_properties + )); + + if (!$column_exists) { + $wpdb->query("ALTER TABLE {$table_properties} ADD COLUMN media_expires_at DATETIME DEFAULT NULL AFTER photos_count"); + } + + // Add index for finding properties with expiring media + $existing_indexes = self::get_existing_indexes($table_properties); + if (!isset($existing_indexes['idx_media_expires_at'])) { + $wpdb->query("ALTER TABLE {$table_properties} ADD INDEX idx_media_expires_at (media_expires_at)"); + } + + update_option('mls_schema_version', 6); + } + + // Migration to schema version 7: Add indexes for search query optimization + if ($current_schema < 7) { + $table_properties = $wpdb->prefix . MLS_TABLE_PROPERTIES; + $existing_indexes = self::get_existing_indexes($table_properties); + + // Index for postal code searches + if (!isset($existing_indexes['idx_postal_code'])) { + $wpdb->query("ALTER TABLE {$table_properties} ADD INDEX idx_postal_code (postal_code)"); + } + + // Index for bathroom filter + if (!isset($existing_indexes['idx_bathrooms_total'])) { + $wpdb->query("ALTER TABLE {$table_properties} ADD INDEX idx_bathrooms_total (bathrooms_total)"); + } + + // Index for living area (sqft) filter + if (!isset($existing_indexes['idx_living_area'])) { + $wpdb->query("ALTER TABLE {$table_properties} ADD INDEX idx_living_area (living_area)"); + } + + // Index for state filter + if (!isset($existing_indexes['idx_state'])) { + $wpdb->query("ALTER TABLE {$table_properties} ADD INDEX idx_state (state_or_province)"); + } + + // Composite index for media refresh sync query + if (!isset($existing_indexes['idx_status_media_expires'])) { + $wpdb->query("ALTER TABLE {$table_properties} ADD INDEX idx_status_media_expires (standard_status, media_expires_at)"); + } + + update_option('mls_schema_version', 7); + } + // Future migrations go here: - // if ($current_schema < 6) { ... } + // if ($current_schema < 8) { ... } } /** @@ -511,6 +654,7 @@ class MLS_DB { MLS_TABLE_MEDIA_LOG, MLS_TABLE_GEO_CITIES, MLS_TABLE_GEO_ZIPCODES, + MLS_TABLE_MANUAL_PROPERTIES, ); foreach ($tables as $table) { diff --git a/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-garbage-collector.php b/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-garbage-collector.php old mode 100644 new mode 100755 index 13ce261e..f51fdace --- a/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-garbage-collector.php +++ b/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-garbage-collector.php @@ -5,12 +5,18 @@ * Cleans up old MLS image directories when disk space is low. * Runs after sync to prevent disk from filling up. * + * IMPORTANT: Only cleans the standard cache directory (mls-listings). + * The persistent cache directory (mls-listings-persistent) is NEVER touched. + * HomeProz listing images are stored in persistent cache and preserved + * even after listings are sold or removed from MLS. + * * Configuration (wp-config.php): * - MLS_GC_DISK_THRESHOLD: Minimum free disk space in bytes before cleanup triggers * Example: define('MLS_GC_DISK_THRESHOLD', 5 * 1024 * 1024 * 1024); // 5GB * * Behavior: * - Only runs if MLS_GC_DISK_THRESHOLD is defined + * - Only cleans standard cache (mls-listings), never persistent cache * - Skips directories modified within the last 24 hours * - Deletes oldest directories first * - Stops when free space >= 5GB or 2GB deleted per run @@ -42,13 +48,20 @@ class MLS_Garbage_Collector { */ private $logger; + /** + * Database instance + */ + private $db; + /** * Constructor * * @param MLS_Logger $logger Logger instance + * @param MLS_DB|null $db Database instance (optional for backwards compatibility) */ - public function __construct(MLS_Logger $logger) { + public function __construct(MLS_Logger $logger, MLS_DB $db = null) { $this->logger = $logger; + $this->db = $db; } /** @@ -70,7 +83,11 @@ class MLS_Garbage_Collector { } /** - * Get the MLS images upload directory + * Get the MLS images upload directory (standard cache only) + * + * Returns the standard cache directory that is subject to garbage collection. + * The persistent cache (mls-listings-persistent) is intentionally excluded + * to preserve HomeProz listing images indefinitely. * * @return string Absolute path to MLS images directory */ @@ -324,6 +341,10 @@ class MLS_Garbage_Collector { $deleted_bytes += $size; $deleted_count++; + // Reset download_status to 'pending' for this listing's media + // so images can be re-downloaded on demand later + $this->reset_media_download_status($listing_key); + $this->logger->info('Garbage collection deleted directory', array( 'listing_key' => $listing_key, 'size' => $size, @@ -366,6 +387,40 @@ class MLS_Garbage_Collector { return $result; } + /** + * Reset download_status to 'pending' for a listing's media records + * + * Called after deleting cached files so images can be re-downloaded on demand. + * + * @param string $listing_key Listing key + */ + private function reset_media_download_status($listing_key) { + global $wpdb; + + // Get the media table name + $media_table = $this->db ? $this->db->media_table() : $wpdb->prefix . 'mls_media'; + + $updated = $wpdb->update( + $media_table, + array( + 'download_status' => 'pending', + 'local_path' => null, + 'local_url' => null, + 'downloaded_at' => null, + ), + array('listing_key' => $listing_key), + array('%s', null, null, null), + array('%s') + ); + + if ($updated > 0) { + $this->logger->debug('Reset media download status for garbage collected listing', array( + 'listing_key' => $listing_key, + 'records_updated' => $updated, + )); + } + } + /** * Clean up empty prefix directories */ diff --git a/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-geocoder.php b/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-geocoder.php new file mode 100755 index 00000000..991f3c2a --- /dev/null +++ b/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-geocoder.php @@ -0,0 +1,264 @@ +fetch_geocode($address); + + if ($result) { + // Cache the result + set_transient($cache_key, $result, self::CACHE_EXPIRATION); + } + + return $result; + } + + /** + * Fetch geocoding data from Nominatim + * + * @param string $address + * @return array|null + */ + private function fetch_geocode($address) { + // Build request URL + $url = add_query_arg(array( + 'q' => $address, + 'format' => 'json', + 'addressdetails' => 1, + 'limit' => 1, + 'countrycodes' => 'us', + ), self::API_URL); + + // Make request with proper User-Agent (required by Nominatim) + $response = wp_remote_get($url, array( + 'timeout' => 10, + 'headers' => array( + 'User-Agent' => 'HomeProz WordPress MLS Plugin/1.0 (contact@homeproz.com)', + ), + )); + + if (is_wp_error($response)) { + return null; + } + + $body = wp_remote_retrieve_body($response); + $data = json_decode($body, true); + + if (empty($data) || !is_array($data) || empty($data[0])) { + return null; + } + + $result = $data[0]; + $addr = $result['address'] ?? array(); + + // Extract components + return array( + 'latitude' => isset($result['lat']) ? (float) $result['lat'] : null, + 'longitude' => isset($result['lon']) ? (float) $result['lon'] : null, + 'city' => $this->extract_city($addr), + 'state' => $addr['state'] ?? null, + 'state_code' => $this->get_state_code($addr['state'] ?? ''), + 'postal_code' => $addr['postcode'] ?? null, + 'county' => isset($addr['county']) ? str_replace(' County', '', $addr['county']) : null, + 'country' => $addr['country'] ?? null, + 'display_name' => $result['display_name'] ?? null, + ); + } + + /** + * Extract city from address components + * + * Nominatim may return city in different fields depending on location type + * + * @param array $addr Address components + * @return string|null + */ + private function extract_city($addr) { + // Try different fields where city might be + $city_fields = array('city', 'town', 'village', 'municipality', 'hamlet'); + + foreach ($city_fields as $field) { + if (!empty($addr[$field])) { + return $addr[$field]; + } + } + + return null; + } + + /** + * Get state code from state name + * + * @param string $state_name Full state name + * @return string|null Two-letter state code + */ + private function get_state_code($state_name) { + $states = array( + 'Alabama' => 'AL', + 'Alaska' => 'AK', + 'Arizona' => 'AZ', + 'Arkansas' => 'AR', + 'California' => 'CA', + 'Colorado' => 'CO', + 'Connecticut' => 'CT', + 'Delaware' => 'DE', + 'Florida' => 'FL', + 'Georgia' => 'GA', + 'Hawaii' => 'HI', + 'Idaho' => 'ID', + 'Illinois' => 'IL', + 'Indiana' => 'IN', + 'Iowa' => 'IA', + 'Kansas' => 'KS', + 'Kentucky' => 'KY', + 'Louisiana' => 'LA', + 'Maine' => 'ME', + 'Maryland' => 'MD', + 'Massachusetts' => 'MA', + 'Michigan' => 'MI', + 'Minnesota' => 'MN', + 'Mississippi' => 'MS', + 'Missouri' => 'MO', + 'Montana' => 'MT', + 'Nebraska' => 'NE', + 'Nevada' => 'NV', + 'New Hampshire' => 'NH', + 'New Jersey' => 'NJ', + 'New Mexico' => 'NM', + 'New York' => 'NY', + 'North Carolina' => 'NC', + 'North Dakota' => 'ND', + 'Ohio' => 'OH', + 'Oklahoma' => 'OK', + 'Oregon' => 'OR', + 'Pennsylvania' => 'PA', + 'Rhode Island' => 'RI', + 'South Carolina' => 'SC', + 'South Dakota' => 'SD', + 'Tennessee' => 'TN', + 'Texas' => 'TX', + 'Utah' => 'UT', + 'Vermont' => 'VT', + 'Virginia' => 'VA', + 'Washington' => 'WA', + 'West Virginia' => 'WV', + 'Wisconsin' => 'WI', + 'Wyoming' => 'WY', + ); + + // If already a code, return as-is + if (strlen($state_name) === 2) { + return strtoupper($state_name); + } + + return $states[$state_name] ?? null; + } + + /** + * Reverse geocode coordinates to address + * + * @param float $lat Latitude + * @param float $lng Longitude + * @return array|null Address components or null on failure + */ + public function reverse_geocode($lat, $lng) { + $cache_key = 'mls_rgeo_' . md5($lat . '_' . $lng); + + $cached = get_transient($cache_key); + if ($cached !== false) { + return $cached; + } + + $url = add_query_arg(array( + 'lat' => $lat, + 'lon' => $lng, + 'format' => 'json', + 'addressdetails' => 1, + ), 'https://nominatim.openstreetmap.org/reverse'); + + $response = wp_remote_get($url, array( + 'timeout' => 10, + 'headers' => array( + 'User-Agent' => 'HomeProz WordPress MLS Plugin/1.0 (contact@homeproz.com)', + ), + )); + + if (is_wp_error($response)) { + return null; + } + + $body = wp_remote_retrieve_body($response); + $data = json_decode($body, true); + + if (empty($data) || !isset($data['address'])) { + return null; + } + + $addr = $data['address']; + + $result = array( + 'latitude' => (float) $lat, + 'longitude' => (float) $lng, + 'city' => $this->extract_city($addr), + 'state' => $addr['state'] ?? null, + 'state_code' => $this->get_state_code($addr['state'] ?? ''), + 'postal_code' => $addr['postcode'] ?? null, + 'county' => isset($addr['county']) ? str_replace(' County', '', $addr['county']) : null, + 'display_name' => $data['display_name'] ?? null, + ); + + set_transient($cache_key, $result, self::CACHE_EXPIRATION); + + return $result; + } + + /** + * Clear geocoding cache for an address + * + * @param string $address + */ + public function clear_cache($address) { + $cache_key = 'mls_geo_' . md5(strtolower(trim($address))); + delete_transient($cache_key); + } +} diff --git a/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-image-endpoint.php b/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-image-endpoint.php index 2aad007b..7a9cb1ac 100755 --- a/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-image-endpoint.php +++ b/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-image-endpoint.php @@ -133,6 +133,19 @@ class MLS_Image_Endpoint { // Get the source image $source_path = $this->get_source_image($listing_key, $index); + if (is_wp_error($source_path)) { + // Handle specific errors + if ($source_path->get_error_code() === 'rate_limited') { + $this->logger->warning('MLS Image: Rate limited by MLS Grid', array( + 'listing_key' => $listing_key, + 'index' => $index, + )); + $this->send_429(); + return; + } + $this->send_404(); + return; + } if (!$source_path) { $this->logger->error('MLS Image: Source not found', array( 'listing_key' => $listing_key, @@ -142,7 +155,7 @@ class MLS_Image_Endpoint { return; } - // Generate thumbnail + // Generate thumbnail from cached source $result = $this->generate_thumbnail($source_path, $cached_path, $max_dimension); if (!$result) { // Fall back to serving original if conversion fails @@ -156,10 +169,13 @@ class MLS_Image_Endpoint { /** * Get source image path, fetching from MLS if needed * + * Source images are cached in the thumbnails directory (mls-thumbnails) + * alongside generated thumbnails so they don't get garbage collected. + * * This method handles: - * 1. Returning cached local images if available - * 2. Checking if media URL has expired and refreshing if needed - * 3. Fetching images from MLS Grid on demand + * 1. Returning cached source from thumbnails directory + * 2. Falling back to media handler cache (mls-listings) if available + * 3. Fetching from MLS Grid on demand and caching source locally */ private function get_source_image($listing_key, $index) { global $wpdb; @@ -167,6 +183,12 @@ class MLS_Image_Endpoint { $plugin = mls_plugin(); $db = $plugin->get_db(); + // First check for cached source in thumbnails directory (won't be garbage collected) + $source_path = $this->get_cached_source_path($listing_key, $index); + if ($source_path) { + return $source_path; + } + // Get media record for this index $media = $wpdb->get_row($wpdb->prepare( "SELECT * FROM {$db->media_table()} @@ -180,24 +202,47 @@ class MLS_Image_Endpoint { return null; } - // Check if already cached locally + // Check if source exists in media handler cache (mls-listings directories) + // These may have been garbage collected, but check anyway + $found_file = null; + if ($media->local_path) { - $full_path = $this->media_handler->get_upload_dir() . '/' . $media->local_path; - if (file_exists($full_path)) { - return $full_path; + $filename = basename($media->local_path); + $webp_filename = preg_replace('/\.[^.]+$/', '.webp', $filename); + $found_file = $this->media_handler->find_cached_file($listing_key, $webp_filename); + if (!$found_file) { + $found_file = $this->media_handler->find_cached_file($listing_key, $filename); } } - // Check if the media URL has expired before trying to fetch + if (!$found_file) { + $extensions = array('webp', 'jpg', 'jpeg', 'png', 'gif'); + foreach ($extensions as $ext) { + $pattern_file = $index . '.' . $ext; + $found_file = $this->media_handler->find_cached_file($listing_key, $pattern_file); + if ($found_file) { + break; + } + } + } + + // If found in mls-listings, copy to thumbnails directory for future use + if ($found_file) { + $copied_path = $this->copy_source_to_cache($found_file['path'], $listing_key, $index); + if ($copied_path) { + return $copied_path; + } + return $found_file['path']; + } + + // If media URL has expired, refresh the entire property on demand if ($this->media_handler->is_url_expired($media->media_url)) { - $this->logger->debug('Media URL expired, refreshing', array( + $this->logger->debug('Media URL expired, attempting on-demand refresh', array( 'listing_key' => $listing_key, 'index' => $index, )); - // Refresh media URLs from API - if ($this->media_handler->refresh_media_urls($listing_key)) { - // Re-fetch the record with fresh URL + if ($this->refresh_property_on_demand($listing_key)) { $media = $wpdb->get_row($wpdb->prepare( "SELECT * FROM {$db->media_table()} WHERE listing_key = %s AND media_order = %d @@ -206,37 +251,259 @@ class MLS_Image_Endpoint { $index )); - if (!$media) { + if (!$media || $this->media_handler->is_url_expired($media->media_url)) { return null; } + } else { + return null; } } - // Fetch from MLS on demand - $url = $this->media_handler->get_image_url($media, true); - if (!$url) { - return null; - } + // Fetch from MLS and cache source directly to thumbnails directory + return $this->fetch_and_cache_source($media, $listing_key, $index); + } - // Re-fetch the record to get updated local_path - $media = $wpdb->get_row($wpdb->prepare( - "SELECT * FROM {$db->media_table()} - WHERE listing_key = %s AND media_order = %d - LIMIT 1", - $listing_key, - $index - )); + /** + * Get cached source path from thumbnails directory + * + * @param string $listing_key Listing key + * @param int $index Image index + * @return string|null Path if found, null otherwise + */ + private function get_cached_source_path($listing_key, $index) { + $cache_dir = $this->get_cache_dir($listing_key); + $extensions = array('webp', 'jpg', 'jpeg', 'png', 'gif'); - if ($media && $media->local_path) { - $full_path = $this->media_handler->get_upload_dir() . '/' . $media->local_path; - if (file_exists($full_path)) { - return $full_path; + foreach ($extensions as $ext) { + $path = $cache_dir . '/' . $index . '-source.' . $ext; + if (file_exists($path)) { + return $path; } } return null; } + /** + * Copy source file to thumbnails cache directory + * + * @param string $source_path Original source path + * @param string $listing_key Listing key + * @param int $index Image index + * @return string|null New path if copied, null on failure + */ + private function copy_source_to_cache($source_path, $listing_key, $index) { + $cache_dir = $this->get_cache_dir($listing_key); + if (!file_exists($cache_dir)) { + wp_mkdir_p($cache_dir); + } + + $ext = strtolower(pathinfo($source_path, PATHINFO_EXTENSION)); + $dest_path = $cache_dir . '/' . $index . '-source.' . $ext; + + if (copy($source_path, $dest_path)) { + return $dest_path; + } + + return null; + } + + /** + * Fetch image from MLS and cache source to thumbnails directory + * + * @param object $media Media record from database + * @param string $listing_key Listing key + * @param int $index Image index + * @return string|WP_Error Path to cached source, or error + */ + private function fetch_and_cache_source($media, $listing_key, $index) { + if (empty($media->media_url)) { + return null; + } + + // Check rate limiter + $rate_limiter = mls_plugin()->get_rate_limiter(); + if (!$rate_limiter->can_fetch_image()) { + $this->logger->warning('Daily data budget exhausted, skipping image fetch', array( + 'listing_key' => $listing_key, + 'index' => $index, + )); + return null; + } + + // Fetch image from MLS + $request_args = array('timeout' => 30); + if (defined('MLS_SKIP_SSL_VERIFY') && MLS_SKIP_SSL_VERIFY) { + $request_args['sslverify'] = false; + } + + $response = wp_remote_get($media->media_url, $request_args); + + if (is_wp_error($response)) { + $this->logger->warning('Source fetch failed', array( + 'listing_key' => $listing_key, + 'index' => $index, + 'error' => $response->get_error_message(), + )); + return null; + } + + $status_code = wp_remote_retrieve_response_code($response); + if ($status_code === 429) { + return new WP_Error('rate_limited', 'MLS Grid rate limit exceeded', array('status' => 429)); + } + if ($status_code !== 200) { + $this->logger->warning('Source fetch HTTP error', array( + 'listing_key' => $listing_key, + 'index' => $index, + 'status' => $status_code, + )); + return null; + } + + $body = wp_remote_retrieve_body($response); + if (empty($body)) { + return null; + } + + // Record bytes downloaded + $rate_limiter->record_data_transfer(strlen($body)); + + // Determine extension from content type + $content_type = wp_remote_retrieve_header($response, 'content-type'); + $ext = $this->get_extension_from_content_type($content_type); + + // Save to thumbnails cache directory + $cache_dir = $this->get_cache_dir($listing_key); + if (!file_exists($cache_dir)) { + wp_mkdir_p($cache_dir); + } + + $source_path = $cache_dir . '/' . $index . '-source.' . $ext; + + if (file_put_contents($source_path, $body) === false) { + $this->logger->error('Failed to write source file', array( + 'path' => $source_path, + )); + return null; + } + + $this->logger->debug('Source fetched and cached', array( + 'listing_key' => $listing_key, + 'index' => $index, + 'path' => $source_path, + 'size' => strlen($body), + )); + + return $source_path; + } + + /** + * Get file extension from content type + * + * @param string $content_type Content-Type header + * @return string Extension + */ + private function get_extension_from_content_type($content_type) { + $content_type = strtolower($content_type); + + if (strpos($content_type, 'jpeg') !== false || strpos($content_type, 'jpg') !== false) { + return 'jpg'; + } elseif (strpos($content_type, 'png') !== false) { + return 'png'; + } elseif (strpos($content_type, 'gif') !== false) { + return 'gif'; + } elseif (strpos($content_type, 'webp') !== false) { + return 'webp'; + } + + return 'jpg'; // Default + } + + /** + * Refresh a property on demand when media URLs have expired + * + * Uses MySQL advisory lock to prevent multiple simultaneous refreshes + * of the same property. Includes a 4 second delay to respect API rate limits. + * + * @param string $listing_key Property listing key + * @return bool True if refresh succeeded, false otherwise + */ + private function refresh_property_on_demand($listing_key) { + global $wpdb; + + // Get the listing_id for API lookup + $db = mls_plugin()->get_db(); + $property = $wpdb->get_row($wpdb->prepare( + "SELECT listing_id FROM {$db->properties_table()} WHERE listing_key = %s", + $listing_key + )); + + if (!$property || empty($property->listing_id)) { + $this->logger->warning('Cannot refresh property: listing_id not found', array( + 'listing_key' => $listing_key, + )); + return false; + } + + // Advisory lock to prevent concurrent refreshes of the same property + $lock_name = 'mls_property_refresh_' . $listing_key; + $lock_timeout = 0; // Non-blocking - return immediately if lock not available + + $lock_acquired = $wpdb->get_var($wpdb->prepare( + "SELECT GET_LOCK(%s, %d)", + $lock_name, + $lock_timeout + )); + + if ($lock_acquired !== '1') { + // Another request is already refreshing this property + $this->logger->debug('Property refresh already in progress', array( + 'listing_key' => $listing_key, + )); + return false; + } + + try { + // Fetch fresh property data from API + $api_client = mls_plugin()->get_api_client(); + $property_data = $api_client->get_property_media($property->listing_id); + + if (is_wp_error($property_data)) { + $this->logger->warning('Failed to refresh property from API', array( + 'listing_key' => $listing_key, + 'error' => $property_data->get_error_message(), + )); + return false; + } + + if (empty($property_data)) { + $this->logger->warning('Property not found in API', array( + 'listing_key' => $listing_key, + )); + return false; + } + + // Update media records with fresh URLs + if (isset($property_data['Media']) && is_array($property_data['Media'])) { + $this->media_handler->sync_property_media($listing_key, $property_data['Media']); + + $this->logger->info('Property media refreshed on demand', array( + 'listing_key' => $listing_key, + 'media_count' => count($property_data['Media']), + )); + + return true; + } + + return false; + + } finally { + // Always release the lock + $wpdb->query($wpdb->prepare("SELECT RELEASE_LOCK(%s)", $lock_name)); + } + } + /** * Get cached thumbnail path */ @@ -423,6 +690,16 @@ class MLS_Image_Endpoint { exit; } + /** + * Send 429 Too Many Requests response + */ + private function send_429() { + status_header(429); + header('Retry-After: 5'); + nocache_headers(); + exit; + } + /** * Get URL for an MLS image * @@ -432,6 +709,25 @@ class MLS_Image_Endpoint { * @return string Image URL */ public static function get_url($listing_key, $index = 1, $size = 'thumb') { + // Handle manual properties - return WordPress attachment URL directly + if (strpos($listing_key, 'MANUAL-') === 0) { + $post_id = (int) str_replace('MANUAL-', '', $listing_key); + if ($post_id) { + $gallery = get_field('gallery', $post_id); + if (!empty($gallery) && is_array($gallery)) { + // $index is 1-based, convert to 0-based array index + $idx = max(0, $index - 1); + if (isset($gallery[$idx])) { + // Use WordPress image size based on requested size + $wp_size = ($size === 'full') ? 'large' : 'medium_large'; + $image_url = wp_get_attachment_image_url($gallery[$idx]['ID'], $wp_size); + return $image_url ?: $gallery[$idx]['url']; + } + } + } + return ''; + } + $sig = self::generate_signature($listing_key); return home_url("/mls-image/{$listing_key}/{$index}/{$size}/") . '?sig=' . $sig; } diff --git a/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-media-handler.php b/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-media-handler.php index f439e784..6138ca8e 100755 --- a/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-media-handler.php +++ b/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-media-handler.php @@ -17,10 +17,15 @@ if (!defined('ABSPATH')) { class MLS_Media_Handler { /** - * Upload subdirectory for MLS media + * Upload subdirectory for MLS media (standard cache - subject to garbage collection) */ const UPLOAD_SUBDIR = 'mls-listings'; + /** + * Upload subdirectory for persistent HomeProz media (never garbage collected) + */ + const PERSISTENT_SUBDIR = 'mls-listings-persistent'; + /** * Database instance */ @@ -161,7 +166,7 @@ class MLS_Media_Handler { } /** - * Get base upload directory for MLS media + * Get base upload directory for MLS media (standard cache) * * @return string Absolute path */ @@ -171,7 +176,7 @@ class MLS_Media_Handler { } /** - * Get base upload URL for MLS media + * Get base upload URL for MLS media (standard cache) * * @return string URL */ @@ -181,14 +186,113 @@ class MLS_Media_Handler { } /** - * Get storage directory for a specific listing + * Get base upload directory for persistent HomeProz media * - * @param string $listing_key Listing key * @return string Absolute path */ - public function get_listing_dir($listing_key) { + public function get_persistent_upload_dir() { + $upload_dir = wp_upload_dir(); + return $upload_dir['basedir'] . '/' . self::PERSISTENT_SUBDIR; + } + + /** + * Get base upload URL for persistent HomeProz media + * + * @return string URL + */ + public function get_persistent_upload_url() { + $upload_dir = wp_upload_dir(); + return $upload_dir['baseurl'] . '/' . self::PERSISTENT_SUBDIR; + } + + /** + * Check if a listing is a HomeProz listing + * + * @param string $listing_key Listing key + * @return bool True if HomeProz listing + */ + public function is_homeproz_listing($listing_key) { + global $wpdb; + + $is_homeproz = $wpdb->get_var($wpdb->prepare( + "SELECT is_homeproz FROM {$this->db->properties_table()} WHERE listing_key = %s", + $listing_key + )); + + return (bool) $is_homeproz; + } + + /** + * Get storage directory for a specific listing + * + * HomeProz listings use the persistent cache directory. + * Other listings use the standard cache directory (subject to garbage collection). + * + * @param string $listing_key Listing key + * @param bool|null $is_homeproz Override HomeProz check (null = look up from DB) + * @return string Absolute path + */ + public function get_listing_dir($listing_key, $is_homeproz = null) { $prefix = substr($listing_key, 0, 2); - return $this->get_upload_dir() . '/' . $prefix . '/' . $listing_key; + + // Determine if HomeProz if not explicitly provided + if ($is_homeproz === null) { + $is_homeproz = $this->is_homeproz_listing($listing_key); + } + + $base_dir = $is_homeproz ? $this->get_persistent_upload_dir() : $this->get_upload_dir(); + return $base_dir . '/' . $prefix . '/' . $listing_key; + } + + /** + * Get the base URL for a listing's media + * + * @param string $listing_key Listing key + * @param bool|null $is_homeproz Override HomeProz check (null = look up from DB) + * @return string URL + */ + public function get_listing_url($listing_key, $is_homeproz = null) { + $prefix = substr($listing_key, 0, 2); + + if ($is_homeproz === null) { + $is_homeproz = $this->is_homeproz_listing($listing_key); + } + + $base_url = $is_homeproz ? $this->get_persistent_upload_url() : $this->get_upload_url(); + return $base_url . '/' . $prefix . '/' . $listing_key; + } + + /** + * Find existing cached file for a listing, checking both persistent and standard cache + * + * @param string $listing_key Listing key + * @param string $filename Filename to find + * @return array|null ['path' => absolute path, 'url' => url, 'persistent' => bool] or null + */ + public function find_cached_file($listing_key, $filename) { + $prefix = substr($listing_key, 0, 2); + + // Check persistent cache first (HomeProz listings) + $persistent_path = $this->get_persistent_upload_dir() . '/' . $prefix . '/' . $listing_key . '/' . $filename; + if (file_exists($persistent_path)) { + return array( + 'path' => $persistent_path, + 'url' => $this->get_persistent_upload_url() . '/' . $prefix . '/' . $listing_key . '/' . $filename, + 'persistent' => true, + ); + } + + // Check standard cache + $standard_path = $this->get_upload_dir() . '/' . $prefix . '/' . $listing_key . '/' . $filename; + if (file_exists($standard_path)) { + return array( + 'path' => $standard_path, + 'url' => $this->get_upload_url() . '/' . $prefix . '/' . $listing_key . '/' . $filename, + 'persistent' => false, + ); + } + + return null; } /** @@ -241,15 +345,40 @@ class MLS_Media_Handler { ); if ($existing) { - // Check if URL changed - if so, clear cached file - if ($existing->media_url !== ($media['MediaURL'] ?? null) && $existing->local_path) { - $file_path = $this->get_upload_dir() . '/' . $existing->local_path; - if (file_exists($file_path)) { - unlink($file_path); + // Check if URL changed + $url_changed = $existing->media_url !== ($media['MediaURL'] ?? null); + + if ($url_changed && $existing->local_path) { + // Check if this is a HomeProz listing + $is_homeproz = $this->is_homeproz_listing($listing_key); + + if ($is_homeproz) { + // HomeProz: Keep existing cached file, don't reset local_path + // The existing image continues to work even if MLS URL expires + // Only replace if a new download succeeds later + } else { + // Non-HomeProz: Delete old cached files to save space + $filename = basename($existing->local_path); + $prefix = substr($listing_key, 0, 2); + + // Delete from standard cache + $standard_path = $this->get_upload_dir() . '/' . $prefix . '/' . $listing_key . '/' . $filename; + if (file_exists($standard_path)) { + unlink($standard_path); + } + + // Also delete WebP versions + $webp_filename = preg_replace('/\.[^.]+$/', '.webp', $filename); + $webp_standard = $this->get_upload_dir() . '/' . $prefix . '/' . $listing_key . '/' . $webp_filename; + if (file_exists($webp_standard)) { + unlink($webp_standard); + } + + $data['local_path'] = null; + $data['local_url'] = null; + $data['downloaded_at'] = null; + $data['download_status'] = 'pending'; } - $data['local_path'] = null; - $data['local_url'] = null; - $data['downloaded_at'] = null; } $wpdb->update( @@ -269,7 +398,7 @@ class MLS_Media_Handler { } } - // Delete orphaned media records + // Delete orphaned media records and their files if (!empty($received_keys)) { $placeholders = implode(',', array_fill(0, count($received_keys), '%s')); $values = array_merge(array($listing_key), $received_keys); @@ -282,21 +411,220 @@ class MLS_Media_Handler { foreach ($orphaned as $record) { if ($record->local_path) { - $file_path = $this->get_upload_dir() . '/' . $record->local_path; - if (file_exists($file_path)) { - unlink($file_path); + $filename = basename($record->local_path); + $prefix = substr($listing_key, 0, 2); + + // Delete from both directories + $paths_to_delete = array( + $this->get_upload_dir() . '/' . $prefix . '/' . $listing_key . '/' . $filename, + $this->get_persistent_upload_dir() . '/' . $prefix . '/' . $listing_key . '/' . $filename, + ); + + // Also include WebP versions + $webp_filename = preg_replace('/\.[^.]+$/', '.webp', $filename); + $paths_to_delete[] = $this->get_upload_dir() . '/' . $prefix . '/' . $listing_key . '/' . $webp_filename; + $paths_to_delete[] = $this->get_persistent_upload_dir() . '/' . $prefix . '/' . $listing_key . '/' . $webp_filename; + + foreach ($paths_to_delete as $path) { + if (file_exists($path)) { + unlink($path); + } } } $wpdb->delete($this->db->media_table(), array('id' => $record->id)); } } + // Update property's media_expires_at with earliest expiration from all media URLs + $this->update_property_media_expiration($listing_key); + return array('stored' => $stored, 'skipped' => $skipped); } + /** + * Download and cache all images for a HomeProz listing + * + * Called during sync to immediately cache images for HomeProz listings + * so they're available even after the listing is sold and removed from MLS. + * + * @param string $listing_key Listing key + * @param callable|null $progress_callback Progress callback + * @param int $delay_seconds Delay between each image download (default 10s to respect API limits) + * @return array Stats with 'downloaded', 'skipped', and 'errors' counts + */ + public function download_homeproz_images($listing_key, $progress_callback = null, $delay_seconds = 10) { + global $wpdb; + + $stats = array('downloaded' => 0, 'skipped' => 0, 'errors' => 0); + + // Get all media records that haven't been downloaded yet + $media_records = $wpdb->get_results($wpdb->prepare( + "SELECT * FROM {$this->db->media_table()} + WHERE listing_key = %s AND media_url IS NOT NULL AND download_status = 'pending' + ORDER BY media_order ASC", + $listing_key + )); + + if (empty($media_records)) { + return $stats; + } + + $total_records = count($media_records); + $current = 0; + + foreach ($media_records as $media) { + $current++; + + // Check if already cached (check both directories) + // Try known local_path first, then search by media_order pattern + $found_file = null; + + if ($media->local_path) { + $filename = basename($media->local_path); + + // Check for WebP version first + $webp_filename = preg_replace('/\.[^.]+$/', '.webp', $filename); + $found_file = $this->find_cached_file($listing_key, $webp_filename); + + // Check for original file + if (!$found_file) { + $found_file = $this->find_cached_file($listing_key, $filename); + } + } + + // If no local_path or file not found, search by media_order pattern + if (!$found_file) { + $extensions = array('webp', 'jpg', 'jpeg', 'png', 'gif'); + foreach ($extensions as $ext) { + $pattern_file = $media->media_order . '.' . $ext; + $found_file = $this->find_cached_file($listing_key, $pattern_file); + if ($found_file) { + break; + } + } + } + + // If file exists on disk, update database and skip download + if ($found_file) { + // Update database to reflect the cached file + $prefix = substr($listing_key, 0, 2); + $filename = basename($found_file['path']); + $relative_path = $prefix . '/' . $listing_key . '/' . $filename; + + $wpdb->update( + $this->db->media_table(), + array( + 'local_path' => $relative_path, + 'local_url' => $found_file['url'], + 'download_status' => 'completed', + 'downloaded_at' => current_time('mysql'), + ), + array('id' => $media->id) + ); + + $stats['skipped']++; + if ($progress_callback) { + call_user_func($progress_callback, 'media_skipped', array('media_key' => $media->media_key)); + } + continue; + } + + // Download the image + $url = $this->fetch_and_cache($media); + if ($url) { + $stats['downloaded']++; + if ($progress_callback) { + call_user_func($progress_callback, 'media_downloaded', array('media_key' => $media->media_key)); + } + + // Rate limit: delay between image downloads to respect MLS API limits + // Only delay if there are more images to download + if ($delay_seconds > 0 && $current < $total_records) { + sleep($delay_seconds); + } + } else { + $stats['errors']++; + if ($progress_callback) { + call_user_func($progress_callback, 'media_error', array('media_key' => $media->media_key)); + } + } + } + + return $stats; + } + + /** + * Update a property's media_expires_at field based on its media URLs + * + * Finds the earliest expiration timestamp from all media URLs + * and sets it on the property record. + * + * @param string $listing_key Listing key + */ + public function update_property_media_expiration($listing_key) { + global $wpdb; + + // Get all media URLs for this property + $media_urls = $wpdb->get_col($wpdb->prepare( + "SELECT media_url FROM {$this->db->media_table()} + WHERE listing_key = %s AND media_url IS NOT NULL", + $listing_key + )); + + if (empty($media_urls)) { + return; + } + + // Find the earliest expiration timestamp + $earliest_expires = null; + + foreach ($media_urls as $url) { + $expires = $this->extract_url_expiration($url); + if ($expires !== null) { + if ($earliest_expires === null || $expires < $earliest_expires) { + $earliest_expires = $expires; + } + } + } + + // Update the property record + if ($earliest_expires !== null) { + $expires_at = gmdate('Y-m-d H:i:s', $earliest_expires); + $wpdb->update( + $this->db->properties_table(), + array('media_expires_at' => $expires_at), + array('listing_key' => $listing_key), + array('%s'), + array('%s') + ); + } + } + + /** + * Extract expiration timestamp from a media URL + * + * MLS Grid media URLs contain an 'expires' parameter with Unix timestamp. + * + * @param string $media_url The media URL + * @return int|null Unix timestamp or null if not found + */ + public function extract_url_expiration($media_url) { + if (empty($media_url)) { + return null; + } + + if (preg_match('/expires=(\d+)/', $media_url, $matches)) { + return (int) $matches[1]; + } + + return null; + } + /** * Get image URL for a media record, fetching on-demand if needed * + * Checks both persistent (HomeProz) and standard cache directories. + * * @param int|object $media Media ID or media record object * @param bool $fetch_if_missing Whether to fetch if not cached * @return string|null Local URL or null @@ -316,24 +644,29 @@ class MLS_Media_Handler { return null; } - // Already cached - check for WebP version first - if ($media->local_url && $media->local_path) { - $file_path = $this->get_upload_dir() . '/' . $media->local_path; - $actual_path = $this->prefer_webp_path($file_path); - if (file_exists($actual_path)) { - // If WebP version exists, return WebP URL - if ($actual_path !== $file_path) { - $webp_path = preg_replace('/\.[^.]+$/', '.webp', $media->local_path); - return $this->get_upload_url() . '/' . $webp_path; - } - return $media->local_url; + // Check for cached file in both directories + if ($media->local_path) { + $filename = basename($media->local_path); + + // Check for WebP version first + $webp_filename = preg_replace('/\.[^.]+$/', '.webp', $filename); + $webp_found = $this->find_cached_file($media->listing_key, $webp_filename); + if ($webp_found) { + return $webp_found['url']; + } + + // Check for original file + $found = $this->find_cached_file($media->listing_key, $filename); + if ($found) { + return $found['url']; } } // Fetch on demand if ($fetch_if_missing && $media->media_url) { $result = $this->fetch_and_cache($media); - if ($result) { + // Propagate WP_Error (e.g., rate limiting) or return URL + if (is_wp_error($result) || $result) { return $result; } } @@ -344,6 +677,8 @@ class MLS_Media_Handler { /** * Get primary image URL for a listing (on-demand) * + * Checks both persistent (HomeProz) and standard cache directories. + * * @param string $listing_key Listing key * @param bool $fetch_if_missing Whether to fetch if not cached * @return string|null Image URL @@ -360,16 +695,20 @@ class MLS_Media_Handler { $listing_key )); - if ($cached) { - $file_path = $this->get_upload_dir() . '/' . $cached->local_path; - $actual_path = $this->prefer_webp_path($file_path); - if (file_exists($actual_path)) { - // If WebP version exists, return WebP URL - if ($actual_path !== $file_path) { - $webp_path = preg_replace('/\.[^.]+$/', '.webp', $cached->local_path); - return $this->get_upload_url() . '/' . $webp_path; - } - return $cached->local_url; + if ($cached && $cached->local_path) { + $filename = basename($cached->local_path); + + // Check for WebP version first + $webp_filename = preg_replace('/\.[^.]+$/', '.webp', $filename); + $webp_found = $this->find_cached_file($listing_key, $webp_filename); + if ($webp_found) { + return $webp_found['url']; + } + + // Check for original file + $found = $this->find_cached_file($listing_key, $filename); + if ($found) { + return $found['url']; } } @@ -386,17 +725,21 @@ class MLS_Media_Handler { return null; } - // If already cached and file exists, return it - check for WebP first - if ($media->local_url && $media->local_path) { - $file_path = $this->get_upload_dir() . '/' . $media->local_path; - $actual_path = $this->prefer_webp_path($file_path); - if (file_exists($actual_path)) { - // If WebP version exists, return WebP URL - if ($actual_path !== $file_path) { - $webp_path = preg_replace('/\.[^.]+$/', '.webp', $media->local_path); - return $this->get_upload_url() . '/' . $webp_path; - } - return $media->local_url; + // Check for cached file in both directories + if ($media->local_path) { + $filename = basename($media->local_path); + + // Check for WebP version first + $webp_filename = preg_replace('/\.[^.]+$/', '.webp', $filename); + $webp_found = $this->find_cached_file($listing_key, $webp_filename); + if ($webp_found) { + return $webp_found['url']; + } + + // Check for original file + $found = $this->find_cached_file($listing_key, $filename); + if ($found) { + return $found['url']; } } @@ -411,6 +754,8 @@ class MLS_Media_Handler { /** * Get all images for a listing (on-demand for first N) * + * Checks both persistent (HomeProz) and standard cache directories. + * * @param string $listing_key Listing key * @param int $fetch_limit Max images to fetch on-demand (0 = none) * @return array Media records with local_url populated where available @@ -431,16 +776,22 @@ class MLS_Media_Handler { $fetched = 0; foreach ($media as &$item) { - // Check if cached and file exists - prefer WebP version - if ($item->local_url && $item->local_path) { - $file_path = $this->get_upload_dir() . '/' . $item->local_path; - $actual_path = $this->prefer_webp_path($file_path); - if (file_exists($actual_path)) { - // If WebP version exists, update the URL - if ($actual_path !== $file_path) { - $webp_path = preg_replace('/\.[^.]+$/', '.webp', $item->local_path); - $item->local_url = $this->get_upload_url() . '/' . $webp_path; - } + // Check for cached file in both directories - prefer WebP version + if ($item->local_path) { + $filename = basename($item->local_path); + + // Check for WebP version first + $webp_filename = preg_replace('/\.[^.]+$/', '.webp', $filename); + $webp_found = $this->find_cached_file($listing_key, $webp_filename); + if ($webp_found) { + $item->local_url = $webp_found['url']; + continue; + } + + // Check for original file + $found = $this->find_cached_file($listing_key, $filename); + if ($found) { + $item->local_url = $found['url']; continue; } } @@ -509,23 +860,97 @@ class MLS_Media_Handler { } try { + // Determine if this is a HomeProz listing (determines cache location) + $is_homeproz = $this->is_homeproz_listing($media->listing_key); + // Re-check if image was cached while we waited for lock $updated_media = $wpdb->get_row($wpdb->prepare( "SELECT local_path, local_url FROM {$this->db->media_table()} WHERE id = %d", $media->id )); + // Check for existing file - first by local_path, then by media_order pattern + $found_file = null; + if ($updated_media && $updated_media->local_path) { - $file_path = $this->get_upload_dir() . '/' . $updated_media->local_path; - $actual_path = $this->prefer_webp_path($file_path); - if (file_exists($actual_path)) { - // Another request cached it while we waited - // If WebP version exists, return WebP URL - if ($actual_path !== $file_path) { - $webp_path = preg_replace('/\.[^.]+$/', '.webp', $updated_media->local_path); - return $this->get_upload_url() . '/' . $webp_path; + // Check both cache directories for existing file + $filename = basename($updated_media->local_path); + + // Check for WebP version first + $webp_filename = preg_replace('/\.[^.]+$/', '.webp', $filename); + $found_file = $this->find_cached_file($media->listing_key, $webp_filename); + + if (!$found_file) { + $found_file = $this->find_cached_file($media->listing_key, $filename); + } + } + + // If no local_path or file not found, search by media_order pattern + if (!$found_file) { + $extensions = array('webp', 'jpg', 'jpeg', 'png', 'gif'); + foreach ($extensions as $ext) { + $pattern_file = $media->media_order . '.' . $ext; + $found_file = $this->find_cached_file($media->listing_key, $pattern_file); + if ($found_file) { + break; } - return $updated_media->local_url; + } + } + + // If file exists on disk, update database and return URL + if ($found_file) { + $prefix = substr($media->listing_key, 0, 2); + $filename = basename($found_file['path']); + $relative_path = $prefix . '/' . $media->listing_key . '/' . $filename; + + $wpdb->update( + $this->db->media_table(), + array( + 'local_path' => $relative_path, + 'local_url' => $found_file['url'], + 'download_status' => 'completed', + 'downloaded_at' => current_time('mysql'), + ), + array('id' => $media->id) + ); + + return $found_file['url']; + } + + // If the media URL has expired, refresh property URLs from the API. + // Use a property-level lock so concurrent fetches share one refresh. + if ($this->is_url_expired($media->media_url)) { + $refresh_lock = 'mls_url_refresh_' . $media->listing_key; + $refresh_acquired = $wpdb->get_var($wpdb->prepare( + "SELECT GET_LOCK(%s, %d)", + $refresh_lock, + 15 + )); + + try { + if ($refresh_acquired === '1') { + // Re-check after lock — another process may have refreshed + $latest = $wpdb->get_row($wpdb->prepare( + "SELECT media_url FROM {$this->db->media_table()} WHERE id = %d", + $media->id + )); + if (!$latest || $this->is_url_expired($latest->media_url)) { + $this->refresh_media_urls($media->listing_key); + } + } + + $media = $wpdb->get_row($wpdb->prepare( + "SELECT * FROM {$this->db->media_table()} WHERE id = %d", + $media->id + )); + } finally { + if ($refresh_acquired === '1') { + $wpdb->query($wpdb->prepare("SELECT RELEASE_LOCK(%s)", $refresh_lock)); + } + } + + if (!$media || empty($media->media_url) || $this->is_url_expired($media->media_url)) { + return null; } } @@ -558,6 +983,10 @@ class MLS_Media_Handler { 'media_key' => $media->media_key, 'status' => $status_code, )); + // Return error code for rate limiting so caller can handle appropriately + if ($status_code === 429) { + return new WP_Error('rate_limited', 'MLS Grid rate limit exceeded', array('status' => 429)); + } return null; } @@ -574,8 +1003,8 @@ class MLS_Media_Handler { $content_type = wp_remote_retrieve_header($response, 'content-type'); $extension = $this->get_extension_from_content_type($content_type, $media->media_url); - // Create directory - $listing_dir = $this->get_listing_dir($media->listing_key); + // Create directory (HomeProz listings go to persistent cache) + $listing_dir = $this->get_listing_dir($media->listing_key, $is_homeproz); if (!file_exists($listing_dir)) { wp_mkdir_p($listing_dir); } @@ -600,10 +1029,11 @@ class MLS_Media_Handler { $content_type = 'image/webp'; } - // Update database + // Update database with correct URL based on cache location $prefix = substr($media->listing_key, 0, 2); $relative_path = $prefix . '/' . $media->listing_key . '/' . $filename; - $local_url = $this->get_upload_url() . '/' . $relative_path; + $base_url = $is_homeproz ? $this->get_persistent_upload_url() : $this->get_upload_url(); + $local_url = $base_url . '/' . $relative_path; // Get actual file size after any conversion $final_size = filesize($file_path); @@ -616,6 +1046,7 @@ class MLS_Media_Handler { 'file_size' => $final_size, 'mime_type' => $content_type, 'downloaded_at' => current_time('mysql'), + 'download_status' => 'completed', ), array('id' => $media->id) ); @@ -668,15 +1099,25 @@ class MLS_Media_Handler { /** * Delete all media for a property * + * Deletes from both persistent and standard cache directories. + * * @param string $listing_key Listing key */ public function delete_property_media($listing_key) { global $wpdb; - // Delete files - $listing_dir = $this->get_listing_dir($listing_key); - if (file_exists($listing_dir)) { - $this->recursive_delete($listing_dir); + $prefix = substr($listing_key, 0, 2); + + // Delete from persistent cache directory + $persistent_dir = $this->get_persistent_upload_dir() . '/' . $prefix . '/' . $listing_key; + if (file_exists($persistent_dir)) { + $this->recursive_delete($persistent_dir); + } + + // Delete from standard cache directory + $standard_dir = $this->get_upload_dir() . '/' . $prefix . '/' . $listing_key; + if (file_exists($standard_dir)) { + $this->recursive_delete($standard_dir); } // Delete records @@ -811,43 +1252,52 @@ class MLS_Media_Handler { /** * Clean up orphaned media files (files without database records) * + * Checks both standard and persistent cache directories. + * * @return int Number of directories deleted */ public function cleanup_orphaned_files() { global $wpdb; $deleted = 0; - $base_dir = $this->get_upload_dir(); - if (!is_dir($base_dir)) { - return 0; - } + // Check both cache directories + $directories = array( + $this->get_upload_dir(), + $this->get_persistent_upload_dir(), + ); - foreach (scandir($base_dir) as $prefix) { - if ($prefix === '.' || $prefix === '..' || !is_dir($base_dir . '/' . $prefix)) { + foreach ($directories as $base_dir) { + if (!is_dir($base_dir)) { continue; } - $prefix_dir = $base_dir . '/' . $prefix; - - foreach (scandir($prefix_dir) as $listing_key) { - if ($listing_key === '.' || $listing_key === '..') { + foreach (scandir($base_dir) as $prefix) { + if ($prefix === '.' || $prefix === '..' || !is_dir($base_dir . '/' . $prefix)) { continue; } - $listing_dir = $prefix_dir . '/' . $listing_key; - if (!is_dir($listing_dir)) { - continue; - } + $prefix_dir = $base_dir . '/' . $prefix; - $exists = $wpdb->get_var($wpdb->prepare( - "SELECT COUNT(*) FROM {$this->db->properties_table()} WHERE listing_key = %s", - $listing_key - )); + foreach (scandir($prefix_dir) as $listing_key) { + if ($listing_key === '.' || $listing_key === '..') { + continue; + } - if (!$exists) { - $this->recursive_delete($listing_dir); - $deleted++; + $listing_dir = $prefix_dir . '/' . $listing_key; + if (!is_dir($listing_dir)) { + continue; + } + + $exists = $wpdb->get_var($wpdb->prepare( + "SELECT COUNT(*) FROM {$this->db->properties_table()} WHERE listing_key = %s", + $listing_key + )); + + if (!$exists) { + $this->recursive_delete($listing_dir); + $deleted++; + } } } } diff --git a/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-query.php b/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-query.php index f13d1e7d..35d1c2de 100755 --- a/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-query.php +++ b/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-query.php @@ -50,6 +50,25 @@ class MLS_Query { return "(street_number IS NULL OR (street_number != 'TBD' AND street_number NOT LIKE 'TBD %'))"; } + /** + * Build a WHERE clause for property_type, supporting comma-separated values. + * + * @param string $property_type Single type or comma-separated types + * @param array &$where WHERE clause fragments + * @param array &$values Prepared statement values + */ + private function build_property_type_clause($property_type, &$where, &$values) { + $types = array_filter(array_map('trim', explode(',', $property_type))); + if (count($types) === 1) { + $where[] = 'property_type = %s'; + $values[] = $types[0]; + } elseif (count($types) > 1) { + $placeholders = implode(',', array_fill(0, count($types), '%s')); + $where[] = "property_type IN ({$placeholders})"; + $values = array_merge($values, $types); + } + } + /** * Get coordinates for a zip code from geo table * @@ -246,13 +265,20 @@ class MLS_Query { } if ($args['status']) { - $where[] = 'standard_status = %s'; - $values[] = $args['status']; + if (is_array($args['status'])) { + // Multiple statuses - use IN clause + $placeholders = implode(',', array_fill(0, count($args['status']), '%s')); + $where[] = "standard_status IN ({$placeholders})"; + $values = array_merge($values, $args['status']); + } else { + // Single status + $where[] = 'standard_status = %s'; + $values[] = $args['status']; + } } if ($args['property_type']) { - $where[] = 'property_type = %s'; - $values[] = $args['property_type']; + $this->build_property_type_clause($args['property_type'], $where, $values); } // City and postal_code are mutually exclusive - city takes priority @@ -503,17 +529,16 @@ class MLS_Query { } $sql = "SELECT * FROM {$table}"; + // Don't filter by status here - we filter AFTER normalization + // because status is derived from MLS for linked properties $where = array("standard_status != 'Withdrawn'"); $values = array(); - if ($args['status']) { - $where[] = 'standard_status = %s'; - $values[] = $args['status']; - } + // Store requested status for post-normalization filtering + $requested_status = $args['status']; if ($args['property_type']) { - $where[] = 'property_type = %s'; - $values[] = $args['property_type']; + $this->build_property_type_clause($args['property_type'], $where, $values); } if ($args['city']) { @@ -566,6 +591,31 @@ class MLS_Query { $values[] = $args['listing_id']; } + // Filter by agent MLS ID - find agent post with this MLS ID + if (!empty($args['agent_mls_id'])) { + $agent_query = new WP_Query(array( + 'post_type' => 'agent', + 'posts_per_page' => 1, + 'post_status' => 'publish', + 'fields' => 'ids', + 'meta_query' => array( + array( + 'key' => 'agent_mls_id', + 'value' => $args['agent_mls_id'], + 'compare' => '=', + ), + ), + )); + if ($agent_query->have_posts()) { + $where[] = 'list_agent_post_id = %d'; + $values[] = $agent_query->posts[0]; + } else { + // No agent found with this MLS ID - return empty for manual properties + return array(); + } + wp_reset_postdata(); + } + if ($args['search']) { $search_term = '%' . $wpdb->esc_like($args['search']) . '%'; $where[] = '(full_address LIKE %s OR city LIKE %s OR public_remarks LIKE %s OR listing_id LIKE %s)'; @@ -616,10 +666,22 @@ class MLS_Query { } // Normalize results to match MLS schema + // This fetches the real status from MLS for linked properties foreach ($results as $key => $property) { $results[$key] = $this->normalize_manual_property($property); } + // Filter by status AFTER normalization (status is now MLS-derived) + if ($requested_status) { + $results = array_filter($results, function($property) use ($requested_status) { + if (is_array($requested_status)) { + return in_array($property->standard_status, $requested_status); + } + return $property->standard_status === $requested_status; + }); + $results = array_values($results); // Re-index array + } + return $results; } @@ -668,9 +730,99 @@ class MLS_Query { } } + // Check if media records need refresh (for single property view) + if ($property) { + $this->ensure_media_records($property); + } + return $property; } + /** + * Ensure media records exist and are fresh for a property + * + * Checks if: + * 1. Media record count < photos_count (missing media records) + * 2. Any media URLs are expired + * + * If either condition is true, refreshes media from the API. + * + * @param object $property Property object with listing_key, listing_id, photos_count + */ + private function ensure_media_records($property) { + global $wpdb; + + // Skip for spider/bot requests to avoid unnecessary API calls + if (function_exists('homeproz_is_spider') && homeproz_is_spider()) { + return; + } + + // Skip if no photos or no listing_id (can't fetch from API without it) + if (empty($property->photos_count) || $property->photos_count <= 0) { + return; + } + if (empty($property->listing_id)) { + return; + } + + $media_table = $this->db->media_table(); + $listing_key = $property->listing_key; + + // Single query to get media count and earliest expiry + $media_stats = $wpdb->get_row($wpdb->prepare( + "SELECT COUNT(*) as media_count, MIN(url_expires_at) as earliest_expiry + FROM {$media_table} + WHERE listing_key = %s", + $listing_key + )); + + $media_count = (int) ($media_stats ? $media_stats->media_count : 0); + $earliest_expiry = $media_stats ? $media_stats->earliest_expiry : null; + + // Check 1: Do we have fewer media records than photos? + $needs_refresh = $media_count < $property->photos_count; + + // Check 2: Are any URLs expired? (only check if we have records) + if (!$needs_refresh && $media_count > 0 && $earliest_expiry) { + $needs_refresh = strtotime($earliest_expiry) < time(); + } + + if (!$needs_refresh) { + return; + } + + // Refresh media from API + $this->refresh_property_media($property->listing_key, $property->listing_id); + } + + /** + * Refresh media records for a property from the MLS API + * + * @param string $listing_key Property listing key + * @param string $listing_id Property listing ID (MLS ID) + */ + private function refresh_property_media($listing_key, $listing_id) { + $plugin = mls_plugin(); + $api_client = $plugin->get_api_client(); + $media_handler = $plugin->get_media_handler(); + + if (!$api_client || !$media_handler) { + return; + } + + // Fetch property with media from API + $property_data = $api_client->get_property_media($listing_id); + + if (is_wp_error($property_data) || empty($property_data)) { + return; + } + + // Sync media records (URLs only, no downloads) + if (isset($property_data['Media']) && is_array($property_data['Media'])) { + $media_handler->sync_property_media($listing_key, $property_data['Media']); + } + } + /** * Get a manual property by listing key or listing ID * @@ -979,8 +1131,7 @@ class MLS_Query { } if (!empty($args['property_type'])) { - $where[] = 'property_type = %s'; - $values[] = $args['property_type']; + $this->build_property_type_clause($args['property_type'], $where, $values); } // City and postal_code are mutually exclusive - city takes priority @@ -1095,8 +1246,7 @@ class MLS_Query { } if (!empty($args['property_type'])) { - $where[] = 'property_type = %s'; - $values[] = $args['property_type']; + $this->build_property_type_clause($args['property_type'], $where, $values); } if (!empty($args['city'])) { @@ -1327,8 +1477,7 @@ class MLS_Query { } if (!empty($args['property_type'])) { - $where[] = 'property_type = %s'; - $values[] = $args['property_type']; + $this->build_property_type_clause($args['property_type'], $where, $values); } // City and postal_code are mutually exclusive - city takes priority diff --git a/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-rate-limiter.php b/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-rate-limiter.php index 166abb8c..3e7d34c2 100755 --- a/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-rate-limiter.php +++ b/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-rate-limiter.php @@ -29,15 +29,37 @@ class MLS_Rate_Limiter { const MLSGRID_BYTES_PER_DAY = 42949672960; // 40GB /** - * Sync operation limits (50% of daily quota paced over 24 hours) + * Sync operation limits * - * Goal: If sync ran continuously for 24h, use max 50% of daily quota - * - 20,000 requests / 86,400 seconds = 0.23 RPS (~4.3s between requests) - * - 20GB data / 86,400 seconds = ~243KB/s average + * Fixed 5-second interval between API requests for rock-solid rate limiting. + * This ensures we never exceed MLS Grid limits regardless of sync duration. + * + * At 5s intervals: 17,280 requests/day max (43% of 40,000 limit) */ - const SYNC_REQUESTS_PER_DAY = 20000; // 50% of 40,000 + const SYNC_REQUESTS_PER_DAY = 17280; // 86400s / 5s = 17,280 max const SYNC_BYTES_PER_DAY = 21474836480; // 20GB (50% of 40GB) - const SYNC_MIN_INTERVAL_MS = 4320; // 86400000ms / 20000 = 4.32s between requests + const SYNC_MIN_INTERVAL_MS = 5000; // 5 seconds between requests (legacy) + + /** + * Global rate limit intervals (cross-process coordination via MySQL advisory locks) + * + * These are enforced across ALL processes to stay well under MLS Grid limits. + * MLS Grid warns at 2 RPS, suspends at 4+ RPS. We use conservative intervals. + */ + const GENERAL_API_INTERVAL_MS = 4000; // 4 seconds between general API requests + const IMAGE_API_INTERVAL_MS = 2000; // 2 seconds between image API requests + + /** + * Advisory lock names for cross-process coordination + */ + const LOCK_GENERAL_API = 'mls_api_general'; + const LOCK_IMAGE_API = 'mls_api_image'; + + /** + * Option keys for storing last request times + */ + const OPTION_LAST_GENERAL_REQUEST = 'mls_last_general_api_request'; + const OPTION_LAST_IMAGE_REQUEST = 'mls_last_image_api_request'; /** * Rate limit constants (used for tracking against MLS Grid limits) @@ -58,11 +80,6 @@ class MLS_Rate_Limiter { */ private $db; - /** - * Last request timestamp for per-second limiting - */ - private $last_request_time = 0; - /** * Constructor * @@ -72,19 +89,131 @@ class MLS_Rate_Limiter { $this->db = $db; } + /** + * Wait for and acquire the global API rate limit (general API) + * + * Uses MySQL advisory locks to coordinate across all PHP processes. + * Enforces 4-second minimum interval between general API requests. + * + * @param int $timeout_seconds Max seconds to wait for lock (0 = non-blocking) + * @return bool True if rate limit acquired, false if timeout + */ + public function acquire_general_api_slot($timeout_seconds = 30) { + return $this->acquire_api_slot( + self::LOCK_GENERAL_API, + self::OPTION_LAST_GENERAL_REQUEST, + self::GENERAL_API_INTERVAL_MS, + $timeout_seconds + ); + } + + /** + * Wait for and acquire the global API rate limit (image API) + * + * Uses MySQL advisory locks to coordinate across all PHP processes. + * Enforces 2-second minimum interval between image API requests. + * + * @param int $timeout_seconds Max seconds to wait for lock (0 = non-blocking) + * @return bool True if rate limit acquired, false if timeout + */ + public function acquire_image_api_slot($timeout_seconds = 30) { + return $this->acquire_api_slot( + self::LOCK_IMAGE_API, + self::OPTION_LAST_IMAGE_REQUEST, + self::IMAGE_API_INTERVAL_MS, + $timeout_seconds + ); + } + + /** + * Internal method to acquire an API slot with advisory lock coordination + * + * @param string $lock_name Advisory lock name + * @param string $option_key Option key for last request timestamp + * @param int $interval_ms Minimum interval between requests in milliseconds + * @param int $timeout_seconds Max seconds to wait + * @return bool True if slot acquired + */ + private function acquire_api_slot($lock_name, $option_key, $interval_ms, $timeout_seconds) { + global $wpdb; + + $start_time = time(); + $interval_sec = $interval_ms / 1000.0; + + while (true) { + // Check timeout + if ($timeout_seconds > 0 && (time() - $start_time) >= $timeout_seconds) { + return false; + } + + // Try to acquire the advisory lock (blocking for up to 1 second) + $lock_acquired = $wpdb->get_var($wpdb->prepare( + "SELECT GET_LOCK(%s, %d)", + $lock_name, + 1 // 1 second timeout for each attempt + )); + + if ($lock_acquired !== '1') { + // Lock held by another process, wait and retry + usleep(100000); // 100ms + continue; + } + + try { + // We have the lock - check/wait for rate limit interval + $last_request = (float) get_option($option_key, 0); + $now = microtime(true); + $elapsed = $now - $last_request; + + if ($elapsed < $interval_sec) { + // Need to wait for the remaining interval + $wait_time = ($interval_sec - $elapsed) * 1000000; // Convert to microseconds + usleep((int) $wait_time); + } + + // Update the last request timestamp + update_option($option_key, microtime(true), false); // false = don't autoload + + return true; + + } finally { + // Always release the advisory lock + $wpdb->query($wpdb->prepare("SELECT RELEASE_LOCK(%s)", $lock_name)); + } + } + } + + /** + * Rate limit channels + */ + const CHANNEL_GENERAL = 'general'; + const CHANNEL_IMAGE = 'image'; + /** * Check if we can make a request (and wait if needed) * - * For sync operations, this enforces the 50% daily quota pacing. - * The minimum interval between requests ensures that even continuous - * syncing won't exceed 50% of the daily quota. + * Uses global advisory lock-based rate limiting to coordinate across + * all PHP processes. Different channels have different intervals: + * - general: 4-second interval + * - image: 2-second interval * * @param bool $wait Whether to wait if rate limited + * @param string $channel Rate limit channel ('general' or 'image') * @return bool True if request can proceed */ - public function check_and_wait($wait = true) { - // Enforce sync pacing (4.32s between requests for 50% daily quota) - $this->enforce_sync_pacing(); + public function check_and_wait($wait = true, $channel = self::CHANNEL_GENERAL) { + // Use global advisory lock-based rate limiting + $timeout = $wait ? 60 : 0; + + if ($channel === self::CHANNEL_IMAGE) { + if (!$this->acquire_image_api_slot($timeout)) { + return false; + } + } else { + if (!$this->acquire_general_api_slot($timeout)) { + return false; + } + } // Check hourly limit (hard stop if approaching MLS Grid limits) if (!$this->check_limit(self::WINDOW_HOUR, self::LIMIT_PER_HOUR)) { @@ -107,27 +236,6 @@ class MLS_Rate_Limiter { return true; } - /** - * Enforce sync operation pacing - * - * Ensures minimum interval between sync requests so that - * 24 hours of continuous syncing uses max 50% of daily quota. - */ - private function enforce_sync_pacing() { - $now = microtime(true); - $min_interval = self::SYNC_MIN_INTERVAL_MS / 1000.0; // Convert ms to seconds (4.32s) - - if ($this->last_request_time > 0) { - $elapsed = $now - $this->last_request_time; - if ($elapsed < $min_interval) { - $sleep_time = ($min_interval - $elapsed) * 1000000; // microseconds - usleep((int) $sleep_time); - } - } - - $this->last_request_time = microtime(true); - } - /** * Check if under the limit for a window type * @@ -474,6 +582,8 @@ class MLS_Rate_Limiter { public function reset() { global $wpdb; $wpdb->query("TRUNCATE TABLE {$this->db->rate_limits_table()}"); - $this->last_request_time = 0; + // Reset global timestamps + delete_option(self::OPTION_LAST_GENERAL_REQUEST); + delete_option(self::OPTION_LAST_IMAGE_REQUEST); } } diff --git a/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-sync-engine.php b/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-sync-engine.php index e3dbb8b6..cdaf82ef 100755 --- a/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-sync-engine.php +++ b/wp-content/plugins/mls-by-hansonxyz/includes/class-mls-sync-engine.php @@ -21,6 +21,7 @@ class MLS_Sync_Engine { const TYPE_FULL = 'full'; const TYPE_INCREMENTAL = 'incremental'; const TYPE_MEDIA = 'media'; + const TYPE_MEDIA_REFRESH = 'media_refresh'; /** * Sync statuses @@ -65,6 +66,8 @@ class MLS_Sync_Engine { 'updated' => 0, 'deleted' => 0, 'errors' => 0, + 'homeproz_media_downloaded' => 0, + 'homeproz_media_skipped' => 0, ); /** @@ -387,6 +390,12 @@ class MLS_Sync_Engine { $this->logger->info('Incremental sync completed', $this->stats); + // Download pending media for HomeProz properties + // This catches any HomeProz listings that have media records but images weren't downloaded + $media_stats = $this->download_pending_homeproz_media($dry_run); + $this->stats['homeproz_media_downloaded'] = $media_stats['downloaded']; + $this->stats['homeproz_media_skipped'] = $media_stats['skipped']; + } catch (Exception $e) { $this->logger->error('Incremental sync failed', array('error' => $e->getMessage())); @@ -410,6 +419,211 @@ class MLS_Sync_Engine { ); } + /** + * Run media refresh sync for properties with expiring media URLs + * + * Fetches fresh data for properties whose media URLs will expire within + * the specified number of days. This prevents on-demand API calls when + * visitors try to view images with expired URLs. + * + * If a property is no longer listed (not Active/Pending or MlgCanView=false), + * it will be removed from the local database. + * + * @param int $days_ahead Number of days to look ahead for expiring media (default: 3) + * @param bool $dry_run If true, don't make changes + * @param callable|null $progress_callback Callback for progress updates + * @return array Sync results + */ + public function run_media_refresh_sync($days_ahead = 3, $dry_run = false, $progress_callback = null) { + global $wpdb; + + $this->logger->info('Starting media refresh sync', array( + 'days_ahead' => $days_ahead, + 'dry_run' => $dry_run, + )); + + $this->progress_callback = $progress_callback; + + if (!$dry_run) { + $this->sync_state_id = $this->create_sync_state(self::TYPE_MEDIA_REFRESH); + $this->logger->set_sync_state($this->sync_state_id); + } + + $this->stats = array( + 'processed' => 0, + 'created' => 0, + 'updated' => 0, + 'deleted' => 0, + 'errors' => 0, + ); + + try { + // Find properties with media expiring within X days + $expiry_threshold = gmdate('Y-m-d H:i:s', strtotime("+{$days_ahead} days")); + + // Include Active/Pending properties, plus Closed HomeProz properties + // (HomeProz wants to keep sold property images for portfolio) + $properties = $wpdb->get_results($wpdb->prepare( + "SELECT listing_key, listing_id, media_expires_at + FROM {$this->db->properties_table()} + WHERE (media_expires_at IS NULL OR media_expires_at <= %s) + AND (standard_status IN ('Active', 'Pending') OR (standard_status = 'Closed' AND is_homeproz = 1)) + ORDER BY media_expires_at ASC", + $expiry_threshold + )); + + $total = count($properties); + $this->logger->info("Found {$total} properties with expiring media"); + + $this->emit_progress('media_refresh_start', array( + 'total' => $total, + 'expiry_threshold' => $expiry_threshold, + )); + + // Process in batches of 25 (MLS Grid max with $expand) + $batch_size = 25; + $batches = array_chunk($properties, $batch_size); + $batch_num = 0; + + foreach ($batches as $batch) { + $batch_num++; + + // Build array of listing_ids for this batch + $listing_ids = array_map(function($prop) { + return $prop->listing_id; + }, $batch); + + // Fetch batch from API + $start_time = microtime(true); + $this->emit_progress('api_request', array( + 'method' => 'GET', + 'url' => 'Property', + 'params' => array('batch' => $batch_num, 'count' => count($listing_ids)), + )); + + $response = $this->api_client->get_properties_by_ids($listing_ids); + $elapsed = round((microtime(true) - $start_time) * 1000); + + if (is_wp_error($response)) { + $this->emit_progress('api_response', array( + 'success' => false, + 'status_code' => 0, + 'error' => $response->get_error_message(), + 'response_time' => $elapsed, + )); + + // Mark all in batch as errors + foreach ($batch as $prop) { + $this->stats['processed']++; + $this->stats['errors']++; + } + $this->logger->warning('Failed to fetch batch for media refresh', array( + 'batch' => $batch_num, + 'error' => $response->get_error_message(), + )); + continue; + } + + $returned_count = isset($response['value']) ? count($response['value']) : 0; + $this->emit_progress('api_response', array( + 'success' => true, + 'status_code' => 200, + 'response_time' => $elapsed, + 'record_count' => $returned_count, + )); + + // Index returned properties by ListingId + $returned_by_id = array(); + if (isset($response['value'])) { + foreach ($response['value'] as $property_data) { + if (isset($property_data['ListingId'])) { + $returned_by_id[$property_data['ListingId']] = $property_data; + } + } + } + + // Process each property in the batch + foreach ($batch as $prop) { + $this->stats['processed']++; + + if (isset($returned_by_id[$prop->listing_id])) { + // Property found - process_property handles its own progress events + $property_data = $returned_by_id[$prop->listing_id]; + + if (!$dry_run) { + $this->process_property($property_data, false); + } else { + $this->stats['updated']++; + $this->emit_progress('property_skipped', array( + 'listing_key' => $prop->listing_key, + )); + } + } else { + // Property not in API response - may have been removed + if (!$dry_run) { + $this->delete_property($prop->listing_key); + } + $this->stats['deleted']++; + $this->emit_progress('property_deleted', array( + 'listing_key' => $prop->listing_key, + 'reason' => 'Not found in API', + )); + } + } + + // Update sync state after each batch + if (!$dry_run) { + $this->update_sync_state(array( + 'records_processed' => $this->stats['processed'], + 'records_updated' => $this->stats['updated'], + 'records_deleted' => $this->stats['deleted'], + )); + } + + // Emit batch/page complete + $this->emit_progress('page_complete', array('processed' => $this->stats['processed'])); + } + + // Mark sync as completed + if (!$dry_run) { + $this->update_sync_state(array( + 'status' => self::STATUS_COMPLETED, + 'completed_at' => current_time('mysql'), + 'records_processed' => $this->stats['processed'], + 'records_updated' => $this->stats['updated'], + 'records_deleted' => $this->stats['deleted'], + )); + } + + $this->logger->info('Media refresh sync completed', $this->stats); + + $this->emit_progress('media_refresh_complete', array( + 'stats' => $this->stats, + )); + + } catch (Exception $e) { + $this->logger->error('Media refresh sync failed', array('error' => $e->getMessage())); + + if (!$dry_run) { + $this->update_sync_state(array( + 'status' => self::STATUS_FAILED, + 'last_error' => $e->getMessage(), + )); + } + + return array( + 'success' => false, + 'error' => $e->getMessage(), + 'stats' => $this->stats, + ); + } + + return array( + 'success' => true, + 'stats' => $this->stats, + ); + } + /** * Resume an interrupted sync * @@ -535,16 +749,24 @@ class MLS_Sync_Engine { private $progress_callback = null; /** - * Allowed statuses for our database (Active/Pending only) + * Allowed statuses for non-HomeProz listings (Active/Pending only) */ const ALLOWED_STATUSES = array('Active', 'Pending'); + /** + * Allowed statuses for HomeProz listings (includes Closed for historical records) + */ + const HOMEPROZ_ALLOWED_STATUSES = array('Active', 'Pending', 'Closed'); + /** * Process a single property record * * During replication, properties are deleted if: * - MlgCanView = false (removed from feed) - * - StandardStatus not in (Active, Pending) + * - StandardStatus not in allowed list (varies by HomeProz status) + * + * HomeProz listings are retained even when Closed (sold) for historical viewing. + * Non-HomeProz listings are deleted when status is not Active/Pending. * * @param array $property Property data from API * @param bool $dry_run If true, don't make changes @@ -565,8 +787,17 @@ class MLS_Sync_Engine { $can_view = $property['MlgCanView'] ?? true; $status = $property['StandardStatus'] ?? null; - // Delete if: not viewable OR status is not Active/Pending - $should_delete = !$can_view || !in_array($status, self::ALLOWED_STATUSES); + // Check if this is a HomeProz listing (by office ID or override list) + $listing_id = $property['ListingId'] ?? ''; + $is_homeproz = (($property['ListOfficeMlsId'] ?? '') === MLS_HOMEPROZ_OFFICE_ID) + || (defined('MLS_HOMEPROZ_OVERRIDE_LISTINGS') && in_array($listing_id, MLS_HOMEPROZ_OVERRIDE_LISTINGS)); + + // Determine allowed statuses based on whether it's a HomeProz listing + $allowed_statuses = $is_homeproz ? self::HOMEPROZ_ALLOWED_STATUSES : self::ALLOWED_STATUSES; + + // Delete if: not viewable OR status is not in allowed list + // HomeProz listings are retained even when Closed (sold) + $should_delete = !$can_view || !in_array($status, $allowed_statuses); if ($should_delete) { // Check if we have this record locally before attempting delete @@ -609,6 +840,13 @@ class MLS_Sync_Engine { return; } + // Build spatial location value for the NOT NULL location column + $lat = $property['Latitude'] ?? null; + $lng = $property['Longitude'] ?? null; + $has_coords = ($lat !== null && $lng !== null); + $point_lat = $has_coords ? (float) $lat : 0.0; + $point_lng = $has_coords ? (float) $lng : 0.0; + if ($existing) { // Update existing $wpdb->update( @@ -618,33 +856,136 @@ class MLS_Sync_Engine { ); $this->stats['updated']++; $this->emit_progress('property_updated', array('listing_key' => $listing_key)); - } else { - // Insert new - $data['listing_key'] = $listing_key; - $data['created_at'] = current_time('mysql'); - $wpdb->insert($this->db->properties_table(), $data); - $this->stats['created']++; - $this->emit_progress('property_created', array('listing_key' => $listing_key)); - } - // Update spatial location column (wpdb can't handle ST_PointFromText directly) - $lat = $property['Latitude'] ?? null; - $lng = $property['Longitude'] ?? null; - if ($lat !== null && $lng !== null) { + // Update spatial location column (wpdb can't handle ST_PointFromText directly) $wpdb->query($wpdb->prepare( "UPDATE {$this->db->properties_table()} SET location = ST_PointFromText(CONCAT('POINT(', %f, ' ', %f, ')'), 4326) WHERE listing_key = %s", - (float) $lat, - (float) $lng, + $point_lat, + $point_lng, $listing_key )); + } else { + // Insert new -- must use raw SQL to include the NOT NULL spatial location column + $data['listing_key'] = $listing_key; + $data['created_at'] = current_time('mysql'); + + $columns = array(); + $placeholders = array(); + $values = array(); + foreach ($data as $col => $val) { + $columns[] = "`{$col}`"; + if ($val === null) { + $placeholders[] = 'NULL'; + } elseif (is_int($val) || is_float($val)) { + $placeholders[] = is_int($val) ? '%d' : '%f'; + $values[] = $val; + } else { + $placeholders[] = '%s'; + $values[] = $val; + } + } + + // Append spatial location column + $columns[] = '`location`'; + $placeholders[] = "ST_PointFromText(CONCAT('POINT(', %f, ' ', %f, ')'), 4326)"; + $values[] = $point_lat; + $values[] = $point_lng; + + $sql = "INSERT INTO {$this->db->properties_table()} (" . implode(', ', $columns) . ") VALUES (" . implode(', ', $placeholders) . ")"; + $wpdb->query($wpdb->prepare($sql, $values)); + + $this->stats['created']++; + $this->emit_progress('property_created', array('listing_key' => $listing_key)); } // Process media if present if (isset($property['Media']) && is_array($property['Media'])) { $this->media_handler->sync_property_media($listing_key, $property['Media'], false, $this->progress_callback); + + // Auto-download and cache all images for HomeProz listings + // These images are stored in persistent cache and never garbage collected + if ($is_homeproz) { + $this->media_handler->download_homeproz_images($listing_key, $this->progress_callback); + } } } + /** + * Download pending media for all HomeProz properties + * + * Finds HomeProz properties that have media records with pending download status + * and downloads them. This ensures HomeProz images are always cached locally. + * + * @param bool $dry_run If true, don't download + * @return array Stats with 'downloaded' and 'skipped' counts + */ + private function download_pending_homeproz_media($dry_run = false) { + global $wpdb; + + $stats = array('downloaded' => 0, 'skipped' => 0, 'properties' => 0); + + // Find HomeProz properties with pending media downloads + $properties_table = $this->db->properties_table(); + $media_table = $this->db->media_table(); + + $homeproz_with_pending = $wpdb->get_results( + "SELECT DISTINCT p.listing_key + FROM {$properties_table} p + INNER JOIN {$media_table} m ON p.listing_key = m.listing_key + WHERE p.is_homeproz = 1 + AND m.download_status = 'pending' + AND m.media_url IS NOT NULL + ORDER BY p.modification_timestamp DESC" + ); + + if (empty($homeproz_with_pending)) { + $this->logger->info('No HomeProz properties with pending media downloads'); + return $stats; + } + + $this->logger->info('Found HomeProz properties with pending media', array( + 'count' => count($homeproz_with_pending), + )); + + $this->emit_progress('homeproz_media_start', array( + 'total_properties' => count($homeproz_with_pending), + )); + + $property_count = count($homeproz_with_pending); + $current = 0; + + foreach ($homeproz_with_pending as $row) { + $current++; + + if ($dry_run) { + $stats['properties']++; + continue; + } + + $this->logger->info('Downloading HomeProz media', array( + 'listing_key' => $row->listing_key, + 'progress' => "{$current}/{$property_count}", + )); + + // Download with 10-second delay between each image to respect MLS API limits + $result = $this->media_handler->download_homeproz_images( + $row->listing_key, + $this->progress_callback, + 10 // delay_seconds between each image + ); + + $stats['downloaded'] += $result['downloaded']; + $stats['skipped'] += $result['skipped']; + $stats['properties']++; + } + + $this->emit_progress('homeproz_media_complete', $stats); + + $this->logger->info('HomeProz media download completed', $stats); + + return $stats; + } + /** * Emit progress event * @@ -714,7 +1055,10 @@ class MLS_Sync_Engine { 'list_office_key' => $property['ListOfficeKey'] ?? null, 'list_office_mls_id' => $property['ListOfficeMlsId'] ?? null, 'list_office_name' => $property['ListOfficeName'] ?? null, - 'is_homeproz' => (($property['ListOfficeMlsId'] ?? '') === MLS_HOMEPROZ_OFFICE_ID) ? 1 : 0, + 'is_homeproz' => ( + (($property['ListOfficeMlsId'] ?? '') === MLS_HOMEPROZ_OFFICE_ID) + || (defined('MLS_HOMEPROZ_OVERRIDE_LISTINGS') && in_array($property['ListingId'] ?? '', MLS_HOMEPROZ_OVERRIDE_LISTINGS)) + ) ? 1 : 0, 'photos_count' => $property['PhotosCount'] ?? 0, 'modification_timestamp' => $this->format_timestamp($property['ModificationTimestamp'] ?? null), @@ -832,7 +1176,11 @@ class MLS_Sync_Engine { ); if ($timestamp) { + // Look back 10 minutes past the latest timestamp as a safety margin + // to catch any records that may have been missed due to race conditions + // or clock skew between our DB and the MLS API $dt = new DateTime($timestamp); + $dt->modify('-10 minutes'); return $dt->format('Y-m-d\TH:i:s.v\Z'); } @@ -992,7 +1340,13 @@ class MLS_Sync_Engine { // Step 2: Check if a sync is actively running $running = $this->get_running_sync(); if ($running) { - $status("Sync #{$running->id} is already running (started {$running->started_at})", 'warning'); + // If a full sync is in progress, exit silently so cron incremental + // syncs don't log warnings while the weekly full sync runs + if ($running->sync_type === 'full') { + $status("Full sync #{$running->id} in progress (started {$running->started_at}), skipping", 'info'); + } else { + $status("Sync #{$running->id} is already running (started {$running->started_at})", 'warning'); + } return array( 'success' => false, 'action' => 'aborted', diff --git a/wp-content/plugins/mls-by-hansonxyz/mls-by-hansonxyz.php b/wp-content/plugins/mls-by-hansonxyz/mls-by-hansonxyz.php index d1d2125c..38593df6 100755 --- a/wp-content/plugins/mls-by-hansonxyz/mls-by-hansonxyz.php +++ b/wp-content/plugins/mls-by-hansonxyz/mls-by-hansonxyz.php @@ -17,7 +17,7 @@ if (!defined('ABSPATH')) { } // Plugin constants -define('MLS_PLUGIN_VERSION', '1.0.0'); +define('MLS_PLUGIN_VERSION', '1.0.1'); define('MLS_PLUGIN_FILE', __FILE__); define('MLS_PLUGIN_DIR', plugin_dir_path(__FILE__)); define('MLS_PLUGIN_URL', plugin_dir_url(__FILE__)); @@ -33,10 +33,16 @@ define('MLS_TABLE_SYNC_LOG', 'mls_sync_log'); define('MLS_TABLE_MEDIA_LOG', 'mls_media_log'); define('MLS_TABLE_GEO_CITIES', 'mls_geo_cities'); define('MLS_TABLE_GEO_ZIPCODES', 'mls_geo_zipcodes'); +define('MLS_TABLE_MANUAL_PROPERTIES', 'mls_properties_manual'); // HomeProz office MLS ID for identifying our listings define('MLS_HOMEPROZ_OFFICE_ID', 'NST253235'); +// Specific MLS listing IDs to treat as HomeProz (for listings from other offices we want to showcase) +define('MLS_HOMEPROZ_OVERRIDE_LISTINGS', array( + 'NST6769023', // 121 Main Street, Glenville, MN 56036 (LandProz) +)); + // Allowed states for MLS queries (MN and IA only) define('MLS_ALLOWED_STATES', array('MN', 'IA')); @@ -64,6 +70,7 @@ final class MLS_Plugin { private $query; private $cluster; private $garbage_collector; + private $manual_property; /** * Get single instance @@ -100,6 +107,8 @@ final class MLS_Plugin { require_once MLS_PLUGIN_DIR . 'includes/class-mls-cluster.php'; require_once MLS_PLUGIN_DIR . 'includes/class-mls-geo-validator.php'; require_once MLS_PLUGIN_DIR . 'includes/class-mls-garbage-collector.php'; + require_once MLS_PLUGIN_DIR . 'includes/class-mls-geocoder.php'; + require_once MLS_PLUGIN_DIR . 'includes/class-mls-manual-property.php'; // Activation/Deactivation require_once MLS_PLUGIN_DIR . 'includes/class-mls-activator.php'; @@ -151,7 +160,8 @@ final class MLS_Plugin { ); $this->query = new MLS_Query($this->db); $this->cluster = new MLS_Cluster($this->db); - $this->garbage_collector = new MLS_Garbage_Collector($this->logger); + $this->garbage_collector = new MLS_Garbage_Collector($this->logger, $this->db); + $this->manual_property = new MLS_Manual_Property($this->db); // Register AJAX handlers add_action('wp_ajax_mls_get_clusters', array($this, 'ajax_get_clusters')); @@ -257,6 +267,13 @@ final class MLS_Plugin { return $this->garbage_collector; } + /** + * Get Manual Property instance + */ + public function get_manual_property() { + return $this->manual_property; + } + /** * AJAX handler for getting map clusters */ @@ -326,12 +343,12 @@ function mls_get_properties($args = array()) { * @param string $identifier Listing key or MLS ID * @return object|null Property object or null */ -function mls_get_property($identifier) { +function mls_get_property($identifier, $skip_manual_override = false) { $plugin = mls_plugin(); if (!$plugin->get_query()) { return null; } - return $plugin->get_query()->get_property($identifier); + return $plugin->get_query()->get_property($identifier, $skip_manual_override); } /** @@ -353,17 +370,31 @@ function mls_get_property_media($listing_key) { * * Images are fetched from MLS Grid and cached locally on first request. * Per MLS Grid rules, images must be served from our own server. + * For manual properties (MANUAL-xxx), returns the first gallery image. * * @param string $listing_key The listing key * @param bool $fetch_if_missing Whether to fetch from MLS Grid if not cached (default: true) * @return string|null Image URL or null */ function mls_get_property_image($listing_key, $fetch_if_missing = true) { + // Handle manual properties - images are in WordPress media library + if (strpos($listing_key, 'MANUAL-') === 0) { + $images = MLS_Manual_Property::get_manual_property_images($listing_key); + if (!empty($images) && isset($images[0]->local_url)) { + return $images[0]->local_url; + } + return null; + } + $plugin = mls_plugin(); if (!$plugin->get_media_handler()) { return null; } - return $plugin->get_media_handler()->get_primary_image($listing_key, $fetch_if_missing); + $result = $plugin->get_media_handler()->get_primary_image($listing_key, $fetch_if_missing); + if (is_wp_error($result) || !is_string($result)) { + return null; + } + return $result; } /** diff --git a/wp-content/plugins/wp-mail-smtp/assets/css/admin-bar.min.css b/wp-content/plugins/wp-mail-smtp/assets/css/admin-bar.min.css new file mode 100755 index 00000000..892001d7 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/css/admin-bar.min.css @@ -0,0 +1 @@ +#wpadminbar .wp-mail-smtp-admin-bar-menu-notification-counter,#wpadminbar .wp-mail-smtp-admin-bar-menu-error{display:inline-block !important;vertical-align:top !important;box-sizing:border-box !important;margin:7px 0 0 2px !important;padding:0 5px !important;min-width:18px !important;height:18px !important;border-radius:9px !important;background-color:#d63638 !important;color:#fff !important;font-size:11px !important;line-height:1.6 !important;text-align:center !important}#wpadminbar .wp-mail-smtp-admin-bar-menu-notification-counter span,#wpadminbar .wp-mail-smtp-admin-bar-menu-error span{line-height:1 !important;font-size:11px !important}body.wp-admin #adminmenu #toplevel_page_wp-mail-smtp .wp-menu-image.svg{background-position-x:10px;background-position-y:8px}@media screen and (max-width: 782px){body.wp-admin #adminmenu #toplevel_page_wp-mail-smtp .wp-menu-image.svg{background-position-x:9px}} \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/css/admin-notifications.min.css b/wp-content/plugins/wp-mail-smtp/assets/css/admin-notifications.min.css new file mode 100755 index 00000000..dc1225e2 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/css/admin-notifications.min.css @@ -0,0 +1 @@ +#wp-mail-smtp-notifications{position:relative;background:#fff 0 0 no-repeat padding-box;box-shadow:0 2px 4px rgba(0,0,0,.05);border-radius:6px;opacity:1;min-height:48px;margin:0 0 14px 0}#wp-mail-smtp-notifications *{box-sizing:border-box}#wp-mail-smtp-notifications .wp-mail-smtp-notifications-header{display:flex;align-items:center;padding:8px 16px;border-bottom:1px solid rgba(204,208,212,.5)}#wp-mail-smtp-notifications .wp-mail-smtp-notifications-header .wp-mail-smtp-notifications-bell{position:relative;top:2px;margin-right:10px}#wp-mail-smtp-notifications .wp-mail-smtp-notifications-header .wp-mail-smtp-notifications-title{font-style:normal;font-weight:500;font-size:14px;line-height:17px;color:#23282d}#wp-mail-smtp-notifications .wp-mail-smtp-notifications-body{position:relative}#wp-mail-smtp-notifications .wp-mail-smtp-notifications-messages{padding:16px 100px 16px 16px}#wp-mail-smtp-notifications .wp-mail-smtp-notifications-messages .wp-mail-smtp-notifications-message{display:none}#wp-mail-smtp-notifications .wp-mail-smtp-notifications-messages .wp-mail-smtp-notifications-message.current{display:block}#wp-mail-smtp-notifications .wp-mail-smtp-notifications-messages .wp-mail-smtp-notifications-title{font-weight:600;font-size:17px;line-height:17px;margin:0;color:#2c3337}#wp-mail-smtp-notifications .wp-mail-smtp-notifications-messages .wp-mail-smtp-notifications-content{font-weight:normal;font-size:14px;line-height:18px;margin:8px 0 41px 0;color:#50575e}#wp-mail-smtp-notifications .wp-mail-smtp-notifications-messages .wp-mail-smtp-notifications-content p{font-size:inherit;line-height:inherit;margin:0 0 5px}#wp-mail-smtp-notifications .wp-mail-smtp-notifications-messages .wp-mail-smtp-notifications-buttons{margin:-30px 80px 0 0}#wp-mail-smtp-notifications .wp-mail-smtp-notifications-messages .wp-mail-smtp-notifications-buttons a{margin:0 10px 0 0;padding:8px 10px;line-height:13px;font-size:13px;min-height:unset}#wp-mail-smtp-notifications .wp-mail-smtp-notifications-messages .wp-mail-smtp-notifications-buttons .button-secondary{border:1px solid #0071a1}#wp-mail-smtp-notifications .dismiss{position:absolute;top:15px;right:16px;width:16px;height:16px;color:#a0a5aa;font-size:16px;cursor:pointer;text-align:center;vertical-align:middle;line-height:16px}#wp-mail-smtp-notifications .dismiss:hover{color:#d63638}#wp-mail-smtp-notifications .dismiss i{width:100%;height:100%;font-size:inherit}#wp-mail-smtp-notifications .navigation{position:absolute;bottom:20px;right:16px;width:63px;height:30px}#wp-mail-smtp-notifications .navigation a{display:block;width:30px;height:30px;border:1px solid #7e8993;border-radius:3px;font-size:16px;line-height:1.625;text-align:center;cursor:pointer;background-color:#fff;color:#41454a}#wp-mail-smtp-notifications .navigation a:hover{background-color:#f1f1f1}#wp-mail-smtp-notifications .navigation a .dashicons{margin-top:8px;font-size:12px}#wp-mail-smtp-notifications .navigation .prev{float:left}#wp-mail-smtp-notifications .navigation .next{float:right}#wp-mail-smtp-notifications .navigation .disabled{border-color:#ddd;color:#a0a5aa;cursor:default}#wp-mail-smtp-notifications .navigation .disabled:hover{background-color:#fff}@media screen and (max-width: 768px){#wp-mail-smtp-notifications .wp-mail-smtp-notifications-messages{padding:15px 50px 20px 16px}#wp-mail-smtp-notifications .wp-mail-smtp-notifications-messages .wp-mail-smtp-notifications-title{margin:0 30px 0 0;line-height:22px}#wp-mail-smtp-notifications .wp-mail-smtp-notifications-messages .wp-mail-smtp-notifications-content{font-size:16px;line-height:22px}#wp-mail-smtp-notifications .wp-mail-smtp-notifications-messages .wp-mail-smtp-notifications-buttons{margin:-30px 80px 0 0}#wp-mail-smtp-notifications .wp-mail-smtp-notifications-messages .wp-mail-smtp-notifications-buttons a{margin:0;display:table}#wp-mail-smtp-notifications .wp-mail-smtp-notifications-messages .wp-mail-smtp-notifications-buttons .button-secondary{margin-top:6px}} \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/css/admin-site-health.min.css b/wp-content/plugins/wp-mail-smtp/assets/css/admin-site-health.min.css new file mode 100755 index 00000000..1b139784 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/css/admin-site-health.min.css @@ -0,0 +1 @@ +#health-check-accordion-block-wp_mail_smtp_email_domain_check>p:first-child{margin-top:0}#wp-mail-smtp-domain-check-details h2{color:#2c3338;font-weight:600;font-size:13px;margin:0 0 15px}#wp-mail-smtp-domain-check-details .wp-mail-smtp-domain-check-details-check-list-item{padding:10px 0 0;border-top:1px solid #e4e4e4;display:flex}#wp-mail-smtp-domain-check-details .wp-mail-smtp-domain-check-details-check-list-item:last-child{border-bottom:1px solid #e4e4e4}#wp-mail-smtp-domain-check-details .wp-mail-smtp-domain-check-details-check-list-item-icon{width:18px;height:16px;margin-right:10px}#wp-mail-smtp-domain-check-details .wp-mail-smtp-domain-check-details-check-list-item-content h3{text-transform:uppercase;font-weight:500;font-size:14px;line-height:17px;margin:0 0 4px 0;color:#2c3337}#wp-mail-smtp-domain-check-details .wp-mail-smtp-domain-check-details-check-list-item-content p{margin:0 0 10px 0;color:#50575e} \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/css/dashboard-widget.min.css b/wp-content/plugins/wp-mail-smtp/assets/css/dashboard-widget.min.css new file mode 100755 index 00000000..203c6fba --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/css/dashboard-widget.min.css @@ -0,0 +1 @@ +#dashboard-widgets .meta-box-sortables .postbox:last-child .wp-mail-smtp-dash-widget-settings-menu{top:auto;bottom:50px}@media(min-width: 800px){#dashboard-widgets .meta-box-sortables .postbox:last-child .wp-mail-smtp-dash-widget-settings-menu{bottom:40px}}#wp_mail_smtp_reports_widget_pro .inside,#wp_mail_smtp_reports_widget_lite .inside{margin:0;padding:0}.wp-mail-smtp-dash-widget button:focus{outline:none}.wp-mail-smtp-dash-widget-block{position:relative;padding:0 12px;margin-top:12px}.wp-mail-smtp-dash-widget-block h3{display:inline-block;line-height:2}.wp-mail-smtp-dash-widget-block p{margin-top:0;margin-bottom:0}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-chart-block-container{position:relative}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-chart-block{height:291px;border-bottom:1px solid #eee;padding:0 12px 12px;padding-inline-end:14px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings{display:flex;align-items:start;justify-content:space-between;margin-top:0;padding:13px;background-color:#fafafa}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings>div{display:flex}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings>div:first-child{flex-wrap:wrap}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings>div:first-child a{line-height:30px}@media(max-width: 980px){.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings{padding:13px 4px}}@media(max-width: 960px){.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings{padding:13px}}@media(max-width: 856px){.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings{padding:13px 2px}}@media(max-width: 799px){.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings{padding:13px}}@media(max-width: 436px){.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings{flex-direction:column;align-items:normal}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings select{width:100%;margin:0 0 10px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-select-timespan{width:calc(100% - 38px)}}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings a{vertical-align:middle}@media(max-width: 1150px){.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings a{display:none}}@media(min-width: 1500px)and (max-width: 1630px){.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings a{display:none}}@media(min-width: 1801px)and (max-width: 2080px){.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings a{display:none}}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-select-email-type{margin-right:6px}@media(max-width: 830px){.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-select-email-type{margin-right:2px}}@media(max-width: 436px){.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-select-email-type{margin-right:0}}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-container{display:inline-block;position:relative;vertical-align:top;margin-left:6px}@media(max-width: 830px){.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-container{margin-left:2px}}@media(max-width: 799px){.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-container{margin-left:6px}}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-button{background:#fafafa;color:#787c82;border-color:#787c82;padding:1px 6px 0;margin-bottom:0;line-height:1;display:flex;align-items:center;justify-content:center}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-button:hover,.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-button:active,.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-button:focus{color:#2271b1;border-color:#2271b1}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-button:hover svg path,.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-button:active svg path,.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-button:focus svg path{fill:#2271b1}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-button.open svg path{transform:rotate(90deg)}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-button svg{display:inline-block;width:19px;height:19px}@media(max-width: 782px){.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-button svg{padding:5px}}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-button svg path{fill:#787c82;transition:transform .2s;transform-origin:center center}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-menu{display:none;position:absolute;background-color:#fff;width:160px;border-radius:3px;box-shadow:0px 5px 15px rgba(0,0,0,.15);padding:10px;z-index:9999;right:0;top:50px}@media(min-width: 800px){.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-menu{top:40px}}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-menu--style,.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-menu--color{border-bottom:1px solid #eee}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-menu--style h4,.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-menu--color h4{text-transform:uppercase !important;color:#3c434a !important;font-size:11px !important;font-weight:500 !important;line-height:13px !important;margin:0 0 10px !important}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-menu--style .wp-mail-smtp-dash-widget-settings-menu-item,.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-menu--color .wp-mail-smtp-dash-widget-settings-menu-item{display:flex;align-items:center;color:#3c434a;font-size:13px;line-height:16px;margin:0 0 13px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-menu--style .wp-mail-smtp-dash-widget-settings-menu-item:last-child,.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-menu--color .wp-mail-smtp-dash-widget-settings-menu-item:last-child{margin:0 0 10px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-menu--style .wp-mail-smtp-dash-widget-settings-menu-item input[type=radio],.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-menu--color .wp-mail-smtp-dash-widget-settings-menu-item input[type=radio]{margin-right:5px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-menu--style .wp-mail-smtp-dash-widget-settings-menu-item label,.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-menu--color .wp-mail-smtp-dash-widget-settings-menu-item label{vertical-align:top;margin-top:-3px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-menu--color{margin-top:10px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-settings .wp-mail-smtp-dash-widget-settings-menu-save{margin-top:10px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-email-stats-block{margin-top:0}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-email-stats-block table{width:calc(100% + 24px);margin:0 -12px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-email-stats-block table .wp-mail-smtp-dash-widget-email-stats-table-cell{padding:10px 12px;border-right:1px solid #eee;border-top:1px solid #eee;color:#3c434a;font-size:14px;width:50%;line-height:17px}@media(max-width: 436px){.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-email-stats-block table .wp-mail-smtp-dash-widget-email-stats-table-cell{display:block;width:100%}}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-email-stats-block table .wp-mail-smtp-dash-widget-email-stats-table-cell--2:not(:first-child){border-right:none}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-email-stats-block table .wp-mail-smtp-dash-widget-email-stats-table-cell--3{width:33.33%}@media(max-width: 436px){.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-email-stats-block table .wp-mail-smtp-dash-widget-email-stats-table-cell--3{width:100%}}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-email-stats-block table .wp-mail-smtp-dash-widget-email-stats-table-cell--3:last-child{border-right:none}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-email-stats-block table .wp-mail-smtp-dash-widget-email-stats-table-cell-container{display:flex;align-items:center}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-email-stats-block table .wp-mail-smtp-dash-widget-email-stats-table-cell-container img{width:16px;margin-right:10px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-email-stats-block .wp-mail-smtp-dash-widget-overlay{background-position-y:50%}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-recommended-plugin-block{display:flex;padding:12px 7px 12px 12px;border-top:1px solid #eee;color:#787c82;font-size:13px;line-height:16px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-recommended-plugin-block b{color:#3c434a}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-recommended-plugin-block .sep{display:inline-block;margin:0 3px;color:#ddd}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-recommended-plugin-block .sep-vertical{color:#ddd}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-recommended-plugin-block p{margin:0}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-recommended-plugin-block .wp-mail-smtp-dash-widget-recommended-plugin{display:inline-block;width:calc(100% - 24px)}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-recommended-plugin-block .wp-mail-smtp-dash-widget-recommended-plugin span{display:inline-block}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-recommended-plugin-block .wp-mail-smtp-dash-widget-dismiss-recommended-plugin-block{display:inline-block;border:0;color:gray;opacity:.3;vertical-align:baseline;cursor:pointer;background:none;padding:0 2px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-recommended-plugin-block .wp-mail-smtp-dash-widget-dismiss-recommended-plugin-block:hover{opacity:1}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-recommended-plugin-block .wp-mail-smtp-dash-widget-dismiss-recommended-plugin-block .dashicons{font-size:16px;height:16px;width:16px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-email-alerts-education{align-items:center;border-left:4px solid #d63638;border-top:1px solid #eee;display:flex;gap:10px;margin-top:0;padding:10px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-email-alerts-education-error-icon{display:flex;height:44px;width:40px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-email-alerts-education-error-icon img{height:35px;width:35px;margin:auto}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-email-alerts-education-content{padding-right:14px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-email-alerts-education-content p{color:#1d2327;font-size:14px;line-height:20px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-email-alerts-education-content p a{color:#2271b1;font-weight:500}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-email-alerts-education-content p strong{font-weight:500}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-email-alerts-education .wp-mail-smtp-dash-widget-dismiss-email-alert-block{background:none;border:0;cursor:pointer;position:absolute;right:6px;top:10px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-email-alerts-education .wp-mail-smtp-dash-widget-dismiss-email-alert-block .dashicons{color:#a0a5aa;font-size:16px;height:17px;width:16px}.wp-mail-smtp-dash-widget .wp-mail-smtp-error{text-align:center}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-chart-upgrade,.wp-mail-smtp-dash-widget .wp-mail-smtp-error-no-data-chart{position:absolute;left:0;top:0;height:100%;width:100%;overflow:hidden;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;background:rgba(255,255,255,0);background:-moz-radial-gradient(center, ellipse cover, rgba(255, 255, 255, 0) 0%, rgb(255, 255, 255) 100%);background:-webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(100%, rgb(255, 255, 255)));background:-webkit-radial-gradient(center, ellipse cover, rgba(255, 255, 255, 0) 0%, rgb(255, 255, 255) 100%);background:-o-radial-gradient(center, ellipse cover, rgba(255, 255, 255, 0) 0%, rgb(255, 255, 255) 100%);background:-ms-radial-gradient(center, ellipse cover, rgba(255, 255, 255, 0) 0%, rgb(255, 255, 255) 100%);background:radial-gradient(ellipse at center, rgba(255, 255, 255, 0) 0%, rgb(255, 255, 255) 100%)}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-chart-upgrade .wp-mail-smtp-dash-widget-modal,.wp-mail-smtp-dash-widget .wp-mail-smtp-error-no-data-chart .wp-mail-smtp-dash-widget-modal{position:absolute;top:calc(50% - 2em);left:50%;transform:translate(-50%, -50%);padding:1.5em 2em 2em 2em;box-shadow:0 0 25px 10px rgba(0,0,0,.08);border-radius:3px;background-color:#fff;text-align:center;width:20em}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-chart-upgrade .wp-mail-smtp-dash-widget-modal h2,.wp-mail-smtp-dash-widget .wp-mail-smtp-error-no-data-chart .wp-mail-smtp-dash-widget-modal h2{padding:0;margin-bottom:5px;font-size:18px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-chart-upgrade .wp-mail-smtp-dash-widget-modal p,.wp-mail-smtp-dash-widget .wp-mail-smtp-error-no-data-chart .wp-mail-smtp-dash-widget-modal p{line-height:1.3}.wp-mail-smtp-dash-widget .wp-mail-smtp-error-no-data-email-stats{padding-top:16px;padding-bottom:16px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-logs-disabled{padding:21px 25px 30px;text-align:center}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-logs-disabled .wp-mail-smtp-dash-widget-block-logo{width:75px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-logs-disabled h2{font-size:16px;line-height:20px;font-weight:500;padding:10px 0 0}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-logs-disabled p{font-size:14px;line-height:20px;margin:7px 0 19px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-block-logs-disabled a.button:first-of-type:not(:only-of-type){margin-right:10px}.wp-mail-smtp-dash-widget .wp-mail-smtp-dash-widget-overlay{width:100%;position:absolute;top:0;right:0;bottom:0;left:0;background:url(../images/wp-spinner.gif) no-repeat center calc(50% - 12px);background-color:#fff;z-index:10}.wp-mail-smtp-dash-widget i.wp-mail-smtp-dash-widget-loader{background-image:url(../images/wp-spinner.gif);background-repeat:no-repeat;background-position:center;background-size:cover}.wp-mail-smtp-dash-widget .hidden{display:none !important}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-chart-block-container #wp-mail-smtp-dash-widget-chart{opacity:.35}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-chart-upgrade{background:none;display:flex;align-items:center;justify-content:center}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-chart-upgrade h2{font-size:20px;line-height:20px;font-weight:500;color:#3c434a;margin-bottom:15px}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-chart-upgrade p{font-size:14px;line-height:18px;color:#787c82;margin-bottom:15px}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-chart-upgrade p:last-child{margin-bottom:0}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-chart-upgrade a.button.button-hero{font-weight:500;font-size:14px;line-height:20px;padding:9px 15px;min-height:40px}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-chart-upgrade .wp-mail-smtp-dash-widget-modal{position:relative;top:inherit;left:inherit;transform:none;width:24em;padding:2.3em;box-shadow:0 5px 25px rgba(0,0,0,.15);border-radius:6px}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-dismiss-chart-upgrade{position:absolute;width:16px;height:17px;right:5px;top:5px;color:#a0a5aa;text-decoration:none}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-dismiss-chart-upgrade .dashicons{width:16px;height:17px;font-style:normal;font-weight:normal;font-size:16px;line-height:17px}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-settings-menu input[type=radio]:checked::before{background-color:#a0a5aa}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-settings-menu *{cursor:not-allowed}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-summary-report-email-block{margin-top:0;padding-top:10px;padding-bottom:10px;border-top:1px solid #eee;font-size:13px;line-height:16px}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-summary-report-email-block>div{padding:10px;border-radius:4px;background:#f0f6fc}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-summary-report-email-block-setting{display:flex;align-items:center}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-summary-report-email-block-setting label{display:flex;margin:0 10px 0 0;color:#3c434a}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-summary-report-email-block-setting label input,#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-summary-report-email-block-setting label i{margin:0 10px 0 0}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-summary-report-email-block-setting label i{display:none;width:16px;height:16px}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-summary-report-email-block-setting label b{font-weight:500}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-summary-report-email-block-setting a{white-space:nowrap;margin-right:10px}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-summary-report-email-block-setting .dashicons-dismiss{margin-left:auto;width:16px;height:16px;font-size:16px;color:#a0a5aa;cursor:pointer}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-summary-report-email-block-setting .dashicons-dismiss:hover{color:#2271b1}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-summary-report-email-block-applied{display:flex}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-summary-report-email-block-applied .wp-mail-smtp-dashicons-yes-alt-green{margin-right:10px;width:16px;height:16px;background-image:url("../images/dash-widget/yes-green.svg")}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-upgrade-footer{padding:12px;margin-top:0;border-top:1px solid #eee}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-upgrade-footer p{font-size:13px;line-height:16px}#wp_mail_smtp_reports_widget_lite .wp-mail-smtp-dash-widget-upgrade-footer--hide{display:none} \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/css/emails/summary-report-email.css b/wp-content/plugins/wp-mail-smtp/assets/css/emails/summary-report-email.css new file mode 100755 index 00000000..57f3e9d2 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/css/emails/summary-report-email.css @@ -0,0 +1,299 @@ +/* General styles. */ + +#outlook a { + padding: 0; +} + +.ExternalClass { + width: 100%; +} + +.ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div { + line-height: 100%; +} + +#backgroundTable { + margin: 0; + padding: 0; + width: 100% !important; + line-height: 100% !important; +} + +/* Prevent blue links in subject. */ +.stats-subject-heading a { + color: inherit !important; + text-decoration: none !important; +} + +/* Mobile styles. */ + +@media only screen and (max-width: 599px) { + table.body .container { + width: 94% !important; + max-width: 600px !important; + } + + .header img { + width: 240px !important; + height: auto !important; + } + + .content { + padding: 30px !important; + } + + .main-heading { + font-size: 16px !important; + line-height: 20px !important; + } + + .main-description { + margin-bottom: 20px !important; + } + + .stats-totals-wrapper.two .stats-totals-item-wrapper { + width: 50% !important; + } + + .stats-totals-wrapper.three .stats-totals-item-wrapper { + width: 33.3% !important; + } + + .stats-totals-wrapper.four .stats-totals-item-wrapper { + width: 25% !important; + } + + .stats-totals-wrapper { + border-collapse: separate !important; + border: 1px solid #DDDDDD !important; + border-radius: 4px !important; + } + + .stats-total-item { + width: 100% !important; + min-width: 100% !important; + } + + .stats-total-item-inner { + border: none !important; + } + + .stats-total-item-icon-wrapper { + height: 24px !important; + } + + .stats-total-item-icon { + width: 24px !important; + height: 24px !important; + } + + .stats-totals-wrapper.three .stats-total-item-title, + .stats-totals-wrapper.four .stats-total-item-title { + display: none !important; + } + + .stats-total-item-value { + font-size: 18px !important; + line-height: 22px !important; + } + + .stats-total-item-percent { + font-size: 12px !important; + line-height: 14px !important; + } + + .stats-total-item-percent img { + width: 9px !important; + height: 9px !important; + } + + .stats-heading th { + display: block !important; + width: 100% !important; + min-width: 100% !important; + padding-right: 0 !important; + padding-left: 0 !important; + text-align: center !important; + } + + .stats-heading .first-col { + padding-top: 20px !important; + padding-bottom: 5px !important; + } + + .stats-heading .second-col { + padding-top: 0 !important; + padding-bottom: 20px !important; + } + + .stats-heading h2 { + text-align: center !important; + font-size: 15px !important; + line-height: 18px !important; + } + + .stats-heading a { + font-size: 13px !important; + line-height: 16px !important; + } + + .stats-subject-heading { + text-align: center !important; + } + + .stats-subject-row { + text-align: center !important; + } + + .stats-subject-column.total, + .stats-subject-column.sent, + .stats-subject-column.confirmed, + .stats-subject-column.unconfirmed, + .stats-subject-column.unsent { + max-width: 64px !important; + } + + .stats-subject-column.opened, + .stats-subject-column.clicked { + max-width: 111px !important; + } + + .spacer-40 { + line-height: 20px !important; + height: 20px !important; + } + + .upgrade-heading { + font-size: 18px !important; + line-height: 22px !important; + } + + .upgrade-text { + font-size: 14px !important; + line-height: 20px !important; + } +} + +@media only screen and (max-width: 360px) { + .content { + padding: 20px !important; + } + + .stats-subject-column.total, + .stats-subject-column.sent, + .stats-subject-column.confirmed, + .stats-subject-column.unconfirmed, + .stats-subject-column.unsent { + max-width: 61px !important; + } +} + +/* Dark Mode. */ + +@media (prefers-color-scheme: dark) { + .dark-body-bg { + background: #1C1E20 !important; + } + + .dark-content-bg { + background: #23282C !important; + } + + .dark-bg { + background: #202326 !important; + } + + .dark-white-color { + color: #ffffff !important; + } + + .dark-img { + display: block !important; + width: auto !important; + overflow: visible !important; + float: none !important; + max-height: inherit !important; + max-width: inherit !important; + line-height: auto !important; + margin-top: 0px !important; + visibility: inherit !important; + } + + .light-img { + display: none; + display: none !important; + } + + .stats-total-item-inner, + .stats-heading { + border-color: #395360 !important; + } + + .stats-subject-column-value, + .stats-total-item-percent, + .footer { + color: #8C8F94 !important; + } + + .stats-subject-column-value span { + color: #4A5057 !important; + } + + .upgrade-text { + color: #8C8F94 !important; + } +} + +/* Dark Mode Outlook. */ + +[data-ogsc] .dark-body-bg { + background: #1C1E20 !important; +} + +[data-ogsc] .dark-content-bg { + background: #23282C !important; +} + +[data-ogsc] .dark-bg { + background: #202326 !important; +} + +[data-ogsc] .dark-white-color { + color: #ffffff !important; +} + +[data-ogsc] .dark-img { + display: block !important; + width: auto !important; + overflow: visible !important; + float: none !important; + max-height: inherit !important; + max-width: inherit !important; + line-height: auto !important; + margin-top: 0px !important; + visibility: inherit !important; +} + +[data-ogsc] .light-img { + display: none; + display: none !important; +} + +[data-ogsc] .stats-total-item-inner, +[data-ogsc] .stats-heading { + border-color: #395360 !important; +} + +[data-ogsc] .stats-subject-column-value, +[data-ogsc] .stats-total-item-percent, +[data-ogsc] .footer { + color: #8C8F94 !important; +} + +[data-ogsc] .stats-subject-column-value span { + color: #4A5057 !important; +} + +[data-ogsc] .upgrade-text { + color: #8C8F94 !important; +} diff --git a/wp-content/plugins/wp-mail-smtp/assets/css/smtp-about.min.css b/wp-content/plugins/wp-mail-smtp/assets/css/smtp-about.min.css new file mode 100755 index 00000000..b2326f5f --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/css/smtp-about.min.css @@ -0,0 +1 @@ +.wp-mail-smtp-page-about{padding:0 !important}.wp-mail-smtp-page-about *,.wp-mail-smtp-page-about *::before,.wp-mail-smtp-page-about *::after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins{padding:0 10px}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container{margin-left:-20px;margin-right:-20px}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-container{padding:0 10px;float:left;width:33.333333%;margin-bottom:20px}@media(max-width: 1249px){.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-container{width:50%}}@media(max-width: 781px){.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-container{width:100%;margin-bottom:20px}}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container h5{font-size:17px;font-weight:600}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item{background-color:#fff;border:1px solid #ddd;border-radius:3px;margin:0}@media(max-width: 781px){.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item{margin:0 0}}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item img{border:1px solid #eee;float:left;max-width:75px;padding:10px}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item img[src*=-mi]{padding:13px}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item h5{margin:0 0 10px 100px;font-size:16px}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item p{margin:0 0 0 100px}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .details{padding:20px}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .actions{background-color:#f7f7f7;border-top:1px solid #ddd;padding:20px;position:relative}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .actions .msg{background-color:#f7f7f7;position:absolute;text-align:center;font-weight:600;top:0;left:0;height:100%;width:100%;z-index:99;padding:20px;display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex;-webkit-align-items:center;-ms-align-items:center;align-items:center;justify-content:center}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .actions .msg.success{color:#00a32a}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .actions .msg.error{color:#d63638}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .status{float:left;padding-top:8px}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .status .status-inactive{color:#d63638}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .status .status-download{color:#666}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .status .status-active{color:#00a32a}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .action-button{float:right}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .action-button button{cursor:pointer;width:140px;text-align:center;display:inline-block;text-decoration:none;font-size:13px;line-height:26px;height:28px;margin:0;padding:0 10px 1px;-webkit-appearance:none;border-radius:3px;border:1px solid #ccc;background:#f7f7f7;box-shadow:0 1px 0 #ccc;font-weight:normal}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .action-button button:hover,.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .action-button button:focus,.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .action-button button.loading{background:#fafafa;border-color:#999;color:#23282d}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .action-button button .fa{margin-right:8px}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .action-button button .fa.fa-spinner{margin-right:0}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .action-button button.button-primary{background:#0085ba;border-color:#0073aa #006799 #006799;box-shadow:0 1px 0 #006799;color:#fff;text-shadow:0 -1px 1px #006799,1px 0 1px #006799,0 1px 1px #006799,-1px 0 1px #006799}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .action-button button.button-primary:hover,.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .action-button button.button-primary:focus{background:#008ec2;border-color:#006799;color:#fff}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .action-button button.button-primary .fa-spinner{color:#fff}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .action-button button.button-secondary{color:#50575e;border-color:#ccc;background:#f7f7f7;box-shadow:0 1px 0 #ccc}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .action-button button.button-secondary:hover,.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .action-button button.button-secondary:focus{background:#fafafa;border-color:#999;color:#23282d}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .action-button button.status-active .fa{color:#00a32a}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .action-button button.status-inactive .fa{color:#d63638}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .action-button button.status-download .fa{color:#999}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .action-button button.loading .fa{color:#666}.wp-mail-smtp-page-about.wp-mail-smtp-tab-about-about .wp-mail-smtp-admin-about-plugins .plugins-container .plugin-item .action-button button.disabled{cursor:default}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section{margin:0 0 20px;padding:30px;background:#fff;border:1px solid #e5e6e6;line-height:2}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section h1,.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section h2,.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section h3,.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section h4,.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section h5{margin-top:0;padding-top:0;line-height:1.6}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section h2{font-size:24px}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section h3{font-size:18px;margin-bottom:30px;color:#23282c}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section ul,.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section p{font-size:16px}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section p{margin-bottom:20px}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section p.bigger{font-size:18px}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section p.smaller{font-size:14px}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section p:last-child{margin-bottom:0}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section hr{margin:30px 0}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section figure{margin:0}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section figure img{width:100%}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section figure figcaption{font-size:14px;color:#646970;margin-top:5px;text-align:center;line-height:initial}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section .wp-mail-smtp-admin-column-40{padding-left:15px}@media(max-width: 781px){.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section .wp-mail-smtp-admin-column-40{width:100%;padding-left:0;padding-top:20px}}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section .wp-mail-smtp-admin-column-60{padding-right:15px}@media(max-width: 781px){.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section .wp-mail-smtp-admin-column-60{width:100%;padding-right:0}}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section ul.list-plain{margin-top:0;margin-bottom:0}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section ul.list-plain li{margin-bottom:0}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section ul.list-features li .fa{color:#00a32a;margin:0 8px 0 0}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section .fa-star{color:gold}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section .no-margin{margin:0 !important}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section .no-padding{padding:0 !important}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section .centered{text-align:center !important}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-hero{padding:0}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-hero .wp-mail-smtp-admin-about-section-hero-main,.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-hero .wp-mail-smtp-admin-about-section-hero-extra{padding:30px}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-hero .wp-mail-smtp-admin-about-section-hero-extra table{width:100%}@media(max-width: 781px){.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-hero .wp-mail-smtp-admin-about-section-hero-extra .wp-mail-smtp-admin-column-50{float:none;width:100%}}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-hero .wp-mail-smtp-admin-about-section-hero-main{background-color:#fafafa;border-bottom:1px solid #e5e6e6}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-hero .wp-mail-smtp-admin-about-section-hero-main.no-border{border-bottom:0}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-hero .wp-mail-smtp-admin-about-section-hero-main p{color:#666}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-hero h3.call-to-action{margin-bottom:-10px}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-hero span.price-off{color:#00a32a}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-squashed{margin-bottom:0}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-squashed:not(:last-of-type){border-bottom:0}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-post h2{margin-bottom:-10px}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-post h3{margin-bottom:15px}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-post p:last-of-type{margin-bottom:30px}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-post .wp-mail-smtp-admin-column-20{padding-right:20px;width:auto}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-post .wp-mail-smtp-admin-column-20 img{width:270px}@media(max-width: 781px){.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-post .wp-mail-smtp-admin-column-20{width:20%}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-post .wp-mail-smtp-admin-column-20 img{width:auto;max-width:100%}}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-post .wp-mail-smtp-admin-column-80{padding-left:20px;width:calc(100% - 20px - 270px)}@media(max-width: 781px){.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-post .wp-mail-smtp-admin-column-80{width:80%}}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-post .wp-mail-smtp-admin-about-section-post-link{padding:10px 15px;background-color:#df7739;color:#fff;border-radius:3px;text-decoration:none;margin-top:15px;font-size:14px}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-post .wp-mail-smtp-admin-about-section-post-link:hover{background-color:#b85a1b}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-post .wp-mail-smtp-admin-about-section-post-link .fa{color:#edba9e;vertical-align:middle;margin-left:8px}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-table table{border-collapse:collapse}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-table table tr td{border-bottom:1px solid #e5e6e6;border-right:1px solid #e5e6e6;padding:30px}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-table table tr td:last-of-type{border-right:0}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-table table tr:last-child td{border-bottom:none}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-table table p{background-repeat:no-repeat;background-size:15px auto;background-position:0 6px;margin:0}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-table table p.features-full{padding-left:30px;background-image:url(../images/about/icon-full.svg)}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-table table p.features-none{padding-left:30px;background-image:url(../images/about/icon-none.svg)}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-table table p.features-partial{padding-left:30px;background-position:-3px 0;background-size:23px auto;background-image:url(../images/about/icon-partial.svg)}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-table .wp-mail-smtp-admin-about-section-hero-main{padding:0}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-table .wp-mail-smtp-admin-about-section-hero-main h3{padding:30px 30px 30px 60px}.wp-mail-smtp-page-about .wp-mail-smtp-admin-about-section-table .wp-mail-smtp-admin-about-section-hero-main .wp-mail-smtp-admin-column-33:first-child h3{padding:30px} \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/css/smtp-admin.min.css b/wp-content/plugins/wp-mail-smtp/assets/css/smtp-admin.min.css new file mode 100755 index 00000000..785232df --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/css/smtp-admin.min.css @@ -0,0 +1 @@ +#wpcontent{padding-left:0 !important;position:relative}@media(max-width: 600px){#wpcontent{padding-top:46px}}@media(max-width: 600px){#wpbody{padding-top:0}}@-webkit-keyframes wp-mail-smtp-fade-in-stop-out{0%,100%{opacity:0}35%{opacity:1}65%{opacity:1}}@keyframes wp-mail-smtp-fade-in-stop-out{0%,100%{opacity:0}35%{opacity:1}65%{opacity:1}}body.wp-mail-smtp-admin-page-body div.jconfirm *,body.wp-mail-smtp-admin-page-body div.jconfirm *::before,body.wp-mail-smtp-admin-page-body div.jconfirm *::after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-bg{background-color:rgba(114,119,124,.75);opacity:1}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box{padding:30px;border-radius:6px;box-shadow:0 3px 6px rgba(0,0,0,.15);border-top-width:4px}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-closeIcon{color:rgba(0,0,0,.4);top:8px;right:8px}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-closeIcon:hover{color:rgba(0,0,0,.8)}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-title-c{margin:0 0 15px 0;padding:0}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c{margin:0 0 30px;-webkit-transition:none;transition:none;-webkit-transform:none !important;-ms-transform:none !important;transform:none !important}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c:empty,body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c i:empty{display:none}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-title{display:block;color:#2c3337;font-weight:500;font-size:24px;line-height:29px}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-content-pane{display:block;margin-bottom:30px}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-content-pane .jconfirm-content{margin-bottom:0;overflow:inherit}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-content{font-size:16px;color:#2c3337;line-height:1.4}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-content p{margin:0 0 20px;font-size:16px;line-height:1.5}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-content p:last-of-type{margin:0}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-content p.large{font-size:18px}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-content p.small{font-size:14px}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-content .wp-mail-smtp-debug-event-preview p{font-size:14px}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-content .wp-mail-smtp-btn{font-weight:600;text-transform:uppercase;-webkit-transition:background .1s;transition:background .1s;padding:10px 20px;outline:none;display:inline-block;font-size:14px;line-height:1.4;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:4px;min-height:1em;-webkit-tap-highlight-color:rgba(0,0,0,0);border:0;background-image:none}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-content .wp-mail-smtp-btn.with-loader{padding:12px 12px 7px}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-buttons{padding:0}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-buttons button{transition:.2s;box-shadow:none;margin:0 10px 0}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-buttons button:hover{box-shadow:inset 0 0 0 100px rgba(0,0,0,.1)}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-buttons button.btn-confirm{color:#fff;outline:none;border:1px solid #e27730;background-color:#e27730}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-buttons button.btn-cancel{color:#777;outline:none;background:#f8f8f8;border:1px solid #ccc}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-buttons button,body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-buttons button.btn-default{color:#666}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-buttons button.btn-hide{display:none}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-buttons button.btn-block{display:block;text-align:center;width:100%;margin:0 0 10px 0 !important}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box div.jconfirm-buttons button.btn-normal-case{text-transform:none !important}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.jconfirm-type-green{border-color:#00a32a}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.jconfirm-type-green div.jconfirm-buttons button.btn-confirm{background-color:#00a32a;border-color:#00a32a}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.jconfirm-type-orange{border-color:#e27730}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.jconfirm-type-orange div.jconfirm-buttons button.btn-confirm{background-color:#e27730;border-color:#e27730}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.jconfirm-type-red{border-color:#d63638}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.jconfirm-type-red div.jconfirm-buttons button.btn-confirm{background-color:#d63638;border-color:#d63638}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.jconfirm-type-blue{border-color:#3582c4}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.jconfirm-type-blue div.jconfirm-buttons button.btn-confirm{background-color:#3582c4;border-color:#3582c4}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.loading{border-top-color:#fff !important;height:160px}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.loading .jconfirm-title-c{display:block !important;position:relative;z-index:4}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.loading .jconfirm-title-c .jconfirm-icon-c{display:none}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.loading:before{z-index:2}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.loading:after{content:"";position:absolute;left:50%;top:68%;margin-left:-20px;height:40px;width:40px;border:solid 6px rgba(0,0,0,0);border-bottom-color:#e27730;opacity:1;z-index:3}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.wp-mail-smtp-upgrade-mailer-education-modal{padding:30px 30px 15px;border-top:none}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.wp-mail-smtp-upgrade-mailer-education-modal div.jconfirm-title-c{margin:0 0 26px 0;padding:0}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.wp-mail-smtp-upgrade-mailer-education-modal div.jconfirm-title-c .jconfirm-icon-c{margin-bottom:20px;color:#c4c4c4 !important}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.wp-mail-smtp-upgrade-mailer-education-modal div.jconfirm-title-c .jconfirm-icon-c svg{height:35px}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.wp-mail-smtp-upgrade-mailer-education-modal div.jconfirm-content-pane{margin-bottom:25px}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.wp-mail-smtp-upgrade-mailer-education-modal div.jconfirm-buttons button.btn-confirm{background-color:#e27730;border-color:#e27730}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.wp-mail-smtp-upgrade-mailer-education-modal .discount-note{text-align:center;margin:45px 0 0}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.wp-mail-smtp-upgrade-mailer-education-modal .discount-note p{background-color:#fcf9e8;margin:0 -30px;padding:24px 60px 20px;font-size:15px;color:#4d4d4d;position:relative}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.wp-mail-smtp-upgrade-mailer-education-modal .discount-note p:after{content:url(../images/font-awesome/check-circle-solid-green.svg);width:40px;height:40px;background-color:#fff;border-radius:50%;padding:5px 6px;position:absolute;top:-20px;right:50%;margin-right:-18px}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.wp-mail-smtp-upgrade-mailer-education-modal .discount-note span{font-weight:600;color:#00a32a}body.wp-mail-smtp-admin-page-body div.jconfirm .jconfirm-box.wp-mail-smtp-upgrade-mailer-education-modal .discount-note a{color:#aaa;display:block;margin-top:12px}@media screen and (max-width: 1023px){#wp-mail-smtp-notice-bar{display:none !important}}#wp-mail-smtp-notice-bar{max-height:35px;position:relative;margin-bottom:-3px;transition:all .3s ease-out;overflow:hidden}#wp-mail-smtp-notice-bar.out{max-height:3px}#wp-mail-smtp-notice-bar .wp-mail-smtp-notice-bar-container{background-color:#fcf9e8;border-top:3px solid #e27730;color:#3a3a56;text-align:center;padding:7px}#wp-mail-smtp-notice-bar a{color:#e27730;font-weight:700}#wp-mail-smtp-notice-bar a:hover{color:#b85a1b}#wp-mail-smtp-notice-bar strong{color:#008a20;font-weight:700}#wp-mail-smtp-notice-bar .dismiss{position:absolute;top:0;right:0;border:none;padding:5px;margin-top:4px;background:0 0;color:#72777c;cursor:pointer}#wp-mail-smtp-notice-bar .dismiss:before{background:0 0;color:#72777c;content:"";display:block;font:normal 20px/20px dashicons;speak:none;height:20px;text-align:center;width:20px;-webkit-font-smoothing:antialiased}#screen-meta-links .screen-meta-toggle{position:absolute;right:20px;top:auto}#wp-mail-smtp .wp-mail-smtp-product-education__row{border-bottom:1px solid #e4e4e4;padding:25px 0 5px;font-size:14px;line-height:1.3;max-width:1005px}#wp-mail-smtp .wp-mail-smtp-product-education__row>*:last-child{border-bottom:none !important}#wp-mail-smtp .wp-mail-smtp-product-education__row--inactive{opacity:.5;pointer-events:none}#wp-mail-smtp .wp-mail-smtp-product-education__row--full-width{max-width:unset}#wp-mail-smtp .wp-mail-smtp-product-education__row--no-border{border-bottom:none !important}#wp-mail-smtp .wp-mail-smtp-product-education__row--no-padding{padding:0 !important}#wp-mail-smtp .wp-mail-smtp-product-education__row:first-of-type{padding-top:10px}#wp-mail-smtp .wp-mail-smtp-product-education__row:last-of-type+.wp-mail-smtp-btn-upgrade{margin-top:25px}#wp-mail-smtp .wp-mail-smtp-product-education__heading{display:flex;align-items:center;margin-top:0;margin-bottom:10px;font-size:20px;line-height:24px;color:#2c3337}#wp-mail-smtp .wp-mail-smtp-product-education__heading:after{content:"";margin-left:10px;background-image:url("../images/pro-badge-small.svg");background-size:contain;background-repeat:no-repeat;width:35px;height:16px}#wp-mail-smtp .wp-mail-smtp-product-education__description{margin-top:0;margin-bottom:20px;color:#50575e;font-size:14px;line-height:1.5em}#wp-mail-smtp .wp-mail-smtp-product-education__upgrade-btn--top{margin-bottom:20px}#wp-mail-smtp .wp-mail-smtp-product-education__screenshots{display:flex;flex-wrap:wrap}@media(max-width: 599px){#wp-mail-smtp .wp-mail-smtp-product-education__screenshots{flex-direction:column}}#wp-mail-smtp .wp-mail-smtp-product-education__screenshots>div{display:flex;flex-direction:column;align-items:center;margin:0 25px 20px 0}@media(max-width: 599px){#wp-mail-smtp .wp-mail-smtp-product-education__screenshots>div{margin-right:0;max-width:unset !important}}#wp-mail-smtp .wp-mail-smtp-product-education__screenshots>div:last-child{margin-right:0}#wp-mail-smtp .wp-mail-smtp-product-education__screenshots>div a{position:relative;margin-bottom:10px;background:#fff;border:5px solid #fff;box-sizing:border-box;border-radius:4px}#wp-mail-smtp .wp-mail-smtp-product-education__screenshots>div a:after{content:"";position:absolute;opacity:0;height:100%;width:100%;top:0;left:0;background-color:rgba(68,68,68,.15);background-image:url("../../assets/images/icons/zoom.svg");background-repeat:no-repeat;background-position:center;background-size:50px;transition:all .3s}#wp-mail-smtp .wp-mail-smtp-product-education__screenshots>div a:hover:after{opacity:1}#wp-mail-smtp .wp-mail-smtp-product-education__screenshots>div img{display:block;max-width:100%;height:auto}#wp-mail-smtp .wp-mail-smtp-product-education__screenshots>div span{font-size:14px;line-height:18px;text-align:center;color:#50575e}#wp-mail-smtp .wp-mail-smtp-product-education__screenshots--two>div{max-width:487px}#wp-mail-smtp .wp-mail-smtp-product-education__screenshots--three>div{max-width:316px}#wp-mail-smtp .wp-mail-smtp-product-education__list>h4{margin-top:0;margin-bottom:20px;font-size:16px;line-height:20px;color:#2c3337}#wp-mail-smtp .wp-mail-smtp-product-education__list>div{display:flex;flex-wrap:wrap}#wp-mail-smtp .wp-mail-smtp-product-education__list ul{width:290px;margin:0 40px 20px 0}#wp-mail-smtp .wp-mail-smtp-product-education__list ul li{display:flex;align-items:center;font-size:14px;line-height:20px;margin-bottom:0;color:#50575e}#wp-mail-smtp .wp-mail-smtp-product-education__list ul li+li{margin-top:20px}#wp-mail-smtp .wp-mail-smtp-product-education__list ul li:before{content:url("../../assets/images/icons/check-solid.svg");width:16px;margin-right:10px}#wp-mail-smtp #wp-mail-smtp-tools-export-email-logs-product-education section{margin-bottom:20px;cursor:not-allowed}#wp-mail-smtp #wp-mail-smtp-tools-export-email-logs-product-education section:last-of-type{margin-bottom:20px}#wp-mail-smtp #wp-mail-smtp-tools-export-email-logs-product-education section h5{clear:both;margin:0 0 10px 0;color:#2c3337;font-size:16px;font-weight:600}#wp-mail-smtp #wp-mail-smtp-tools-export-email-logs-product-education section label{clear:both;float:left;margin:3px 0 3px 0}#wp-mail-smtp #wp-mail-smtp-tools-export-email-logs-product-education section .wp-mail-smtp-date-selector{width:200px;cursor:pointer}#wp-mail-smtp #wp-mail-smtp-tools-export-email-logs-product-education section .wp-mail-smtp-search-box-field{width:200px}#wp-mail-smtp #wp-mail-smtp-tools-export-email-logs-product-education section .wp-mail-smtp-search-box-term{width:300px}#wp-mail-smtp #wp-mail-smtp-email-controls-product-education .wp-mail-smtp-product-education__row--inactive{padding-top:20px;padding-bottom:0}#wp-mail-smtp #wp-mail-smtp-email-controls-product-education .wp-mail-smtp-setting-row:last-child{border-bottom:none}#wp-mail-smtp .wp-mail-smtp-page-nw-product-edu h2{display:inline-block;vertical-align:middle}#wp-mail-smtp .wp-mail-smtp-page-nw-product-edu .badge{margin:0 0 2px 7px;vertical-align:middle;width:40px;height:17px}#wp-mail-smtp .wp-mail-smtp-page-nw-product-edu .wp-mail-smtp-setting-row-multisite{color:#9a9a9a}#wp-mail-smtp .wp-mail-smtp-page-nw-product-edu .wp-mail-smtp-setting-row-multisite p.desc{color:#bababa}#wp-mail-smtp .wp-mail-smtp-page-nw-product-edu .wp-mail-smtp-setting-row-multisite input[type=checkbox]:disabled{border-color:#aaa}#wp-mail-smtp .wp-mail-smtp-page-nw-product-edu .wp-mail-smtp-setting-row-no-setting{margin-top:30px}#wp-mail-smtp .wp-mail-smtp-upgrade-license-banner{border-radius:4px;border:1px solid #c3c4c7;background:#fff;padding:20px;max-width:796px;margin-top:20px}#wp-mail-smtp .wp-mail-smtp-upgrade-license-banner p{font-size:14px;margin:0 0 10px 0}#wp-mail-smtp .wp-mail-smtp-upgrade-license-banner strong{font-weight:500}#wp-mail-smtp .wp-mail-smtp-upgrade-license-banner__discount-line strong{font-weight:700;color:#008a20}#wp-mail-smtp .wp-mail-smtp-upgrade-license-banner__upgrade-btn{border-radius:4px;font-weight:400}#wp-mail-smtp .wp-mail-smtp-upgrade-banner{position:relative;padding:30px;border:1px solid #dadadf;background:#fff;box-shadow:0 2px 4px 0 rgba(0,0,0,.05)}#wp-mail-smtp .wp-mail-smtp-upgrade-banner p{margin:0}#wp-mail-smtp .wp-mail-smtp-upgrade-banner .wp-mail-smtp-pro-banner-dismiss{position:absolute;right:20px;top:20px}#wp-mail-smtp .wp-mail-smtp-upgrade-banner .wp-mail-smtp-pro-banner-dismiss button{background:none;border:none;color:#a9a9a9;cursor:pointer;margin:0;padding:0}#wp-mail-smtp .wp-mail-smtp-upgrade-banner__row+.wp-mail-smtp-upgrade-banner__row{margin-top:25px}#wp-mail-smtp .wp-mail-smtp-upgrade-banner__heading{color:#2c3338;font-size:17px;font-weight:500;line-height:1.5;margin:0 0 10px 0}#wp-mail-smtp .wp-mail-smtp-upgrade-banner__subheading{margin:0;color:#646970;font-size:14px;font-weight:500;line-height:1.4}#wp-mail-smtp .wp-mail-smtp-upgrade-banner__subheading strong{color:#2c3338;font-weight:700}#wp-mail-smtp .wp-mail-smtp-upgrade-banner__features{display:grid;grid-template-columns:fit-content(480px) fit-content(480px);grid-column-gap:60px;grid-row-gap:12px;margin:16px 0 0}@media(max-width: 599px){#wp-mail-smtp .wp-mail-smtp-upgrade-banner__features{grid-template-columns:1fr}}#wp-mail-smtp .wp-mail-smtp-upgrade-banner__features li{position:relative;margin:0;padding-left:16px;font-size:13px;line-height:1.5}#wp-mail-smtp .wp-mail-smtp-upgrade-banner__features li:before{position:absolute;content:"";top:3px;left:0;background-image:url("../../assets/images/icons/check.svg");background-size:contain;background-repeat:no-repeat;background-position:center;width:10px;height:10px}#wp-mail-smtp .wp-mail-smtp-upgrade-banner__features li h5{font-size:13px;margin:0 0 4px 0;color:#2c3338;font-weight:700}#wp-mail-smtp .wp-mail-smtp-upgrade-banner__features li p{margin:0;color:#50575e;font-weight:400}#wp-mail-smtp .wp-mail-smtp-upgrade-banner__upgrade-btn{font-size:16px;font-weight:500;padding:13px 19px;border-radius:4px}#wp-mail-smtp .wp-mail-smtp-upgrade-banner__discount-line{display:flex;align-items:center;color:#646970;line-height:1.4;margin-top:8px}#wp-mail-smtp .wp-mail-smtp-upgrade-banner__discount-line img{margin-right:7px}#wp-mail-smtp .wp-mail-smtp-upgrade-banner__discount-line strong{color:#008a20;font-weight:600}#wp-mail-smtp .wp-mail-smtp-upgrade-banner .wp-mail-smtp-product-education__screenshots{gap:25px}#wp-mail-smtp .wp-mail-smtp-upgrade-banner .wp-mail-smtp-product-education__screenshots>div{margin:0;max-width:365px}#wp-mail-smtp .wp-mail-smtp-upgrade-banner .wp-mail-smtp-product-education__screenshots>div a{border-color:#dcdcde}#wp-mail-smtp .wp-mail-smtp-upgrade-banner .wp-mail-smtp-product-education__screenshots>div span{color:#646970}.wp-mail-smtp-lite #wp-mail-smtp .wp-mail-smtp-page-reports .wp-mail-smtp-page-title .page-title{position:relative}.wp-mail-smtp-lite #wp-mail-smtp .wp-mail-smtp-page-reports .wp-mail-smtp-page-title .page-title:after{content:"";display:inline-block;margin-left:10px;background-image:url("../images/pro-badge-small.svg");background-size:contain;background-repeat:no-repeat;width:35px;height:16px}.wp-mail-smtp-lite #wp-mail-smtp #wp-mail-smtp-setting-row-gmail-one_click_setup_enabled-lite .wp-mail-smtp-toggle::after,.wp-mail-smtp-lite #wp-mail-smtp #wp-mail-smtp-setting-row-misc-rate_limit-lite .wp-mail-smtp-toggle::after{content:"";margin-left:10px;background-image:url("../images/pro-badge-small.svg");background-size:contain;background-repeat:no-repeat;width:35px;height:16px}.wp-mail-smtp-loading{animation:.65s linear infinite wp-mail-smtp-loading-spin}.wp-mail-smtp-loading-md{width:32px;height:32px}.wp-mail-smtp-loading-sm{width:16px;height:16px}.wp-mail-smtp-loading-spin{position:relative;color:rgba(0,0,0,0) !important;pointer-events:none}.wp-mail-smtp-loading-spin:after{position:absolute;box-sizing:border-box;animation:.65s linear infinite wp-mail-smtp-loading-spin;border:2px solid #fff;border-radius:50%;border-right-color:rgba(0,0,0,0) !important;border-top-color:rgba(0,0,0,0) !important;content:"";display:block;top:50%;left:50%;width:16px;height:16px;margin-top:-8px;margin-left:-8px}@keyframes wp-mail-smtp-loading-spin{0%{transform:rotateZ(270deg)}100%{transform:rotateZ(630deg)}}#wp-mail-smtp-flyout{position:fixed;z-index:99999;transition:all .2s ease-in-out;right:40px;bottom:40px;opacity:1}@media(max-width: 959px){#wp-mail-smtp-flyout{display:none}}#wp-mail-smtp-flyout .wp-mail-smtp-flyout-head{display:block}#wp-mail-smtp-flyout .wp-mail-smtp-flyout-head:focus{box-shadow:none}#wp-mail-smtp-flyout .wp-mail-smtp-flyout-head figure{margin:0;border-radius:50%;border:3px solid #e27730;overflow:hidden;box-shadow:0 2px 20px rgba(0,0,0,.15);background-color:#fff;transition:all .2s ease-in-out}#wp-mail-smtp-flyout .wp-mail-smtp-flyout-head figure img{display:block;width:54px;height:54px;transition:all .2s ease-in-out}#wp-mail-smtp-flyout .wp-mail-smtp-flyout-head:hover figure{box-shadow:0 2px 30px rgba(0,0,0,.2)}#wp-mail-smtp-flyout .wp-mail-smtp-flyout-head .wp-mail-smtp-flyout-label{right:calc(100% + 15px);opacity:0;transform:translateY(-50%) scale(0);margin-right:-50px}#wp-mail-smtp-flyout .wp-mail-smtp-flyout-head:hover .wp-mail-smtp-flyout-label{opacity:1;transform:translateY(-50%) scale(1);margin-right:0}#wp-mail-smtp-flyout .wp-mail-smtp-flyout-label{position:absolute;display:block;top:50%;right:calc(100% + 15px);transform:translateY(-50%);-moz-transform:translateY(-50%);-webkit-transform:translateY(-50%);color:#fff;background-color:#a7aaad;font-size:12px;white-space:nowrap;padding:6px 10px;height:auto !important;line-height:initial;transition:all .2s ease-out;border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px}#wp-mail-smtp-flyout .wp-mail-smtp-flyout-item{position:absolute;display:flex;left:10px;width:40px;height:40px;opacity:0;visibility:hidden;transition:all .2s ease-in-out;transform:scale(0);border-radius:50%;box-shadow:0px 2px 10px rgba(0,0,0,.15);background-color:#738e9e}#wp-mail-smtp-flyout .wp-mail-smtp-flyout-item img{margin:auto}#wp-mail-smtp-flyout .wp-mail-smtp-flyout-item.wp-mail-smtp-flyout-item-0{bottom:75px}#wp-mail-smtp-flyout .wp-mail-smtp-flyout-item.wp-mail-smtp-flyout-item-1{bottom:130px}#wp-mail-smtp-flyout .wp-mail-smtp-flyout-item.wp-mail-smtp-flyout-item-2{bottom:185px}#wp-mail-smtp-flyout .wp-mail-smtp-flyout-item.wp-mail-smtp-flyout-item-3{bottom:240px}#wp-mail-smtp-flyout .wp-mail-smtp-flyout-item.wp-mail-smtp-flyout-item-4{bottom:295px}#wp-mail-smtp-flyout .wp-mail-smtp-flyout-item:hover{background-color:#395360}#wp-mail-smtp-flyout .wp-mail-smtp-flyout-item:hover .wp-mail-smtp-flyout-label{background-color:#787c82}#wp-mail-smtp-flyout.opened .wp-mail-smtp-flyout-item{opacity:1;visibility:visible;transform:scale(1)}#wp-mail-smtp-flyout.opened .wp-mail-smtp-flyout-head .wp-mail-smtp-flyout-label{display:none}#wp-mail-smtp-flyout.opened .wp-mail-smtp-flyout-head figure img{transform:rotate(-15deg) scale(1.17)}#wp-mail-smtp-flyout.opened .wp-mail-smtp-flyout-item-0{transition:transform .2s 0ms,background-color .2s}#wp-mail-smtp-flyout.opened .wp-mail-smtp-flyout-item-1{transition:transform .2s 35ms,background-color .2s}#wp-mail-smtp-flyout.opened .wp-mail-smtp-flyout-item-2{transition:transform .2s 70ms,background-color .2s}#wp-mail-smtp-flyout.opened .wp-mail-smtp-flyout-item-3{transition:transform .2s 105ms,background-color .2s}#wp-mail-smtp-flyout.opened .wp-mail-smtp-flyout-item-4{transition:transform .2s 140ms,background-color .2s}#wp-mail-smtp-flyout.out{opacity:0;visibility:hidden}.wp-mail-smtp-tooltip{position:relative;display:inline-block;text-decoration:underline;text-decoration-style:dotted;cursor:help;color:#50575e;margin-top:15px !important}.wp-mail-smtp-tooltip-with-icon{margin-top:2px !important;margin-left:10px}.wp-mail-smtp-tooltip-with-icon .wp-mail-smtp-tooltip-text{bottom:130%}.wp-mail-smtp-tooltip-text{visibility:hidden;position:absolute;z-index:9999;width:360px;background-color:#2d4f60;color:#fff;text-align:center;padding:16px 20px;font-size:14px;border-radius:5px;bottom:100%;left:50%;margin-left:-180px}.wp-mail-smtp-tooltip-text::after{content:" ";position:absolute;top:100%;left:50%;margin-left:-5px;border-width:5px;border-style:solid;border-color:#2d4f60 rgba(0,0,0,0) rgba(0,0,0,0) rgba(0,0,0,0)}.wp-mail-smtp-tooltip-small-text{font-size:12px;line-height:140%;text-align:left}.wp-mail-smtp-tooltip-small-text code,.wp-mail-smtp-tooltip-small-text kbd{font-size:12px}.wp-mail-smtp-tooltip:hover .wp-mail-smtp-tooltip-text{visibility:visible}.wp-mail-smtp-page label.wp-mail-smtp-setting-label-with-tooltip .wp-mail-smtp-tooltip-with-icon{margin-left:0;position:relative;left:0;top:0;vertical-align:top}.wp-mail-smtp-page .wp-mail-smtp-tooltip-text a{color:#fff}.wp-mail-smtp-page .wp-mail-smtp-tooltip-text a:active,.wp-mail-smtp-page .wp-mail-smtp-tooltip-text a:hover{color:#fff}#wp-mail-smtp .wp-mail-smtp-conditional button{cursor:pointer}#wp-mail-smtp .wp-mail-smtp-conditional table{width:100%;max-width:740px;padding:0;margin:0;border-collapse:collapse;border-spacing:0;font-size:13px}#wp-mail-smtp .wp-mail-smtp-conditional table td{padding:0 10px 20px 0}@media(max-width: 600px){#wp-mail-smtp .wp-mail-smtp-conditional__row{display:flex;flex-direction:column}}#wp-mail-smtp .wp-mail-smtp-conditional__row input,#wp-mail-smtp .wp-mail-smtp-conditional__row select{width:100% !important;max-width:100%;margin:0;text-overflow:ellipsis}#wp-mail-smtp .wp-mail-smtp-conditional__property-col{width:23%}@media(max-width: 600px){#wp-mail-smtp .wp-mail-smtp-conditional__property-col{width:100%}}#wp-mail-smtp .wp-mail-smtp-conditional__operator-col{width:23%}@media(max-width: 600px){#wp-mail-smtp .wp-mail-smtp-conditional__operator-col{width:100%}}#wp-mail-smtp .wp-mail-smtp-conditional__value-col{width:42%}@media(max-width: 600px){#wp-mail-smtp .wp-mail-smtp-conditional__value-col{width:100%}}#wp-mail-smtp .wp-mail-smtp-conditional__value :disabled{background-color:#f1f1f1;cursor:not-allowed}#wp-mail-smtp .wp-mail-smtp-conditional__actions{display:flex;align-items:center;padding-right:0}#wp-mail-smtp .wp-mail-smtp-conditional__delete-rule{background-color:rgba(0,0,0,0);border:none;color:#999;margin:0 0 0 10px;padding:0;vertical-align:middle}#wp-mail-smtp .wp-mail-smtp-conditional__delete-rule:hover{color:#d63638}#wp-mail-smtp .wp-mail-smtp-conditional__group-delimiter{margin:0 0 20px;font-size:14px;font-style:italic;font-weight:400;line-height:17px;color:#646970}.wp-mail-smtp-toggle{vertical-align:middle;display:inline-flex;align-items:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.wp-mail-smtp-toggle__switch{position:relative;width:27px;height:17px;flex-shrink:0;cursor:pointer;background-color:#ccc;border-radius:10px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-ms-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wp-mail-smtp-toggle__switch:before{position:absolute;content:"";height:13px;width:13px;left:2px;top:2px;background-color:#fff;border-radius:50%;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-ms-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wp-mail-smtp-toggle__label{display:none;margin-left:10px;font-weight:400;font-size:13px;line-height:15px;color:#50575e;text-transform:uppercase}.wp-mail-smtp-toggle__label--static{display:block;text-transform:none}.wp-mail-smtp-toggle input[type=checkbox]{position:absolute;top:auto;overflow:hidden;clip:rect(1px, 1px, 1px, 1px);width:1px;height:1px;white-space:nowrap}.wp-mail-smtp-toggle input[type=checkbox]:not(:checked):hover+.wp-mail-smtp-toggle__switch,.wp-mail-smtp-toggle input[type=checkbox]:not(:checked):focus+.wp-mail-smtp-toggle__switch{box-shadow:0 0 0 1px #fff,0 0 0 3px #999;background-color:#999}.wp-mail-smtp-toggle input[type=checkbox]:not(:checked)~.wp-mail-smtp-toggle__label--unchecked{display:block}.wp-mail-smtp-toggle input[type=checkbox]:checked+.wp-mail-smtp-toggle__switch{background-color:#00a32a}.wp-mail-smtp-toggle input[type=checkbox]:checked+.wp-mail-smtp-toggle__switch:before{-webkit-transform:translateX(10px);-ms-transform:translateX(10px);transform:translateX(10px)}.wp-mail-smtp-toggle input[type=checkbox]:checked:hover+.wp-mail-smtp-toggle__switch,.wp-mail-smtp-toggle input[type=checkbox]:checked:focus+.wp-mail-smtp-toggle__switch{box-shadow:0 0 0 1px #fff,0 0 0 3px #00a32a}.wp-mail-smtp-toggle input[type=checkbox]:checked~.wp-mail-smtp-toggle__label--checked{display:block}.wp-mail-smtp-toggle input[type=checkbox]:disabled:hover+.wp-mail-smtp-toggle__switch,.wp-mail-smtp-toggle input[type=checkbox]:disabled:focus+.wp-mail-smtp-toggle__switch{box-shadow:none}.wp-mail-smtp-toggle input[type=checkbox]:disabled~*{opacity:.5;cursor:default}.wp-mail-smtp-admin-page-body #wpbody-content{padding-bottom:200px}@media(max-width: 782px){.wp-mail-smtp-admin-page-body #wpbody-content{padding-bottom:0 !important}}.wp-mail-smtp-admin-page-body #wpfooter a{color:#2171b1 !important}.wp-mail-smtp-admin-page-body #wpfooter a:hover,.wp-mail-smtp-admin-page-body #wpfooter a:active{color:#135e96 !important}.wp-mail-smtp-admin-page-body #wpfooter .wp-mail-smtp-footer-promotion{text-align:center;font-weight:400;font-size:13px;line-height:normal;color:#646970;padding:30px 0;margin-bottom:20px}.wp-mail-smtp-admin-page-body #wpfooter .wp-mail-smtp-footer-promotion p{font-weight:600}.wp-mail-smtp-admin-page-body #wpfooter .wp-mail-smtp-footer-promotion-links,.wp-mail-smtp-admin-page-body #wpfooter .wp-mail-smtp-footer-promotion-social{display:flex;justify-content:center;align-items:center}.wp-mail-smtp-admin-page-body #wpfooter .wp-mail-smtp-footer-promotion-links{margin:10px 0;color:#646970}.wp-mail-smtp-admin-page-body #wpfooter .wp-mail-smtp-footer-promotion-links a{color:#04558a}.wp-mail-smtp-admin-page-body #wpfooter .wp-mail-smtp-footer-promotion-links a:hover{color:#04558a}.wp-mail-smtp-admin-page-body #wpfooter .wp-mail-smtp-footer-promotion-links span{color:#c3c4c7;padding:0 7px}.wp-mail-smtp-admin-page-body #wpfooter .wp-mail-smtp-footer-promotion-social{gap:10px;margin:0}.wp-mail-smtp-admin-page-body #wpfooter .wp-mail-smtp-footer-promotion-social li{margin-bottom:0}.wp-mail-smtp-admin-page-body #wpfooter .wp-mail-smtp-footer-promotion-social li path{color:#646970}.wp-mail-smtp-admin-page-body #wpfooter .wp-mail-smtp-footer-promotion-social li:hover path{fill:#50575e}.wp-mail-smtp-admin-page-body #wpfooter .wp-mail-smtp-footer-promotion-social a{display:block;height:16px}.wp-mail-smtp-admin-page-body #wpfooter #footer-left{color:#50575e;font-size:13px;font-style:normal;font-weight:400;line-height:normal}.wp-mail-smtp-admin-page-body #wpfooter #footer-left strong{font-weight:600}#screen-meta-links,#screen-meta{display:none}#wp-mail-smtp-header-temp{position:absolute;margin:0;top:-1px;left:20px;right:0;z-index:99}#wp-mail-smtp-header{border-top:3px solid #e27730;padding:24px 20px}#wp-mail-smtp-header img{display:block;margin:0;max-width:242px}@media(max-width: 782px){#wp-mail-smtp-header img{max-width:200px}}.wp-mail-smtp-page{color:#2c3337}.wp-mail-smtp-page a{color:#2171b1}.wp-mail-smtp-page a:hover,.wp-mail-smtp-page a:active{color:#135e96}#wp-mail-smtp{margin:0}#wp-mail-smtp .wp-mail-smtp-hide{display:none}#wp-mail-smtp .wp-mail-smtp-page-title{min-height:58px;background-color:#fff;font-size:14px;margin:0 0 20px 0;padding:0 20px}#wp-mail-smtp .wp-mail-smtp-page-title a.tab{border-bottom:3px solid #fff;box-shadow:none;color:#666;display:inline-block;margin-right:30px;padding:20px 0 17px 0;text-decoration:none}#wp-mail-smtp .wp-mail-smtp-page-title a.tab.active{border-color:#e27730}#wp-mail-smtp .wp-mail-smtp-page-title a.tab:hover{border-color:#999}#wp-mail-smtp .wp-mail-smtp-page-title a.action{color:#fff;font-weight:600;margin:14px 0 14px 10px;line-height:28px;min-height:30px;vertical-align:top}@media(max-width: 600px){#wp-mail-smtp .wp-mail-smtp-page-title a.action{margin-left:0}}#wp-mail-smtp .wp-mail-smtp-page-title .page-title{background-color:#fff;display:inline-block;font-size:23px;margin:0;padding:20px 20px 20px 0}#wp-mail-smtp .wp-mail-smtp-page-content{padding:0 20px}#wp-mail-smtp .wp-mail-smtp-page-content *,#wp-mail-smtp .wp-mail-smtp-page-content *::before,#wp-mail-smtp .wp-mail-smtp-page-content *::after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-clear:before{content:" ";display:table}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-clear:after{clear:both;content:" ";display:table}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row{border-bottom:1px solid #e4e4e4;padding:30px 0;font-size:14px;line-height:1.3}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row:first-of-type{padding-top:10px !important}@media(max-width: 781px){#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row{padding:20px 0}}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.inactive{display:none}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row .wp-mail-smtp-setting-mid-row-sep{background:#e4e4e4;height:1px;border:0;margin:15px 0}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.section-heading{padding:20px 0 10px;border-bottom:none}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.section-heading.no-desc h2,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.section-heading.no-desc h4{margin:0}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.section-heading.wp-mail-smtp-section-heading--has-divider{padding:20px 0 30px;border-bottom:1px solid #e4e4e4}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.section-heading .wp-mail-smtp-setting-field{margin:0;max-width:1005px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.section-heading .desc{font-style:normal}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-checkbox input[type=checkbox]{float:left;margin:1px 0 0 0}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-checkbox input[type=checkbox]+label{margin:0 0 0 8px;vertical-align:baseline}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-checkbox .desc{margin:0 0 0 30px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-checkbox input[type=checkbox]+label+.desc{margin:8px 0 0 0}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-text .wp-mail-smtp-setting-label,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-password .wp-mail-smtp-setting-label,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-number .wp-mail-smtp-setting-label,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-email .wp-mail-smtp-setting-label{padding-top:8px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-select .wp-mail-smtp-setting-label{padding-top:8px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-radio .wp-mail-smtp-setting-field input[type=radio]{margin:-3px 10px 0 0}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-radio .wp-mail-smtp-setting-field label{margin-right:30px;display:inline-block}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-no-border{border-bottom:none}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-no-padding{padding:0}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-license_key .wp-mail-smtp-setting-field p:first-child{margin-top:0}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-mailer{padding-bottom:20px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-mailer .wp-mail-smtp-mailers .wp-mail-smtp-mailer{display:inline-block;width:140px;margin-right:12px;margin-bottom:12px;position:relative}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-mailer .wp-mail-smtp-mailers .wp-mail-smtp-mailer .wp-mail-smtp-mailer-image{background:#fff;text-align:center;border:2px solid #e5e5e5;border-radius:4px;cursor:pointer;height:76px;position:relative;margin-bottom:10px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-ms-transition:all .2s ease-in-out;transition:all .2s ease-in-out}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-mailer .wp-mail-smtp-mailers .wp-mail-smtp-mailer .wp-mail-smtp-mailer-image.is-recommended{background-image:url(../images/recommended.svg);background-repeat:no-repeat;background-size:60%;background-position:top right -2px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-mailer .wp-mail-smtp-mailers .wp-mail-smtp-mailer .wp-mail-smtp-mailer-image img{max-width:80%;max-height:40px;display:block;position:relative;top:50%;left:50%;transform:translate(-50%, -50%);opacity:.6;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-ms-transition:all .2s ease-in-out;transition:all .2s ease-in-out}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-mailer .wp-mail-smtp-mailers .wp-mail-smtp-mailer.wp-mail-smtp-mailer-smtp .wp-mail-smtp-mailer-image img{max-height:30px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-mailer .wp-mail-smtp-mailers .wp-mail-smtp-mailer.active .wp-mail-smtp-mailer-image{border-color:#e27730}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-mailer .wp-mail-smtp-mailers .wp-mail-smtp-mailer.active .wp-mail-smtp-mailer-image img{opacity:1}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-mailer .wp-mail-smtp-mailers .wp-mail-smtp-mailer:hover .wp-mail-smtp-mailer-image{border-color:#ccc}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-mailer .wp-mail-smtp-mailers .wp-mail-smtp-mailer:hover .wp-mail-smtp-mailer-image img{opacity:1}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-alert{padding-top:20px;padding-bottom:25px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-alert .wp-mail-smtp-setting-row{border:none}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-alert .section-heading{margin-bottom:25px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-alert .section-heading h3{margin-bottom:10px;font-weight:500;font-size:18px;line-height:22px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-alert .section-heading .notice{margin-top:20px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-alert .section-heading .notice p{margin:6.5px 0;font-size:13px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-alert .wp-mail-smtp-setting-row{padding:0 !important}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-alert .wp-mail-smtp-setting-row+.wp-mail-smtp-setting-row{margin-top:20px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-alert .wp-mail-smtp-setting-label label{font-weight:500}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-alert .dashicons-trash{position:relative;top:6px;color:#a7aaad;cursor:pointer;transition:.2s}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row.wp-mail-smtp-setting-row-alert .dashicons-trash:hover{color:#d63638}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row#wp-mail-smtp-setting-row-alerts-twilio_sms .wp-mail-smtp-setting-row-alert-connection-options{position:relative}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row#wp-mail-smtp-setting-row-alerts-twilio_sms .wp-mail-smtp-setting-row-alert-connection-options+.wp-mail-smtp-setting-row-alert-connection-options:before{content:"";display:block;max-width:605px;height:1px;margin-bottom:20px;background-color:#dcdcde}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row#wp-mail-smtp-setting-row-alerts-whatsapp .wp-mail-smtp-setting-row-alert-connection-options{position:relative}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row#wp-mail-smtp-setting-row-alerts-whatsapp .wp-mail-smtp-setting-row-alert-connection-options+.wp-mail-smtp-setting-row-alert-connection-options:before{content:"";display:block;max-width:605px;height:1px;margin-bottom:20px;background-color:#dcdcde}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row#wp-mail-smtp-setting-row-alerts-whatsapp .wp-mail-smtp-setting-row-alert-connection-options .wp-mail-smtp-setting-row:first-child .wp-mail-smtp-setting-field{position:relative}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row#wp-mail-smtp-setting-row-alerts-whatsapp .wp-mail-smtp-setting-row-alert-connection-options .wp-mail-smtp-setting-row:first-child .wp-mail-smtp-setting-field .js-wp-mail-smtp-setting-alert-remove-connection{position:absolute;top:8px;left:415px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row h2,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row h4{color:#2c3337;font-size:20px;font-weight:600;margin:0 0 6px 0}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row h2{margin-bottom:15px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row h3{color:#2c3337;font-size:24px;font-weight:600;margin:0 0 20px 0}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row h5{color:#2c3337;font-size:16px;font-weight:600;margin:0 0 20px 0}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row p{margin:12px 0 0;font-size:14px;line-height:1.5em}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row p:first-of-type{margin:8px 0 0}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row p.desc{margin:10px 0 0;font-style:italic;color:#50575e}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row p.desc+.desc{font-style:normal}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row p.buttonned{margin-top:30px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row p.inline-notice{margin:5px 0 15px;box-sizing:border-box;background:#fff;border-left:4px solid rgba(0,0,0,0);box-shadow:0 1px 1px 0 rgba(0,0,0,.1)}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row p.inline-notice.inline-error{border-color:#d63638;margin-bottom:5px;padding:10px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row p.inline-notice.inline-info{border-color:#2171b1;margin-bottom:5px;padding:10px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row p.inline-notice.inline-edu-notice{border-color:#809eb0;line-height:1.5em;padding:10px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row p.inline-notice a.wp-mail-smtp-mailer-notice-dismiss{float:right;color:#999da1;margin:0 0 10px 10px;text-decoration:none}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row p.inline-notice a.wp-mail-smtp-mailer-notice-dismiss:hover{color:#666a6e}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row ul{margin:8px 0 0}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row ul.list li{margin-left:20px;list-style-type:disc}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row table.actions-list td,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row table.actions-list th{padding:5px 5px 5px 0;text-align:left}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row table.actions-list td.email{padding-right:2em}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row table.actions-list td.status{width:100px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row table.actions-list td.actions a{border-bottom:1px solid;display:inline-block;margin-right:5px;text-decoration:none}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row table.actions-list td.actions a[class*=delete],#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row table.actions-list td.actions a[class*=error]{color:#d63638}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row table.actions-list td.actions a[class*=delete]:hover,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row table.actions-list td.actions a[class*=delete]:active,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row table.actions-list td.actions a[class*=delete]:focus,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row table.actions-list td.actions a[class*=error]:hover,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row table.actions-list td.actions a[class*=error]:active,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row table.actions-list td.actions a[class*=error]:focus{color:#8a1c1d}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=text],#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=email],#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=number],#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=password],#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row select{background-color:#fff;border:1px solid #8d8f95;border-radius:4px;box-shadow:none;color:#2c3337;display:inline-block;vertical-align:middle;padding:7px 12px;margin:0 10px 0 0;width:400px;min-height:36px;line-height:1.3}@media(max-width: 959px){#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=text],#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=email],#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=number],#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=password],#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row select{width:300px}}@media(max-width: 599px){#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=text],#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=email],#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=number],#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=password],#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row select{width:100%;max-width:unset;margin-right:0}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=text]~button,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=text]~.wp-mail-smtp-btn,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=email]~button,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=email]~.wp-mail-smtp-btn,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=number]~button,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=number]~.wp-mail-smtp-btn,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=password]~button,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=password]~.wp-mail-smtp-btn,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row select~button,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row select~.wp-mail-smtp-btn{margin-top:8px}}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=text][readonly],#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=email][readonly],#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=number][readonly],#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=password][readonly],#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row select[readonly]{background-color:#f9f9f9}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=text].small-text,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=email].small-text,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=number].small-text,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=password].small-text,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row select.small-text{width:75px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=text]:focus,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=email]:focus,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=number]:focus,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=password]:focus,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row select:focus{border:1px solid #016aab;box-shadow:0 0 0 1px #016aab;outline:none}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=text]:disabled,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=email]:disabled,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=number]:disabled,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=password]:disabled,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row select:disabled{opacity:.6}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=checkbox]:focus,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row input[type=radio]:focus{border:1px solid #016aab;box-shadow:0 0 0 1px #016aab;outline:none}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row .wp-mail-smtp-dashicons-yes-alt-green.wp-mail-smtp-animate{-webkit-animation:wp-mail-smtp-fade-in-stop-out 1s linear;animation:wp-mail-smtp-fade-in-stop-out 1s linear}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-row .wp-mail-smtp-dashicons-yes-alt-green.wp-mail-smtp-success{color:#00a32a}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-group{border-bottom:1px solid #e4e4e4;padding:0 0 30px}@media(max-width: 781px){#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-group{padding:0 0 20px}}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-group:first-of-type{padding-top:10px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-group .wp-mail-smtp-setting-row{border:none;padding:30px 0 0 !important}@media(max-width: 781px){#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-group .wp-mail-smtp-setting-row{padding:20px 0 0}}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-label{display:block;float:left;width:205px;padding:0 20px 0 0}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-label-with-tooltip{display:flex}@media(max-width: 781px){#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-label{float:none;width:100%;padding-bottom:15px}}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-label label{display:block;font-weight:600}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-field{display:block;margin:0 0 0 205px;max-width:800px}@media(max-width: 781px){#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-field{margin:0}}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-field hr{margin:20px 0}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-field .wp-mail-smtp-setting-field-row{display:flex;flex-wrap:wrap}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-field .wp-mail-smtp-setting-field-row>.wp-mail-smtp-btn+.wp-mail-smtp-btn{margin-left:10px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-field .wp-mail-smtp-setting-status-label{display:inline-flex;align-items:center;font-size:12px;padding:4px 8px;border-radius:4px;background-color:#fff4cd;color:#bd8600}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-field .wp-mail-smtp-setting-status-label.wp-mail-smtp-setting-status-label-approved{background-color:#cefad4;color:#008a20}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-field .wp-mail-smtp-setting-status-label.wp-mail-smtp-setting-status-label-not-found,#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-field .wp-mail-smtp-setting-status-label.wp-mail-smtp-setting-status-label-rejected{background-color:#ffe2e4;color:#d63638}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-field .wp-mail-smtp-setting-status-label img{margin-left:4px;height:12px;width:auto}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-field .wp-mail-smtp-whatsapp-recheck-status{display:inline-flex;align-items:center;padding:7px;margin-left:5px;margin-right:5px;text-decoration:none;color:#2271b1;font-size:12px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-field .wp-mail-smtp-whatsapp-recheck-status img{margin-left:4px;margin-right:4px;height:12px;width:auto}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-field .wp-mail-smtp-whatsapp-recheck-status:hover{color:#135e96}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-field .wp-mail-smtp-whatsapp-recheck-status:focus{outline:none;box-shadow:none}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-setting-field .wp-mail-smtp-whatsapp-recheck-status.loading img{animation:wp-mail-smtp-spin 2s linear infinite}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-submit{margin:0;padding:25px 0}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-submit .help-text{margin-left:10px;vertical-align:middle}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-mailer-options .wp-mail-smtp-mailer-option .wp-mail-smtp-setting-row.section-heading{padding:20px 0 !important}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-mailer-options .wp-mail-smtp-mailer-option blockquote{background:#e5e5e5;border-radius:4px;color:#666;font-size:14px;margin:20px 0;padding:15px;max-width:1005px;width:100%}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-mailer-options .wp-mail-smtp-connected-row{display:flex;align-items:center}@media(max-width: 781px){#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-mailer-options .wp-mail-smtp-connected-row{flex-direction:column;align-items:flex-start}}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-mailer-options .wp-mail-smtp-connected-row__info{margin-left:30px}@media(max-width: 781px){#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-mailer-options .wp-mail-smtp-connected-row__info{margin-left:0;margin-top:10px}}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-mailer-options p.inline-notice{margin-top:10px}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-mailer-options p.inline-notice:first-child{margin-top:0}#wp-mail-smtp .wp-mail-smtp-page-content .wp-mail-smtp-mailer-options p.inline-notice:last-child{margin-bottom:0}#wp-mail-smtp .wp-mail-smtp-page-content.wp-mail-smtp-page-general p{margin:0}#wp-mail-smtp .wp-mail-smtp-page-content .notice-inline{background:#fff;border-left:4px solid #fff;box-shadow:0 1px 1px 0 rgba(0,0,0,.1);margin:5px 0 15px;padding:1px 12px}#wp-mail-smtp .wp-mail-smtp-page-content .notice-inline.notice-success{border-left-color:#00a32a}#wp-mail-smtp .wp-mail-smtp-page-content .notice-inline.notice-warning{border-left-color:#ffb900}#wp-mail-smtp .wp-mail-smtp-page-content .notice-inline.notice-error{border-left-color:#d63638}#wp-mail-smtp .wp-mail-smtp-page-content .notice-inline.notice-info{border-left-color:#00a0d2}#wp-mail-smtp .wp-mail-smtp-page-content .notice p,#wp-mail-smtp .wp-mail-smtp-page-content .notice-inline p,#wp-mail-smtp .wp-mail-smtp-page-content .notice p:first-of-type,#wp-mail-smtp .wp-mail-smtp-page-content .notice-inline p:first-of-type{margin:.5em 0;padding:2px}#wp-mail-smtp .wp-mail-smtp-page-content pre{white-space:pre-line}#wp-mail-smtp .wp-mail-smtp-page-content.active{display:block}#wp-mail-smtp .wp-mail-smtp-page-content .connected-as{margin-left:30px}@media(max-width: 599px){#wp-mail-smtp .wp-mail-smtp-page-content .connected-as{display:block;margin-left:0;margin-top:8px}}#wp-mail-smtp .wp-mail-smtp-admin-columns>div[class*=-column-]{float:left}#wp-mail-smtp .wp-mail-smtp-admin-columns .wp-mail-smtp-admin-column-20{width:20%}#wp-mail-smtp .wp-mail-smtp-admin-columns .wp-mail-smtp-admin-column-33{width:33.33333%}#wp-mail-smtp .wp-mail-smtp-admin-columns .wp-mail-smtp-admin-column-40{width:40%}#wp-mail-smtp .wp-mail-smtp-admin-columns .wp-mail-smtp-admin-column-50{width:50%}#wp-mail-smtp .wp-mail-smtp-admin-columns .wp-mail-smtp-admin-column-60{width:60%}#wp-mail-smtp .wp-mail-smtp-admin-columns .wp-mail-smtp-admin-column-80{width:80%}#wp-mail-smtp .wp-mail-smtp-admin-columns .wp-mail-smtp-admin-column-last{float:right !important}#wp-mail-smtp .wp-mail-smtp-admin-columns:after{content:"";display:table;clear:both}#wp-mail-smtp .notice blockquote{margin-left:0;padding:2px}#wp-mail-smtp .notice blockquote pre{margin:0;white-space:pre-line}#wp-mail-smtp #wp-mail-smtp-reset-filter{clear:both;margin:20px 0;padding:10px;font-size:15px;text-align:center;background:#fff;border:1px solid #ccd0d4;box-shadow:0 1px 1px rgba(0,0,0,.04)}#wp-mail-smtp #wp-mail-smtp-reset-filter a{text-decoration:none}#wp-mail-smtp #wp-mail-smtp-reset-filter .reset{cursor:pointer;color:#a6a6a6;font-size:15px;line-height:18px;width:18px;height:18px}#wp-mail-smtp #wp-mail-smtp-reset-filter .reset:focus,#wp-mail-smtp #wp-mail-smtp-reset-filter .reset:hover{color:#d63638}@media(min-width: 783px){#wp-mail-smtp .wp-mail-smtp-tab-tools-debug-events th#event{width:130px}#wp-mail-smtp .wp-mail-smtp-tab-tools-debug-events th#type{width:80px}#wp-mail-smtp .wp-mail-smtp-tab-tools-debug-events th#initiator{width:20%}#wp-mail-smtp .wp-mail-smtp-tab-tools-debug-events th#created_at{width:200px}}#wp-mail-smtp .wp-mail-smtp-tab-misc #wp-mail-smtp-setting-row-rate_limit_periods input[type=number]{width:100px}#wp-mail-smtp .wp-mail-smtp-tab-misc #wp-mail-smtp-setting-row-uninstall .wp-mail-smtp-danger{font-weight:600;color:#d63638}@media(max-width: 782px){#wp-mail-smtp .wp-mail-smtp-filter-date{display:flex !important;flex-direction:column;align-items:flex-start;float:none;width:100%;padding-right:0;margin-bottom:10px;max-width:600px}}#wp-mail-smtp .wp-mail-smtp-filter-date__control{float:left;margin:0 5px 0 0;min-height:30px;background-color:#fff;vertical-align:middle;max-width:210px}@media(max-width: 782px){#wp-mail-smtp .wp-mail-smtp-filter-date__control{flex-grow:1;width:100%;max-width:none;min-height:40px;margin-right:0;margin-bottom:5px}}#wp-mail-smtp .wp-mail-smtp-filter-date__btn{margin:0;vertical-align:top}#wp-mail-smtp .wp-mail-smtp-sign-in-btn{display:inline-flex;align-items:center;background-color:#4285f4;border-radius:2px;box-shadow:0 2px 4px 0 rgba(0,0,0,.25);transition:all 300ms ease-in-out;text-decoration:none;cursor:pointer;color:#fff}#wp-mail-smtp .wp-mail-smtp-sign-in-btn:hover{box-shadow:0 0 3px 3px rgba(66,133,244,.3)}#wp-mail-smtp .wp-mail-smtp-sign-in-btn:active{background:#3367d6}#wp-mail-smtp .wp-mail-smtp-sign-in-btn--disabled{pointer-events:none;background-color:#d4d3d3;box-shadow:none;color:#7f7f7f}#wp-mail-smtp .wp-mail-smtp-sign-in-btn--disabled .wp-mail-smtp-sign-in-icon__border,#wp-mail-smtp .wp-mail-smtp-sign-in-btn--disabled .wp-mail-smtp-sign-in-icon__bg{fill:#d4d3d3}#wp-mail-smtp .wp-mail-smtp-sign-in-btn--disabled .wp-mail-smtp-sign-in-icon__symbol{fill:#7f7f7f}#wp-mail-smtp .wp-mail-smtp-sign-in-btn__icon{overflow:hidden;border-radius:2px}#wp-mail-smtp .wp-mail-smtp-sign-in-btn__icon svg{display:block;margin:-3px}#wp-mail-smtp .wp-mail-smtp-sign-in-btn__text{font-size:14px;font-weight:600;margin:0 10px}.wp-mail-smtp-btn{border:0;border-radius:3px;cursor:pointer;display:inline-block;margin:0;text-decoration:none;text-align:center;vertical-align:middle;white-space:nowrap;text-shadow:none;box-shadow:none;outline:none}.wp-mail-smtp-btn .dashicons{font-size:16px;width:16px;height:16px}.wp-mail-smtp-btn+.wp-mail-smtp-btn{margin-left:16px}.wp-mail-smtp-btn:disabled,.wp-mail-smtp-btn-disabled{opacity:.5;cursor:not-allowed}.wp-mail-smtp-btn-disabled{pointer-events:none}.wp-mail-smtp-btn.wp-mail-smtp-btn-md{font-size:14px;font-weight:500;padding:9px 15px;min-height:36px;line-height:16px;border-width:1px;border-style:solid}.wp-mail-smtp-btn.wp-mail-smtp-btn-lg{font-size:16px;font-weight:600;padding:16px 28px}.wp-mail-smtp-btn.wp-mail-smtp-btn-upgrade,.wp-mail-smtp-btn.wp-mail-smtp-btn-cta{font-size:16px;line-height:20px;font-weight:500;padding:14px 30px}.wp-mail-smtp-btn.wp-mail-smtp-btn-orange{background-color:#e27730;border-color:#e27730;color:#fff}.wp-mail-smtp-btn.wp-mail-smtp-btn-orange:hover,.wp-mail-smtp-btn.wp-mail-smtp-btn-orange:active,.wp-mail-smtp-btn.wp-mail-smtp-btn-orange:focus{background-color:#b85a1b;border-color:#b85a1b;color:#fff}.wp-mail-smtp-btn.wp-mail-smtp-btn-orange:focus{box-shadow:0 0 0 1px #fff,0 0 0 3px #b85a1b}.wp-mail-smtp-btn.wp-mail-smtp-btn-secondary{background-color:#056aab;border-color:#056aab;color:#fff}.wp-mail-smtp-btn.wp-mail-smtp-btn-secondary:hover,.wp-mail-smtp-btn.wp-mail-smtp-btn-secondary:active,.wp-mail-smtp-btn.wp-mail-smtp-btn-secondary:focus{background-color:#045b92;border-color:#045b92;color:#fff}.wp-mail-smtp-btn.wp-mail-smtp-btn-secondary:focus{box-shadow:0 0 0 1px #fff,0 0 0 3px #045b92}.wp-mail-smtp-btn.wp-mail-smtp-btn-red{background-color:#d63638;border-color:#d63638;color:#fff}.wp-mail-smtp-btn.wp-mail-smtp-btn-red:hover,.wp-mail-smtp-btn.wp-mail-smtp-btn-red:active,.wp-mail-smtp-btn.wp-mail-smtp-btn-red:focus{background-color:#b32d2e;border-color:#b32d2e;color:#fff}.wp-mail-smtp-btn.wp-mail-smtp-btn-red:focus{box-shadow:0 0 0 1px #fff,0 0 0 3px #b32d2e}.wp-mail-smtp-btn.wp-mail-smtp-btn-grey{background-color:#f8f8f8;border-color:#999;color:#555}.wp-mail-smtp-btn.wp-mail-smtp-btn-grey:hover,.wp-mail-smtp-btn.wp-mail-smtp-btn-grey:active,.wp-mail-smtp-btn.wp-mail-smtp-btn-grey:focus{background-color:#eee;border-color:#555;color:#444}.wp-mail-smtp-btn.wp-mail-smtp-btn-light-grey{background-color:#f5f5f5;border-color:#ccc;color:#666}.wp-mail-smtp-btn.wp-mail-smtp-btn-light-grey:hover,.wp-mail-smtp-btn.wp-mail-smtp-btn-light-grey:active,.wp-mail-smtp-btn.wp-mail-smtp-btn-light-grey:focus{background-color:#eee;color:#444}.wp-mail-smtp-btn.wp-mail-smtp-btn-blueish{background-color:#738e9e;border-color:#738e9e;color:#fff}.wp-mail-smtp-btn.wp-mail-smtp-btn-blueish:hover,.wp-mail-smtp-btn.wp-mail-smtp-btn-blueish:active,.wp-mail-smtp-btn.wp-mail-smtp-btn-blueish:focus{background-color:#395360;border-color:#395360;color:#fff}.wp-mail-smtp-btn.wp-mail-smtp-btn-blueish:focus{box-shadow:0 0 0 1px #fff,0 0 0 3px #395360}a.wp-mail-smtp-btn.wp-mail-smtp-btn-md{line-height:16px}#wp-mail-smtp-domain-check-details h2{color:#2c3337;font-size:20px;line-height:24px;font-weight:600;margin:28px 0 23px}#wp-mail-smtp-domain-check-details .wp-mail-smtp-domain-check-details-check-list-item{padding:25px 0;border-top:1px solid #e4e4e4;display:flex}#wp-mail-smtp-domain-check-details .wp-mail-smtp-domain-check-details-check-list-item:last-child{padding-bottom:0}#wp-mail-smtp-domain-check-details .wp-mail-smtp-domain-check-details-check-list-item-icon{width:18px;height:16px;margin-right:10px}#wp-mail-smtp-domain-check-details .wp-mail-smtp-domain-check-details-check-list-item-content h3{text-transform:uppercase;font-weight:500;font-size:14px;line-height:17px;color:#2c3337;margin:0 0 4px 0}#wp-mail-smtp-domain-check-details .wp-mail-smtp-domain-check-details-check-list-item-content p{color:#50575e;font-size:14px;line-height:20px;margin:0 0 10px 0}#wp-mail-smtp-domain-check-details .wp-mail-smtp-domain-check-details-check-list-item-content p:last-of-type{margin-bottom:0}.wp-mail-smtp-tab-tools-test .wp-mail-smtp-setting-row.section-heading{margin-bottom:22px}.wp-mail-smtp-tab-tools-test .wp-mail-smtp-test-email-resend{padding-top:22px;margin-top:22px;border-top:1px solid #e4e4e4}.wp-mail-smtp-tab-tools-test .wp-mail-smtp-test-email-resend a{font-size:14px;outline:none;box-shadow:none}.wp-mail-smtp-tab-tools-test #email-test-success{margin-top:30px;text-align:center}.wp-mail-smtp-tab-tools-test #email-test-success svg{display:block;max-width:500px;width:100%;height:auto;margin:0 auto 22px}.wp-mail-smtp-tab-tools-test #email-test-success h2{margin-top:0;margin-bottom:10px;font-weight:500;font-size:24px;line-height:29px;color:#2c3337}.wp-mail-smtp-tab-tools-test #email-test-success p{margin-top:0;font-size:16px;line-height:24px;color:#50575e}.wp-mail-smtp-tab-tools-test #email-test-form .wp-mail-smtp-setting-row.section-heading{margin-bottom:0}.wp-mail-smtp-tab-tools-test #email-test-form .wp-mail-smtp-btn{min-width:95px}.wp-mail-smtp-tab-tools-test #email-test-form .wp-mail-smtp-loading{display:none;margin-bottom:-2px}.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug{margin-top:25px}.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug h2{margin:20px 0 10px;color:#2c3337;font-size:16px;line-height:20px;font-weight:600}.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug p{margin:10px 0;color:#50575e;font-size:14px;line-height:20px}.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug ul{list-style-type:disc}.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug ul,.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug ol{margin:10px 0 10px 15px;color:#50575e;font-size:14px;line-height:20px}.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug ul li,.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug ol li{margin:0 0 8px 0}.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug ul li:last-of-type,.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug ol li:last-of-type{margin:0}.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug ul li ul,.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug ol li ul{list-style-type:disc}.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug .dashicons-star-filled{color:#e27730;width:16px;height:16px;font-size:16px;vertical-align:text-top}.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug .price-off{color:#00a32a;font-weight:600}.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug .error-log-button-container{margin-bottom:22px}.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug .error-log-toggle{float:left;margin-right:10px}.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug .error-log-copy{min-width:122px}.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug .error-log-copy .error-log-copy-back{display:none}.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug .error-log-copy-copied .error-log-copy-front{display:none}.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug .error-log-copy-copied .error-log-copy-back{display:inline}.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug .error-log{padding-top:10px;padding-bottom:10px;display:none}.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug .error-log.error-log-selection{display:block !important;opacity:0;height:0;padding:0;margin:0}.wp-mail-smtp-tab-tools-test #wp-mail-smtp-debug .error-log pre{margin:0}.wp-mail-smtp-tab-tools-action-scheduler .wp-mail-smtp-page-content .wrap,.wp-mail-smtp-tab-tools-action-scheduler .wp-mail-smtp-page-content .subsubsub{margin:0}.wp-mail-smtp-tab-tools-action-scheduler .wp-mail-smtp-page-content>h1{color:#2c3337;font-size:20px;font-weight:600;margin:0 0 15px 0;padding:0}.wp-mail-smtp-tab-tools-action-scheduler .wp-mail-smtp-page-content>p{font-size:14px}.wp-mail-smtp-tab-tools-action-scheduler .wp-mail-smtp-page-content h1.wp-heading-inline,.wp-mail-smtp-tab-tools-action-scheduler .wp-mail-smtp-page-content span.subtitle{display:none}.wp-mail-smtp-tab-tools-action-scheduler .wp-mail-smtp-page-content hr.wp-header-end{visibility:hidden;margin:-2px 0 0}.wp-mail-smtp-admin-page-body .lity{z-index:999999999;padding:20px}.wp-mail-smtp-admin-page-body .lity-close{margin:10px}.wp-mail-smtp-admin-page-body .lity-content{max-width:80vw;max-height:80vh}.wp-mail-smtp-admin-page-body .lity-content img{max-height:80vh !important;max-width:80vw !important}.wp-mail-smtp-debug-event-preview{text-align:left}.wp-mail-smtp-debug-event-preview h4{margin:15px 0;font-size:18px}.wp-mail-smtp-debug-event-preview .wp-mail-smtp-debug-event-preview-subtitle{margin-bottom:30px;text-align:center}.wp-mail-smtp-debug-event-preview .wp-mail-smtp-debug-event-preview-subtitle span{color:#50575e;font-size:16px;line-height:22px}.wp-mail-smtp-debug-event-preview .wp-mail-smtp-debug-event-row{padding:20px 0;border-top:1px solid #ddd;display:flex;justify-content:flex-start;align-items:flex-start;font-size:16px;line-height:22px}.wp-mail-smtp-debug-event-preview .wp-mail-smtp-debug-event-row .debug-event-label{width:60px;margin-right:30px;font-weight:500}.wp-mail-smtp-debug-event-preview .wp-mail-smtp-debug-event-row .debug-event-value{width:calc(100% - 90px)}.wp-mail-smtp-debug-event-preview .wp-mail-smtp-debug-event-row .debug-event-initiator{display:inline-block;margin-bottom:5px}.wp-mail-smtp-debug-event-preview .wp-mail-smtp-debug-event-row .debug-event-code{color:#50575e}.wp-mail-smtp-debug-event-preview .wp-mail-smtp-debug-event-row:last-child{border-bottom:1px solid #ddd}.wp-mail-smtp-debug-event-preview .wp-mail-smtp-debug-event-preview-content>div{word-break:break-word}[class^=wp-mail-smtp-dashicons]{display:inline-block;width:20px;height:20px}.wp-mail-smtp-dashicons-yes-alt-green{background-image:url("../images/icons/dashicons/dashicons-yes-alt-green.svg")}.wp-mail-smtp-dashicons-pdf-gray{background-image:url("../images/icons/dashicons/dashicons-pdf-grey.svg")}@keyframes wp-mail-smtp-spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}} \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/css/smtp-smart-routing.min.css b/wp-content/plugins/wp-mail-smtp/assets/css/smtp-smart-routing.min.css new file mode 100755 index 00000000..7e256a57 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/css/smtp-smart-routing.min.css @@ -0,0 +1 @@ +#wp-mail-smtp .wp-mail-smtp-smart-routing-header{padding-bottom:0 !important;border-bottom:none !important}#wp-mail-smtp .wp-mail-smtp-smart-routing-header__heading{display:flex;align-items:center}#wp-mail-smtp .wp-mail-smtp-smart-routing-header__heading>a{margin-left:15px;font-weight:600;font-size:14px;line-height:22px}#wp-mail-smtp .wp-mail-smtp-smart-routing-notice-top{max-width:1000px;margin:10px 0 0 !important;border:1px solid #bbb}#wp-mail-smtp .wp-mail-smtp-smart-routing-notice-top--no-connections~.wp-mail-smtp-setting-row,#wp-mail-smtp .wp-mail-smtp-smart-routing-notice-top--no-connections~.wp-mail-smtp-submit{opacity:.5;pointer-events:none}#wp-mail-smtp .wp-mail-smtp-smart-routing-toggle .wp-mail-smtp-toggle__label{font-weight:500;font-size:14px;text-transform:capitalize}#wp-mail-smtp .wp-mail-smtp-smart-routing-routes{max-width:1000px;margin-bottom:30px}#wp-mail-smtp .wp-mail-smtp-smart-routing-route{background:#fff;box-shadow:0px 2px 4px rgba(0,0,0,.07);border-radius:6px}#wp-mail-smtp .wp-mail-smtp-smart-routing-route+.wp-mail-smtp-smart-routing-route{margin-top:30px}#wp-mail-smtp .wp-mail-smtp-smart-routing-route__header{display:flex;align-items:center;padding:20px;border-bottom:1px solid #f1f1f1}@media(max-width: 600px){#wp-mail-smtp .wp-mail-smtp-smart-routing-route__header{flex-direction:column;align-items:flex-start}}#wp-mail-smtp .wp-mail-smtp-smart-routing-route__header>span{margin-right:10px;font-size:14px;line-height:17px;font-style:italic;color:#646970}@media(max-width: 600px){#wp-mail-smtp .wp-mail-smtp-smart-routing-route__header>span{margin-right:0;margin-top:10px}}#wp-mail-smtp .wp-mail-smtp-smart-routing-route__header>select{margin-right:10px !important}@media(max-width: 600px){#wp-mail-smtp .wp-mail-smtp-smart-routing-route__header>select{margin-right:0;margin-top:10px !important}}#wp-mail-smtp .wp-mail-smtp-smart-routing-route__connection{max-width:273px;width:100%}#wp-mail-smtp .wp-mail-smtp-smart-routing-route__connection--invalid{border-color:#d63638 !important}#wp-mail-smtp .wp-mail-smtp-smart-routing-route__actions{display:flex;align-items:center;margin-left:auto}@media(max-width: 600px){#wp-mail-smtp .wp-mail-smtp-smart-routing-route__actions{order:-1}}#wp-mail-smtp .wp-mail-smtp-smart-routing-route__order{margin-right:23px;white-space:nowrap}#wp-mail-smtp .wp-mail-smtp-smart-routing-route__order-btn{background-color:rgba(0,0,0,0);border:none;padding:0;vertical-align:middle;cursor:pointer}#wp-mail-smtp .wp-mail-smtp-smart-routing-route__order-btn--down{margin-left:13px;transform:rotate(-180deg)}#wp-mail-smtp .wp-mail-smtp-smart-routing-route__order-btn img{display:block}#wp-mail-smtp .wp-mail-smtp-smart-routing-route:first-child .wp-mail-smtp-smart-routing-route__order-btn--up,#wp-mail-smtp .wp-mail-smtp-smart-routing-route:last-child .wp-mail-smtp-smart-routing-route__order-btn--down{opacity:.25;cursor:not-allowed;pointer-events:none}#wp-mail-smtp .wp-mail-smtp-smart-routing-route__delete{background-color:rgba(0,0,0,0);border:none;color:#999;padding:0;vertical-align:middle;cursor:pointer}#wp-mail-smtp .wp-mail-smtp-smart-routing-route__delete:hover:not(:disabled){color:#d63638}#wp-mail-smtp .wp-mail-smtp-smart-routing-route__delete:disabled{opacity:.25;cursor:not-allowed}#wp-mail-smtp .wp-mail-smtp-smart-routing-route__main{padding:20px}#wp-mail-smtp .wp-mail-smtp-smart-routing-route__notice{margin-top:0 !important;margin-bottom:20px !important;border:1px solid #bbb}#wp-mail-smtp .wp-mail-smtp-smart-routing-route__notice p{margin:6px 0 !important;font-size:13px !important}#wp-mail-smtp .wp-mail-smtp-smart-routing-route .wp-mail-smtp-btn-grey{font-weight:500}#wp-mail-smtp .wp-mail-smtp-smart-routing-routes-note{display:flex;align-items:center;margin-bottom:5px;font-size:14px;line-height:20px;color:#646970}#wp-mail-smtp .wp-mail-smtp-smart-routing-routes-note img{margin-right:10px}#wp-mail-smtp .wp-mail-smtp-smart-routing-routes-note p{margin:0 !important}#wp-mail-smtp .wp-mail-smtp-smart-routing-routes-note a{color:inherit}#wp-mail-smtp .wp-mail-smtp-smart-routing-routes-note a:hover,#wp-mail-smtp .wp-mail-smtp-smart-routing-routes-note a:active{color:#555} \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/css/vendor/flatpickr.min.css b/wp-content/plugins/wp-mail-smtp/assets/css/vendor/flatpickr.min.css new file mode 100755 index 00000000..8920a67e --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/css/vendor/flatpickr.min.css @@ -0,0 +1,13 @@ +.flatpickr-calendar{background:transparent;opacity:0;display:none;text-align:center;visibility:hidden;padding:0;-webkit-animation:none;animation:none;direction:ltr;border:0;font-size:14px;line-height:24px;border-radius:5px;position:absolute;width:307.875px;-webkit-box-sizing:border-box;box-sizing:border-box;-ms-touch-action:manipulation;touch-action:manipulation;background:#fff;-webkit-box-shadow:1px 0 0 #e6e6e6,-1px 0 0 #e6e6e6,0 1px 0 #e6e6e6,0 -1px 0 #e6e6e6,0 3px 13px rgba(0,0,0,0.08);box-shadow:1px 0 0 #e6e6e6,-1px 0 0 #e6e6e6,0 1px 0 #e6e6e6,0 -1px 0 #e6e6e6,0 3px 13px rgba(0,0,0,0.08)}.flatpickr-calendar.open,.flatpickr-calendar.inline{opacity:1;max-height:640px;visibility:visible}.flatpickr-calendar.open{display:inline-block;z-index:99999}.flatpickr-calendar.animate.open{-webkit-animation:fpFadeInDown 300ms cubic-bezier(.23,1,.32,1);animation:fpFadeInDown 300ms cubic-bezier(.23,1,.32,1)}.flatpickr-calendar.inline{display:block;position:relative;top:2px}.flatpickr-calendar.static{position:absolute;top:calc(100% + 2px)}.flatpickr-calendar.static.open{z-index:999;display:block}.flatpickr-calendar.multiMonth .flatpickr-days .dayContainer:nth-child(n+1) .flatpickr-day.inRange:nth-child(7n+7){-webkit-box-shadow:none !important;box-shadow:none !important}.flatpickr-calendar.multiMonth .flatpickr-days .dayContainer:nth-child(n+2) .flatpickr-day.inRange:nth-child(7n+1){-webkit-box-shadow:-2px 0 0 #e6e6e6,5px 0 0 #e6e6e6;box-shadow:-2px 0 0 #e6e6e6,5px 0 0 #e6e6e6}.flatpickr-calendar .hasWeeks .dayContainer,.flatpickr-calendar .hasTime .dayContainer{border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.flatpickr-calendar .hasWeeks .dayContainer{border-left:0}.flatpickr-calendar.hasTime .flatpickr-time{height:40px;border-top:1px solid #e6e6e6}.flatpickr-calendar.noCalendar.hasTime .flatpickr-time{height:auto}.flatpickr-calendar:before,.flatpickr-calendar:after{position:absolute;display:block;pointer-events:none;border:solid transparent;content:'';height:0;width:0;left:22px}.flatpickr-calendar.rightMost:before,.flatpickr-calendar.arrowRight:before,.flatpickr-calendar.rightMost:after,.flatpickr-calendar.arrowRight:after{left:auto;right:22px}.flatpickr-calendar.arrowCenter:before,.flatpickr-calendar.arrowCenter:after{left:50%;right:50%}.flatpickr-calendar:before{border-width:5px;margin:0 -5px}.flatpickr-calendar:after{border-width:4px;margin:0 -4px}.flatpickr-calendar.arrowTop:before,.flatpickr-calendar.arrowTop:after{bottom:100%}.flatpickr-calendar.arrowTop:before{border-bottom-color:#e6e6e6}.flatpickr-calendar.arrowTop:after{border-bottom-color:#fff}.flatpickr-calendar.arrowBottom:before,.flatpickr-calendar.arrowBottom:after{top:100%}.flatpickr-calendar.arrowBottom:before{border-top-color:#e6e6e6}.flatpickr-calendar.arrowBottom:after{border-top-color:#fff}.flatpickr-calendar:focus{outline:0}.flatpickr-wrapper{position:relative;display:inline-block}.flatpickr-months{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.flatpickr-months .flatpickr-month{background:transparent;color:rgba(0,0,0,0.9);fill:rgba(0,0,0,0.9);height:34px;line-height:1;text-align:center;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;overflow:hidden;-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1}.flatpickr-months .flatpickr-prev-month,.flatpickr-months .flatpickr-next-month{text-decoration:none;cursor:pointer;position:absolute;top:0;height:34px;padding:10px;z-index:3;color:rgba(0,0,0,0.9);fill:rgba(0,0,0,0.9)}.flatpickr-months .flatpickr-prev-month.flatpickr-disabled,.flatpickr-months .flatpickr-next-month.flatpickr-disabled{display:none}.flatpickr-months .flatpickr-prev-month i,.flatpickr-months .flatpickr-next-month i{position:relative}.flatpickr-months .flatpickr-prev-month.flatpickr-prev-month,.flatpickr-months .flatpickr-next-month.flatpickr-prev-month{/* + /*rtl:begin:ignore*/left:0/* + /*rtl:end:ignore*/}/* + /*rtl:begin:ignore*/ +/* + /*rtl:end:ignore*/ +.flatpickr-months .flatpickr-prev-month.flatpickr-next-month,.flatpickr-months .flatpickr-next-month.flatpickr-next-month{/* + /*rtl:begin:ignore*/right:0/* + /*rtl:end:ignore*/}/* + /*rtl:begin:ignore*/ +/* + /*rtl:end:ignore*/ +.flatpickr-months .flatpickr-prev-month:hover,.flatpickr-months .flatpickr-next-month:hover{color:#959ea9}.flatpickr-months .flatpickr-prev-month:hover svg,.flatpickr-months .flatpickr-next-month:hover svg{fill:#f64747}.flatpickr-months .flatpickr-prev-month svg,.flatpickr-months .flatpickr-next-month svg{width:14px;height:14px}.flatpickr-months .flatpickr-prev-month svg path,.flatpickr-months .flatpickr-next-month svg path{-webkit-transition:fill .1s;transition:fill .1s;fill:inherit}.numInputWrapper{position:relative;height:auto}.numInputWrapper input,.numInputWrapper span{display:inline-block}.numInputWrapper input{width:100%}.numInputWrapper input::-ms-clear{display:none}.numInputWrapper input::-webkit-outer-spin-button,.numInputWrapper input::-webkit-inner-spin-button{margin:0;-webkit-appearance:none}.numInputWrapper span{position:absolute;right:0;width:14px;padding:0 4px 0 2px;height:50%;line-height:50%;opacity:0;cursor:pointer;border:1px solid rgba(57,57,57,0.15);-webkit-box-sizing:border-box;box-sizing:border-box}.numInputWrapper span:hover{background:rgba(0,0,0,0.1)}.numInputWrapper span:active{background:rgba(0,0,0,0.2)}.numInputWrapper span:after{display:block;content:"";position:absolute}.numInputWrapper span.arrowUp{top:0;border-bottom:0}.numInputWrapper span.arrowUp:after{border-left:4px solid transparent;border-right:4px solid transparent;border-bottom:4px solid rgba(57,57,57,0.6);top:26%}.numInputWrapper span.arrowDown{top:50%}.numInputWrapper span.arrowDown:after{border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid rgba(57,57,57,0.6);top:40%}.numInputWrapper span svg{width:inherit;height:auto}.numInputWrapper span svg path{fill:rgba(0,0,0,0.5)}.numInputWrapper:hover{background:rgba(0,0,0,0.05)}.numInputWrapper:hover span{opacity:1}.flatpickr-current-month{font-size:135%;line-height:inherit;font-weight:300;color:inherit;position:absolute;width:75%;left:12.5%;padding:7.48px 0 0 0;line-height:1;height:34px;display:inline-block;text-align:center;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.flatpickr-current-month span.cur-month{font-family:inherit;font-weight:700;color:inherit;display:inline-block;margin-left:.5ch;padding:0}.flatpickr-current-month span.cur-month:hover{background:rgba(0,0,0,0.05)}.flatpickr-current-month .numInputWrapper{width:6ch;width:7ch\0;display:inline-block}.flatpickr-current-month .numInputWrapper span.arrowUp:after{border-bottom-color:rgba(0,0,0,0.9)}.flatpickr-current-month .numInputWrapper span.arrowDown:after{border-top-color:rgba(0,0,0,0.9)}.flatpickr-current-month input.cur-year{background:transparent;-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;cursor:text;padding:0 0 0 .5ch;margin:0;display:inline-block;font-size:inherit;font-family:inherit;font-weight:300;line-height:inherit;height:auto;border:0;border-radius:0;vertical-align:initial;-webkit-appearance:textfield;-moz-appearance:textfield;appearance:textfield}.flatpickr-current-month input.cur-year:focus{outline:0}.flatpickr-current-month input.cur-year[disabled],.flatpickr-current-month input.cur-year[disabled]:hover{font-size:100%;color:rgba(0,0,0,0.5);background:transparent;pointer-events:none}.flatpickr-current-month .flatpickr-monthDropdown-months{appearance:menulist;background:transparent;border:none;border-radius:0;box-sizing:border-box;color:inherit;cursor:pointer;font-size:inherit;font-family:inherit;font-weight:300;height:auto;line-height:inherit;margin:-1px 0 0 0;outline:none;padding:0 0 0 .5ch;position:relative;vertical-align:initial;-webkit-box-sizing:border-box;-webkit-appearance:menulist;-moz-appearance:menulist;width:auto}.flatpickr-current-month .flatpickr-monthDropdown-months:focus,.flatpickr-current-month .flatpickr-monthDropdown-months:active{outline:none}.flatpickr-current-month .flatpickr-monthDropdown-months:hover{background:rgba(0,0,0,0.05)}.flatpickr-current-month .flatpickr-monthDropdown-months .flatpickr-monthDropdown-month{background-color:transparent;outline:none;padding:0}.flatpickr-weekdays{background:transparent;text-align:center;overflow:hidden;width:100%;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;height:28px}.flatpickr-weekdays .flatpickr-weekdaycontainer{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1}span.flatpickr-weekday{cursor:default;font-size:90%;background:transparent;color:rgba(0,0,0,0.54);line-height:1;margin:0;text-align:center;display:block;-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1;font-weight:bolder}.dayContainer,.flatpickr-weeks{padding:1px 0 0 0}.flatpickr-days{position:relative;overflow:hidden;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:start;-webkit-align-items:flex-start;-ms-flex-align:start;align-items:flex-start;width:307.875px}.flatpickr-days:focus{outline:0}.dayContainer{padding:0;outline:0;text-align:left;width:307.875px;min-width:307.875px;max-width:307.875px;-webkit-box-sizing:border-box;box-sizing:border-box;display:inline-block;display:-ms-flexbox;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-wrap:wrap;-ms-flex-pack:justify;-webkit-justify-content:space-around;justify-content:space-around;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}.dayContainer + .dayContainer{-webkit-box-shadow:-1px 0 0 #e6e6e6;box-shadow:-1px 0 0 #e6e6e6}.flatpickr-day{background:none;border:1px solid transparent;border-radius:150px;-webkit-box-sizing:border-box;box-sizing:border-box;color:#393939;cursor:pointer;font-weight:400;width:14.2857143%;-webkit-flex-basis:14.2857143%;-ms-flex-preferred-size:14.2857143%;flex-basis:14.2857143%;max-width:39px;height:39px;line-height:39px;margin:0;display:inline-block;position:relative;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center}.flatpickr-day.inRange,.flatpickr-day.prevMonthDay.inRange,.flatpickr-day.nextMonthDay.inRange,.flatpickr-day.today.inRange,.flatpickr-day.prevMonthDay.today.inRange,.flatpickr-day.nextMonthDay.today.inRange,.flatpickr-day:hover,.flatpickr-day.prevMonthDay:hover,.flatpickr-day.nextMonthDay:hover,.flatpickr-day:focus,.flatpickr-day.prevMonthDay:focus,.flatpickr-day.nextMonthDay:focus{cursor:pointer;outline:0;background:#e6e6e6;border-color:#e6e6e6}.flatpickr-day.today{border-color:#959ea9}.flatpickr-day.today:hover,.flatpickr-day.today:focus{border-color:#959ea9;background:#959ea9;color:#fff}.flatpickr-day.selected,.flatpickr-day.startRange,.flatpickr-day.endRange,.flatpickr-day.selected.inRange,.flatpickr-day.startRange.inRange,.flatpickr-day.endRange.inRange,.flatpickr-day.selected:focus,.flatpickr-day.startRange:focus,.flatpickr-day.endRange:focus,.flatpickr-day.selected:hover,.flatpickr-day.startRange:hover,.flatpickr-day.endRange:hover,.flatpickr-day.selected.prevMonthDay,.flatpickr-day.startRange.prevMonthDay,.flatpickr-day.endRange.prevMonthDay,.flatpickr-day.selected.nextMonthDay,.flatpickr-day.startRange.nextMonthDay,.flatpickr-day.endRange.nextMonthDay{background:#569ff7;-webkit-box-shadow:none;box-shadow:none;color:#fff;border-color:#569ff7}.flatpickr-day.selected.startRange,.flatpickr-day.startRange.startRange,.flatpickr-day.endRange.startRange{border-radius:50px 0 0 50px}.flatpickr-day.selected.endRange,.flatpickr-day.startRange.endRange,.flatpickr-day.endRange.endRange{border-radius:0 50px 50px 0}.flatpickr-day.selected.startRange + .endRange:not(:nth-child(7n+1)),.flatpickr-day.startRange.startRange + .endRange:not(:nth-child(7n+1)),.flatpickr-day.endRange.startRange + .endRange:not(:nth-child(7n+1)){-webkit-box-shadow:-10px 0 0 #569ff7;box-shadow:-10px 0 0 #569ff7}.flatpickr-day.selected.startRange.endRange,.flatpickr-day.startRange.startRange.endRange,.flatpickr-day.endRange.startRange.endRange{border-radius:50px}.flatpickr-day.inRange{border-radius:0;-webkit-box-shadow:-5px 0 0 #e6e6e6,5px 0 0 #e6e6e6;box-shadow:-5px 0 0 #e6e6e6,5px 0 0 #e6e6e6}.flatpickr-day.flatpickr-disabled,.flatpickr-day.flatpickr-disabled:hover,.flatpickr-day.prevMonthDay,.flatpickr-day.nextMonthDay,.flatpickr-day.notAllowed,.flatpickr-day.notAllowed.prevMonthDay,.flatpickr-day.notAllowed.nextMonthDay{color:rgba(57,57,57,0.3);background:transparent;border-color:transparent;cursor:default}.flatpickr-day.flatpickr-disabled,.flatpickr-day.flatpickr-disabled:hover{cursor:not-allowed;color:rgba(57,57,57,0.1)}.flatpickr-day.week.selected{border-radius:0;-webkit-box-shadow:-5px 0 0 #569ff7,5px 0 0 #569ff7;box-shadow:-5px 0 0 #569ff7,5px 0 0 #569ff7}.flatpickr-day.hidden{visibility:hidden}.rangeMode .flatpickr-day{margin-top:1px}.flatpickr-weekwrapper{float:left}.flatpickr-weekwrapper .flatpickr-weeks{padding:0 12px;-webkit-box-shadow:1px 0 0 #e6e6e6;box-shadow:1px 0 0 #e6e6e6}.flatpickr-weekwrapper .flatpickr-weekday{float:none;width:100%;line-height:28px}.flatpickr-weekwrapper span.flatpickr-day,.flatpickr-weekwrapper span.flatpickr-day:hover{display:block;width:100%;max-width:none;color:rgba(57,57,57,0.3);background:transparent;cursor:default;border:none}.flatpickr-innerContainer{display:block;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden}.flatpickr-rContainer{display:inline-block;padding:0;-webkit-box-sizing:border-box;box-sizing:border-box}.flatpickr-time{text-align:center;outline:0;display:block;height:0;line-height:40px;max-height:40px;-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.flatpickr-time:after{content:"";display:table;clear:both}.flatpickr-time .numInputWrapper{-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1;width:40%;height:40px;float:left}.flatpickr-time .numInputWrapper span.arrowUp:after{border-bottom-color:#393939}.flatpickr-time .numInputWrapper span.arrowDown:after{border-top-color:#393939}.flatpickr-time.hasSeconds .numInputWrapper{width:26%}.flatpickr-time.time24hr .numInputWrapper{width:49%}.flatpickr-time input{background:transparent;-webkit-box-shadow:none;box-shadow:none;border:0;border-radius:0;text-align:center;margin:0;padding:0;height:inherit;line-height:inherit;color:#393939;font-size:14px;position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:textfield;-moz-appearance:textfield;appearance:textfield}.flatpickr-time input.flatpickr-hour{font-weight:bold}.flatpickr-time input.flatpickr-minute,.flatpickr-time input.flatpickr-second{font-weight:400}.flatpickr-time input:focus{outline:0;border:0}.flatpickr-time .flatpickr-time-separator,.flatpickr-time .flatpickr-am-pm{height:inherit;float:left;line-height:inherit;color:#393939;font-weight:bold;width:2%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-align-self:center;-ms-flex-item-align:center;align-self:center}.flatpickr-time .flatpickr-am-pm{outline:0;width:18%;cursor:pointer;text-align:center;font-weight:400}.flatpickr-time input:hover,.flatpickr-time .flatpickr-am-pm:hover,.flatpickr-time input:focus,.flatpickr-time .flatpickr-am-pm:focus{background:#eee}.flatpickr-input[readonly]{cursor:pointer}@-webkit-keyframes fpFadeInDown{from{opacity:0;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}to{opacity:1;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes fpFadeInDown{from{opacity:0;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}to{opacity:1;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}} diff --git a/wp-content/plugins/wp-mail-smtp/assets/css/vendor/jquery-confirm.min.css b/wp-content/plugins/wp-mail-smtp/assets/css/vendor/jquery-confirm.min.css new file mode 100755 index 00000000..b66d2054 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/css/vendor/jquery-confirm.min.css @@ -0,0 +1,9 @@ +/*! + * jquery-confirm v3.3.4 (http://craftpip.github.io/jquery-confirm/) + * Author: boniface pereira + * Website: www.craftpip.com + * Contact: hey@craftpip.com + * + * Copyright 2013-2019 jquery-confirm + * Licensed under MIT (https://github.com/craftpip/jquery-confirm/blob/master/LICENSE) + */@-webkit-keyframes jconfirm-spin{from{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes jconfirm-spin{from{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}body[class*=jconfirm-no-scroll-]{overflow:hidden!important}.jconfirm{position:fixed;top:0;left:0;right:0;bottom:0;z-index:99999999;font-family:inherit;overflow:hidden}.jconfirm .jconfirm-bg{position:fixed;top:0;left:0;right:0;bottom:0;-webkit-transition:opacity .4s;transition:opacity .4s}.jconfirm .jconfirm-bg.jconfirm-bg-h{opacity:0!important}.jconfirm .jconfirm-scrollpane{-webkit-perspective:500px;perspective:500px;-webkit-perspective-origin:center;perspective-origin:center;display:table;width:100%;height:100%}.jconfirm .jconfirm-row{display:table-row;width:100%}.jconfirm .jconfirm-cell{display:table-cell;vertical-align:middle}.jconfirm .jconfirm-holder{max-height:100%;padding:50px 0}.jconfirm .jconfirm-box-container{-webkit-transition:-webkit-transform;transition:-webkit-transform;transition:transform;transition:transform,-webkit-transform}.jconfirm .jconfirm-box-container.jconfirm-no-transition{-webkit-transition:none!important;transition:none!important}.jconfirm .jconfirm-box{background:white;border-radius:4px;position:relative;outline:0;padding:15px 15px 0;overflow:hidden;margin-left:auto;margin-right:auto}@-webkit-keyframes type-blue{1%,100%{border-color:#3498db}50%{border-color:#5faee3}}@keyframes type-blue{1%,100%{border-color:#3498db}50%{border-color:#5faee3}}@-webkit-keyframes type-green{1%,100%{border-color:#2ecc71}50%{border-color:#54d98c}}@keyframes type-green{1%,100%{border-color:#2ecc71}50%{border-color:#54d98c}}@-webkit-keyframes type-red{1%,100%{border-color:#e74c3c}50%{border-color:#ed7669}}@keyframes type-red{1%,100%{border-color:#e74c3c}50%{border-color:#ed7669}}@-webkit-keyframes type-orange{1%,100%{border-color:#f1c40f}50%{border-color:#f4d03f}}@keyframes type-orange{1%,100%{border-color:#f1c40f}50%{border-color:#f4d03f}}@-webkit-keyframes type-purple{1%,100%{border-color:#9b59b6}50%{border-color:#b07cc6}}@keyframes type-purple{1%,100%{border-color:#9b59b6}50%{border-color:#b07cc6}}@-webkit-keyframes type-dark{1%,100%{border-color:#34495e}50%{border-color:#46627f}}@keyframes type-dark{1%,100%{border-color:#34495e}50%{border-color:#46627f}}.jconfirm .jconfirm-box.jconfirm-type-animated{-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.jconfirm .jconfirm-box.jconfirm-type-blue{border-top:solid 7px #3498db;-webkit-animation-name:type-blue;animation-name:type-blue}.jconfirm .jconfirm-box.jconfirm-type-green{border-top:solid 7px #2ecc71;-webkit-animation-name:type-green;animation-name:type-green}.jconfirm .jconfirm-box.jconfirm-type-red{border-top:solid 7px #e74c3c;-webkit-animation-name:type-red;animation-name:type-red}.jconfirm .jconfirm-box.jconfirm-type-orange{border-top:solid 7px #f1c40f;-webkit-animation-name:type-orange;animation-name:type-orange}.jconfirm .jconfirm-box.jconfirm-type-purple{border-top:solid 7px #9b59b6;-webkit-animation-name:type-purple;animation-name:type-purple}.jconfirm .jconfirm-box.jconfirm-type-dark{border-top:solid 7px #34495e;-webkit-animation-name:type-dark;animation-name:type-dark}.jconfirm .jconfirm-box.loading{height:120px}.jconfirm .jconfirm-box.loading:before{content:'';position:absolute;left:0;background:white;right:0;top:0;bottom:0;border-radius:10px;z-index:1}.jconfirm .jconfirm-box.loading:after{opacity:.6;content:'';height:30px;width:30px;border:solid 3px transparent;position:absolute;left:50%;margin-left:-15px;border-radius:50%;-webkit-animation:jconfirm-spin 1s infinite linear;animation:jconfirm-spin 1s infinite linear;border-bottom-color:dodgerblue;top:50%;margin-top:-15px;z-index:2}.jconfirm .jconfirm-box div.jconfirm-closeIcon{height:20px;width:20px;position:absolute;top:10px;right:10px;cursor:pointer;opacity:.6;text-align:center;font-size:27px!important;line-height:14px!important;display:none;z-index:1}.jconfirm .jconfirm-box div.jconfirm-closeIcon:empty{display:none}.jconfirm .jconfirm-box div.jconfirm-closeIcon .fa{font-size:16px}.jconfirm .jconfirm-box div.jconfirm-closeIcon .glyphicon{font-size:16px}.jconfirm .jconfirm-box div.jconfirm-closeIcon .zmdi{font-size:16px}.jconfirm .jconfirm-box div.jconfirm-closeIcon:hover{opacity:1}.jconfirm .jconfirm-box div.jconfirm-title-c{display:block;font-size:22px;line-height:20px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default;padding-bottom:15px}.jconfirm .jconfirm-box div.jconfirm-title-c.jconfirm-hand{cursor:move}.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c{font-size:inherit;display:inline-block;vertical-align:middle}.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c i{vertical-align:middle}.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c:empty{display:none}.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-title{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-size:inherit;font-family:inherit;display:inline-block;vertical-align:middle}.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-title:empty{display:none}.jconfirm .jconfirm-box div.jconfirm-content-pane{margin-bottom:15px;height:auto;-webkit-transition:height .4s ease-in;transition:height .4s ease-in;display:inline-block;width:100%;position:relative;overflow-x:hidden;overflow-y:auto}.jconfirm .jconfirm-box div.jconfirm-content-pane.no-scroll{overflow-y:hidden}.jconfirm .jconfirm-box div.jconfirm-content-pane::-webkit-scrollbar{width:3px}.jconfirm .jconfirm-box div.jconfirm-content-pane::-webkit-scrollbar-track{background:rgba(0,0,0,0.1)}.jconfirm .jconfirm-box div.jconfirm-content-pane::-webkit-scrollbar-thumb{background:#666;border-radius:3px}.jconfirm .jconfirm-box div.jconfirm-content-pane .jconfirm-content{overflow:auto}.jconfirm .jconfirm-box div.jconfirm-content-pane .jconfirm-content img{max-width:100%;height:auto}.jconfirm .jconfirm-box div.jconfirm-content-pane .jconfirm-content:empty{display:none}.jconfirm .jconfirm-box .jconfirm-buttons{padding-bottom:11px}.jconfirm .jconfirm-box .jconfirm-buttons>button{margin-bottom:4px;margin-left:2px;margin-right:2px}.jconfirm .jconfirm-box .jconfirm-buttons button{display:inline-block;padding:6px 12px;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:4px;min-height:1em;-webkit-transition:opacity .1s ease,background-color .1s ease,color .1s ease,background .1s ease,-webkit-box-shadow .1s ease;transition:opacity .1s ease,background-color .1s ease,color .1s ease,background .1s ease,-webkit-box-shadow .1s ease;transition:opacity .1s ease,background-color .1s ease,color .1s ease,box-shadow .1s ease,background .1s ease;transition:opacity .1s ease,background-color .1s ease,color .1s ease,box-shadow .1s ease,background .1s ease,-webkit-box-shadow .1s ease;-webkit-tap-highlight-color:transparent;border:0;background-image:none}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-blue{background-color:#3498db;color:#FFF;text-shadow:none;-webkit-transition:background .2s;transition:background .2s}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-blue:hover{background-color:#2980b9;color:#FFF}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-green{background-color:#2ecc71;color:#FFF;text-shadow:none;-webkit-transition:background .2s;transition:background .2s}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-green:hover{background-color:#27ae60;color:#FFF}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-red{background-color:#e74c3c;color:#FFF;text-shadow:none;-webkit-transition:background .2s;transition:background .2s}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-red:hover{background-color:#c0392b;color:#FFF}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-orange{background-color:#f1c40f;color:#FFF;text-shadow:none;-webkit-transition:background .2s;transition:background .2s}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-orange:hover{background-color:#f39c12;color:#FFF}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-default{background-color:#ecf0f1;color:#000;text-shadow:none;-webkit-transition:background .2s;transition:background .2s}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-default:hover{background-color:#bdc3c7;color:#000}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-purple{background-color:#9b59b6;color:#FFF;text-shadow:none;-webkit-transition:background .2s;transition:background .2s}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-purple:hover{background-color:#8e44ad;color:#FFF}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-dark{background-color:#34495e;color:#FFF;text-shadow:none;-webkit-transition:background .2s;transition:background .2s}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-dark:hover{background-color:#2c3e50;color:#FFF}.jconfirm .jconfirm-box.jconfirm-type-red .jconfirm-title-c .jconfirm-icon-c{color:#e74c3c!important}.jconfirm .jconfirm-box.jconfirm-type-blue .jconfirm-title-c .jconfirm-icon-c{color:#3498db!important}.jconfirm .jconfirm-box.jconfirm-type-green .jconfirm-title-c .jconfirm-icon-c{color:#2ecc71!important}.jconfirm .jconfirm-box.jconfirm-type-purple .jconfirm-title-c .jconfirm-icon-c{color:#9b59b6!important}.jconfirm .jconfirm-box.jconfirm-type-orange .jconfirm-title-c .jconfirm-icon-c{color:#f1c40f!important}.jconfirm .jconfirm-box.jconfirm-type-dark .jconfirm-title-c .jconfirm-icon-c{color:#34495e!important}.jconfirm .jconfirm-clear{clear:both}.jconfirm.jconfirm-rtl{direction:rtl}.jconfirm.jconfirm-rtl div.jconfirm-closeIcon{left:5px;right:auto}.jconfirm.jconfirm-white .jconfirm-bg,.jconfirm.jconfirm-light .jconfirm-bg{background-color:#444;opacity:.2}.jconfirm.jconfirm-white .jconfirm-box,.jconfirm.jconfirm-light .jconfirm-box{-webkit-box-shadow:0 2px 6px rgba(0,0,0,0.2);box-shadow:0 2px 6px rgba(0,0,0,0.2);border-radius:5px}.jconfirm.jconfirm-white .jconfirm-box .jconfirm-title-c .jconfirm-icon-c,.jconfirm.jconfirm-light .jconfirm-box .jconfirm-title-c .jconfirm-icon-c{margin-right:8px;margin-left:0}.jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons,.jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons{float:right}.jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons button,.jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons button{text-transform:uppercase;font-size:14px;font-weight:bold;text-shadow:none}.jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons button.btn-default,.jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons button.btn-default{-webkit-box-shadow:none;box-shadow:none;color:#333}.jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons button.btn-default:hover,.jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons button.btn-default:hover{background:#ddd}.jconfirm.jconfirm-white.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c,.jconfirm.jconfirm-light.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c{margin-left:8px;margin-right:0}.jconfirm.jconfirm-black .jconfirm-bg,.jconfirm.jconfirm-dark .jconfirm-bg{background-color:darkslategray;opacity:.4}.jconfirm.jconfirm-black .jconfirm-box,.jconfirm.jconfirm-dark .jconfirm-box{-webkit-box-shadow:0 2px 6px rgba(0,0,0,0.2);box-shadow:0 2px 6px rgba(0,0,0,0.2);background:#444;border-radius:5px;color:white}.jconfirm.jconfirm-black .jconfirm-box .jconfirm-title-c .jconfirm-icon-c,.jconfirm.jconfirm-dark .jconfirm-box .jconfirm-title-c .jconfirm-icon-c{margin-right:8px;margin-left:0}.jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons,.jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons{float:right}.jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons button,.jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons button{border:0;background-image:none;text-transform:uppercase;font-size:14px;font-weight:bold;text-shadow:none;-webkit-transition:background .1s;transition:background .1s;color:white}.jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons button.btn-default,.jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons button.btn-default{-webkit-box-shadow:none;box-shadow:none;color:#fff;background:0}.jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons button.btn-default:hover,.jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons button.btn-default:hover{background:#666}.jconfirm.jconfirm-black.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c,.jconfirm.jconfirm-dark.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c{margin-left:8px;margin-right:0}.jconfirm .jconfirm-box.hilight.jconfirm-hilight-shake{-webkit-animation:shake .82s cubic-bezier(0.36,0.07,0.19,0.97) both;animation:shake .82s cubic-bezier(0.36,0.07,0.19,0.97) both;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.jconfirm .jconfirm-box.hilight.jconfirm-hilight-glow{-webkit-animation:glow .82s cubic-bezier(0.36,0.07,0.19,0.97) both;animation:glow .82s cubic-bezier(0.36,0.07,0.19,0.97) both;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}@-webkit-keyframes shake{10%,90%{-webkit-transform:translate3d(-2px,0,0);transform:translate3d(-2px,0,0)}20%,80%{-webkit-transform:translate3d(4px,0,0);transform:translate3d(4px,0,0)}30%,50%,70%{-webkit-transform:translate3d(-8px,0,0);transform:translate3d(-8px,0,0)}40%,60%{-webkit-transform:translate3d(8px,0,0);transform:translate3d(8px,0,0)}}@keyframes shake{10%,90%{-webkit-transform:translate3d(-2px,0,0);transform:translate3d(-2px,0,0)}20%,80%{-webkit-transform:translate3d(4px,0,0);transform:translate3d(4px,0,0)}30%,50%,70%{-webkit-transform:translate3d(-8px,0,0);transform:translate3d(-8px,0,0)}40%,60%{-webkit-transform:translate3d(8px,0,0);transform:translate3d(8px,0,0)}}@-webkit-keyframes glow{0%,100%{-webkit-box-shadow:0 0 0 red;box-shadow:0 0 0 red}50%{-webkit-box-shadow:0 0 30px red;box-shadow:0 0 30px red}}@keyframes glow{0%,100%{-webkit-box-shadow:0 0 0 red;box-shadow:0 0 0 red}50%{-webkit-box-shadow:0 0 30px red;box-shadow:0 0 30px red}}.jconfirm{-webkit-perspective:400px;perspective:400px}.jconfirm .jconfirm-box{opacity:1;-webkit-transition-property:all;transition-property:all}.jconfirm .jconfirm-box.jconfirm-animation-top,.jconfirm .jconfirm-box.jconfirm-animation-left,.jconfirm .jconfirm-box.jconfirm-animation-right,.jconfirm .jconfirm-box.jconfirm-animation-bottom,.jconfirm .jconfirm-box.jconfirm-animation-opacity,.jconfirm .jconfirm-box.jconfirm-animation-zoom,.jconfirm .jconfirm-box.jconfirm-animation-scale,.jconfirm .jconfirm-box.jconfirm-animation-none,.jconfirm .jconfirm-box.jconfirm-animation-rotate,.jconfirm .jconfirm-box.jconfirm-animation-rotatex,.jconfirm .jconfirm-box.jconfirm-animation-rotatey,.jconfirm .jconfirm-box.jconfirm-animation-scaley,.jconfirm .jconfirm-box.jconfirm-animation-scalex{opacity:0}.jconfirm .jconfirm-box.jconfirm-animation-rotate{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.jconfirm .jconfirm-box.jconfirm-animation-rotatex{-webkit-transform:rotateX(90deg);transform:rotateX(90deg);-webkit-transform-origin:center;transform-origin:center}.jconfirm .jconfirm-box.jconfirm-animation-rotatexr{-webkit-transform:rotateX(-90deg);transform:rotateX(-90deg);-webkit-transform-origin:center;transform-origin:center}.jconfirm .jconfirm-box.jconfirm-animation-rotatey{-webkit-transform:rotatey(90deg);transform:rotatey(90deg);-webkit-transform-origin:center;transform-origin:center}.jconfirm .jconfirm-box.jconfirm-animation-rotateyr{-webkit-transform:rotatey(-90deg);transform:rotatey(-90deg);-webkit-transform-origin:center;transform-origin:center}.jconfirm .jconfirm-box.jconfirm-animation-scaley{-webkit-transform:scaley(1.5);transform:scaley(1.5);-webkit-transform-origin:center;transform-origin:center}.jconfirm .jconfirm-box.jconfirm-animation-scalex{-webkit-transform:scalex(1.5);transform:scalex(1.5);-webkit-transform-origin:center;transform-origin:center}.jconfirm .jconfirm-box.jconfirm-animation-top{-webkit-transform:translate(0px,-100px);transform:translate(0px,-100px)}.jconfirm .jconfirm-box.jconfirm-animation-left{-webkit-transform:translate(-100px,0px);transform:translate(-100px,0px)}.jconfirm .jconfirm-box.jconfirm-animation-right{-webkit-transform:translate(100px,0px);transform:translate(100px,0px)}.jconfirm .jconfirm-box.jconfirm-animation-bottom{-webkit-transform:translate(0px,100px);transform:translate(0px,100px)}.jconfirm .jconfirm-box.jconfirm-animation-zoom{-webkit-transform:scale(1.2);transform:scale(1.2)}.jconfirm .jconfirm-box.jconfirm-animation-scale{-webkit-transform:scale(0.5);transform:scale(0.5)}.jconfirm .jconfirm-box.jconfirm-animation-none{visibility:hidden}.jconfirm.jconfirm-supervan .jconfirm-bg{background-color:rgba(54,70,93,0.95)}.jconfirm.jconfirm-supervan .jconfirm-box{background-color:transparent}.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-blue{border:0}.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-green{border:0}.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-red{border:0}.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-orange{border:0}.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-purple{border:0}.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-dark{border:0}.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-closeIcon{color:white}.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-title-c{text-align:center;color:white;font-size:28px;font-weight:normal}.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-title-c>*{padding-bottom:25px}.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c{margin-right:8px;margin-left:0}.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-content-pane{margin-bottom:25px}.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-content{text-align:center;color:white}.jconfirm.jconfirm-supervan .jconfirm-box .jconfirm-buttons{text-align:center}.jconfirm.jconfirm-supervan .jconfirm-box .jconfirm-buttons button{font-size:16px;border-radius:2px;background:#303f53;text-shadow:none;border:0;color:white;padding:10px;min-width:100px}.jconfirm.jconfirm-supervan.jconfirm-rtl .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c{margin-left:8px;margin-right:0}.jconfirm.jconfirm-material .jconfirm-bg{background-color:rgba(0,0,0,0.67)}.jconfirm.jconfirm-material .jconfirm-box{background-color:white;-webkit-box-shadow:0 7px 8px -4px rgba(0,0,0,0.2),0 13px 19px 2px rgba(0,0,0,0.14),0 5px 24px 4px rgba(0,0,0,0.12);box-shadow:0 7px 8px -4px rgba(0,0,0,0.2),0 13px 19px 2px rgba(0,0,0,0.14),0 5px 24px 4px rgba(0,0,0,0.12);padding:30px 25px 10px 25px}.jconfirm.jconfirm-material .jconfirm-box .jconfirm-title-c .jconfirm-icon-c{margin-right:8px;margin-left:0}.jconfirm.jconfirm-material .jconfirm-box div.jconfirm-closeIcon{color:rgba(0,0,0,0.87)}.jconfirm.jconfirm-material .jconfirm-box div.jconfirm-title-c{color:rgba(0,0,0,0.87);font-size:22px;font-weight:bold}.jconfirm.jconfirm-material .jconfirm-box div.jconfirm-content{color:rgba(0,0,0,0.87)}.jconfirm.jconfirm-material .jconfirm-box .jconfirm-buttons{text-align:right}.jconfirm.jconfirm-material .jconfirm-box .jconfirm-buttons button{text-transform:uppercase;font-weight:500}.jconfirm.jconfirm-material.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c{margin-left:8px;margin-right:0}.jconfirm.jconfirm-bootstrap .jconfirm-bg{background-color:rgba(0,0,0,0.21)}.jconfirm.jconfirm-bootstrap .jconfirm-box{background-color:white;-webkit-box-shadow:0 3px 8px 0 rgba(0,0,0,0.2);box-shadow:0 3px 8px 0 rgba(0,0,0,0.2);border:solid 1px rgba(0,0,0,0.4);padding:15px 0 0}.jconfirm.jconfirm-bootstrap .jconfirm-box .jconfirm-title-c .jconfirm-icon-c{margin-right:8px;margin-left:0}.jconfirm.jconfirm-bootstrap .jconfirm-box div.jconfirm-closeIcon{color:rgba(0,0,0,0.87)}.jconfirm.jconfirm-bootstrap .jconfirm-box div.jconfirm-title-c{color:rgba(0,0,0,0.87);font-size:22px;font-weight:bold;padding-left:15px;padding-right:15px}.jconfirm.jconfirm-bootstrap .jconfirm-box div.jconfirm-content{color:rgba(0,0,0,0.87);padding:0 15px}.jconfirm.jconfirm-bootstrap .jconfirm-box .jconfirm-buttons{text-align:right;padding:10px;margin:-5px 0 0;border-top:solid 1px #ddd;overflow:hidden;border-radius:0 0 4px 4px}.jconfirm.jconfirm-bootstrap .jconfirm-box .jconfirm-buttons button{font-weight:500}.jconfirm.jconfirm-bootstrap.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c{margin-left:8px;margin-right:0}.jconfirm.jconfirm-modern .jconfirm-bg{background-color:slategray;opacity:.6}.jconfirm.jconfirm-modern .jconfirm-box{background-color:white;-webkit-box-shadow:0 7px 8px -4px rgba(0,0,0,0.2),0 13px 19px 2px rgba(0,0,0,0.14),0 5px 24px 4px rgba(0,0,0,0.12);box-shadow:0 7px 8px -4px rgba(0,0,0,0.2),0 13px 19px 2px rgba(0,0,0,0.14),0 5px 24px 4px rgba(0,0,0,0.12);padding:30px 30px 15px}.jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-closeIcon{color:rgba(0,0,0,0.87);top:15px;right:15px}.jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-title-c{color:rgba(0,0,0,0.87);font-size:24px;font-weight:bold;text-align:center;margin-bottom:10px}.jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c{-webkit-transition:-webkit-transform .5s;transition:-webkit-transform .5s;transition:transform .5s;transition:transform .5s,-webkit-transform .5s;-webkit-transform:scale(0);transform:scale(0);display:block;margin-right:0;margin-left:0;margin-bottom:10px;font-size:69px;color:#aaa}.jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-content{text-align:center;font-size:15px;color:#777;margin-bottom:25px}.jconfirm.jconfirm-modern .jconfirm-box .jconfirm-buttons{text-align:center}.jconfirm.jconfirm-modern .jconfirm-box .jconfirm-buttons button{font-weight:bold;text-transform:uppercase;-webkit-transition:background .1s;transition:background .1s;padding:10px 20px}.jconfirm.jconfirm-modern .jconfirm-box .jconfirm-buttons button+button{margin-left:4px}.jconfirm.jconfirm-modern.jconfirm-open .jconfirm-box .jconfirm-title-c .jconfirm-icon-c{-webkit-transform:scale(1);transform:scale(1)} \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/css/vendor/lity.min.css b/wp-content/plugins/wp-mail-smtp/assets/css/vendor/lity.min.css new file mode 100755 index 00000000..aa251766 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/css/vendor/lity.min.css @@ -0,0 +1,3 @@ +/*! Lity - v2.4.1 - 2020-04-26 +* http://sorgalla.com/lity/ +* Copyright (c) 2015-2020 Jan Sorgalla; Licensed MIT */.lity{z-index:9990;position:fixed;top:0;right:0;bottom:0;left:0;white-space:nowrap;background:#0b0b0b;background:rgba(0,0,0,0.9);outline:none !important;opacity:0;-webkit-transition:opacity .3s ease;-o-transition:opacity .3s ease;transition:opacity .3s ease}.lity.lity-opened{opacity:1}.lity.lity-closed{opacity:0}.lity *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.lity-wrap{z-index:9990;position:fixed;top:0;right:0;bottom:0;left:0;text-align:center;outline:none !important}.lity-wrap:before{content:'';display:inline-block;height:100%;vertical-align:middle;margin-right:-0.25em}.lity-loader{z-index:9991;color:#fff;position:absolute;top:50%;margin-top:-0.8em;width:100%;text-align:center;font-size:14px;font-family:Arial,Helvetica,sans-serif;opacity:0;-webkit-transition:opacity .3s ease;-o-transition:opacity .3s ease;transition:opacity .3s ease}.lity-loading .lity-loader{opacity:1}.lity-container{z-index:9992;position:relative;text-align:left;vertical-align:middle;display:inline-block;white-space:normal;max-width:100%;max-height:100%;outline:none !important}.lity-content{z-index:9993;width:100%;-webkit-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1);-webkit-transition:-webkit-transform .3s ease;transition:-webkit-transform .3s ease;-o-transition:-o-transform .3s ease;transition:transform .3s ease;transition:transform .3s ease, -webkit-transform .3s ease, -o-transform .3s ease}.lity-loading .lity-content,.lity-closed .lity-content{-webkit-transform:scale(.8);-ms-transform:scale(.8);-o-transform:scale(.8);transform:scale(.8)}.lity-content:after{content:'';position:absolute;left:0;top:0;bottom:0;display:block;right:0;width:auto;height:auto;z-index:-1;-webkit-box-shadow:0 0 8px rgba(0,0,0,0.6);box-shadow:0 0 8px rgba(0,0,0,0.6)}.lity-close{z-index:9994;width:35px;height:35px;position:fixed;right:0;top:0;-webkit-appearance:none;cursor:pointer;text-decoration:none;text-align:center;padding:0;color:#fff;font-style:normal;font-size:35px;font-family:Arial,Baskerville,monospace;line-height:35px;text-shadow:0 1px 2px rgba(0,0,0,0.6);border:0;background:none;outline:none;-webkit-box-shadow:none;box-shadow:none}.lity-close::-moz-focus-inner{border:0;padding:0}.lity-close:hover,.lity-close:focus,.lity-close:active,.lity-close:visited{text-decoration:none;text-align:center;padding:0;color:#fff;font-style:normal;font-size:35px;font-family:Arial,Baskerville,monospace;line-height:35px;text-shadow:0 1px 2px rgba(0,0,0,0.6);border:0;background:none;outline:none;-webkit-box-shadow:none;box-shadow:none}.lity-close:active{top:1px}.lity-image img{max-width:100%;display:block;line-height:0;border:0}.lity-iframe .lity-container,.lity-youtube .lity-container,.lity-vimeo .lity-container,.lity-facebookvideo .lity-container,.lity-googlemaps .lity-container{width:100%;max-width:964px}.lity-iframe-container{width:100%;height:0;padding-top:56.25%;overflow:auto;pointer-events:auto;-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-overflow-scrolling:touch}.lity-iframe-container iframe{position:absolute;display:block;top:0;left:0;width:100%;height:100%;-webkit-box-shadow:0 0 8px rgba(0,0,0,0.6);box-shadow:0 0 8px rgba(0,0,0,0.6);background:#000}.lity-hide{display:none} \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/affiliatewp.png b/wp-content/plugins/wp-mail-smtp/assets/images/about/affiliatewp.png new file mode 100755 index 00000000..cbd0d3cc Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/about/affiliatewp.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/duplicator-icon-large.png b/wp-content/plugins/wp-mail-smtp/assets/images/about/duplicator-icon-large.png new file mode 100755 index 00000000..3add72c3 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/about/duplicator-icon-large.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/edd.png b/wp-content/plugins/wp-mail-smtp/assets/images/about/edd.png new file mode 100755 index 00000000..cc33aa20 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/about/edd.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/icon-full.svg b/wp-content/plugins/wp-mail-smtp/assets/images/about/icon-full.svg new file mode 100755 index 00000000..6d5d611b --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/about/icon-full.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/icon-none.svg b/wp-content/plugins/wp-mail-smtp/assets/images/about/icon-none.svg new file mode 100755 index 00000000..43efd278 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/about/icon-none.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/icon-partial.svg b/wp-content/plugins/wp-mail-smtp/assets/images/about/icon-partial.svg new file mode 100755 index 00000000..fde33ea3 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/about/icon-partial.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-aioseo.png b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-aioseo.png new file mode 100755 index 00000000..7785f677 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-aioseo.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-charitable.png b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-charitable.png new file mode 100755 index 00000000..c85adc9f Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-charitable.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-mi.png b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-mi.png new file mode 100755 index 00000000..613d6ee4 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-mi.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-om.png b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-om.png new file mode 100755 index 00000000..11004c55 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-om.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-pushengage.png b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-pushengage.png new file mode 100755 index 00000000..15ce746e Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-pushengage.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-rp.png b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-rp.png new file mode 100755 index 00000000..7a075697 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-rp.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-seedprod.png b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-seedprod.png new file mode 100755 index 00000000..615191f9 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-seedprod.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-smash-balloon-facebook-feeds.png b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-smash-balloon-facebook-feeds.png new file mode 100755 index 00000000..eb0d4191 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-smash-balloon-facebook-feeds.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-smash-balloon-instagram-feeds.png b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-smash-balloon-instagram-feeds.png new file mode 100755 index 00000000..3d4532e6 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-smash-balloon-instagram-feeds.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-smash-balloon-twitter-feeds.png b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-smash-balloon-twitter-feeds.png new file mode 100755 index 00000000..9262097e Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-smash-balloon-twitter-feeds.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-smash-balloon-youtube-feeds.png b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-smash-balloon-youtube-feeds.png new file mode 100755 index 00000000..1b20fc62 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-smash-balloon-youtube-feeds.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-trustpulse.png b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-trustpulse.png new file mode 100755 index 00000000..cb762d63 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-trustpulse.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-wpcode.png b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-wpcode.png new file mode 100755 index 00000000..456134aa Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-wpcode.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-wpf.png b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-wpf.png new file mode 100755 index 00000000..ef1490bb Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/about/plugin-wpf.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/searchwp.png b/wp-content/plugins/wp-mail-smtp/assets/images/about/searchwp.png new file mode 100755 index 00000000..4e8a2f59 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/about/searchwp.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/sugar-calendar.png b/wp-content/plugins/wp-mail-smtp/assets/images/about/sugar-calendar.png new file mode 100755 index 00000000..6d0ae541 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/about/sugar-calendar.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/team.jpg b/wp-content/plugins/wp-mail-smtp/assets/images/about/team.jpg new file mode 100755 index 00000000..acd30fa2 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/about/team.jpg differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/about/wp-simple-pay.png b/wp-content/plugins/wp-mail-smtp/assets/images/about/wp-simple-pay.png new file mode 100755 index 00000000..b7525260 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/about/wp-simple-pay.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/additional-connections/screenshot-01.png b/wp-content/plugins/wp-mail-smtp/assets/images/additional-connections/screenshot-01.png new file mode 100755 index 00000000..c77705b3 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/additional-connections/screenshot-01.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/additional-connections/screenshot-02.png b/wp-content/plugins/wp-mail-smtp/assets/images/additional-connections/screenshot-02.png new file mode 100755 index 00000000..72346b89 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/additional-connections/screenshot-02.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/additional-connections/thumbnail-01.png b/wp-content/plugins/wp-mail-smtp/assets/images/additional-connections/thumbnail-01.png new file mode 100755 index 00000000..f740babf Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/additional-connections/thumbnail-01.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/additional-connections/thumbnail-02.png b/wp-content/plugins/wp-mail-smtp/assets/images/additional-connections/thumbnail-02.png new file mode 100755 index 00000000..96caf312 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/additional-connections/thumbnail-02.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/error-icon.svg b/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/error-icon.svg new file mode 100755 index 00000000..12fe2e93 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/error-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/smtp/delivered.svg b/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/smtp/delivered.svg new file mode 100755 index 00000000..54970493 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/smtp/delivered.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/smtp/sent.svg b/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/smtp/sent.svg new file mode 100755 index 00000000..af291253 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/smtp/sent.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/smtp/total.svg b/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/smtp/total.svg new file mode 100755 index 00000000..ff843f1f --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/smtp/total.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/smtp/unsent.svg b/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/smtp/unsent.svg new file mode 100755 index 00000000..aaa1d5a9 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/smtp/unsent.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/wp/delivered.svg b/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/wp/delivered.svg new file mode 100755 index 00000000..ab90d5dc --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/wp/delivered.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/wp/sent.svg b/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/wp/sent.svg new file mode 100755 index 00000000..af291253 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/wp/sent.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/wp/total.svg b/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/wp/total.svg new file mode 100755 index 00000000..b4bc0912 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/wp/total.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/wp/unsent.svg b/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/wp/unsent.svg new file mode 100755 index 00000000..aaa1d5a9 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/wp/unsent.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/yes-green.svg b/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/yes-green.svg new file mode 100755 index 00000000..57f1302c --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/dash-widget/yes-green.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/email-reports/screenshot-01.png b/wp-content/plugins/wp-mail-smtp/assets/images/email-reports/screenshot-01.png new file mode 100755 index 00000000..4a878e97 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/email-reports/screenshot-01.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/email-reports/screenshot-02.png b/wp-content/plugins/wp-mail-smtp/assets/images/email-reports/screenshot-02.png new file mode 100755 index 00000000..48c4aeb9 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/email-reports/screenshot-02.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/email-reports/screenshot-03.png b/wp-content/plugins/wp-mail-smtp/assets/images/email-reports/screenshot-03.png new file mode 100755 index 00000000..320510c8 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/email-reports/screenshot-03.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/email-reports/thumbnail-01.png b/wp-content/plugins/wp-mail-smtp/assets/images/email-reports/thumbnail-01.png new file mode 100755 index 00000000..d0e3bf1e Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/email-reports/thumbnail-01.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/email-reports/thumbnail-02.png b/wp-content/plugins/wp-mail-smtp/assets/images/email-reports/thumbnail-02.png new file mode 100755 index 00000000..d2cf6996 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/email-reports/thumbnail-02.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/email-reports/thumbnail-03.png b/wp-content/plugins/wp-mail-smtp/assets/images/email-reports/thumbnail-03.png new file mode 100755 index 00000000..0daa8def Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/email-reports/thumbnail-03.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/email/icon-check.png b/wp-content/plugins/wp-mail-smtp/assets/images/email/icon-check.png new file mode 100755 index 00000000..02e61da0 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/email/icon-check.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/email/illustration-success.svg b/wp-content/plugins/wp-mail-smtp/assets/images/email/illustration-success.svg new file mode 100755 index 00000000..783f52ee --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/email/illustration-success.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/email/signature.png b/wp-content/plugins/wp-mail-smtp/assets/images/email/signature.png new file mode 100755 index 00000000..f8fff312 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/email/signature.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/email/wp-mail-smtp-whitelabel.png b/wp-content/plugins/wp-mail-smtp/assets/images/email/wp-mail-smtp-whitelabel.png new file mode 100755 index 00000000..9ce76ad0 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/email/wp-mail-smtp-whitelabel.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/email/wp-mail-smtp.png b/wp-content/plugins/wp-mail-smtp/assets/images/email/wp-mail-smtp.png new file mode 100755 index 00000000..6a452531 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/email/wp-mail-smtp.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/flyout-menu/facebook.svg b/wp-content/plugins/wp-mail-smtp/assets/images/flyout-menu/facebook.svg new file mode 100755 index 00000000..74095298 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/flyout-menu/facebook.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/flyout-menu/life-ring.svg b/wp-content/plugins/wp-mail-smtp/assets/images/flyout-menu/life-ring.svg new file mode 100755 index 00000000..21aa971d --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/flyout-menu/life-ring.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/flyout-menu/lightbulb.svg b/wp-content/plugins/wp-mail-smtp/assets/images/flyout-menu/lightbulb.svg new file mode 100755 index 00000000..42a28840 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/flyout-menu/lightbulb.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/flyout-menu/mascot.svg b/wp-content/plugins/wp-mail-smtp/assets/images/flyout-menu/mascot.svg new file mode 100755 index 00000000..6d9e8a03 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/flyout-menu/mascot.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/flyout-menu/star.svg b/wp-content/plugins/wp-mail-smtp/assets/images/flyout-menu/star.svg new file mode 100755 index 00000000..85bf4f00 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/flyout-menu/star.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/arrow-rotate-right-purple.svg b/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/arrow-rotate-right-purple.svg new file mode 100755 index 00000000..c978648f --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/arrow-rotate-right-purple.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/cancel-red.svg b/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/cancel-red.svg new file mode 100755 index 00000000..a61ae98d --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/cancel-red.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/check-circle-dark-green.svg b/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/check-circle-dark-green.svg new file mode 100755 index 00000000..4fc508d5 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/check-circle-dark-green.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/check-circle-solid-green.svg b/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/check-circle-solid-green.svg new file mode 100755 index 00000000..6be58277 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/check-circle-solid-green.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/clock-orange.svg b/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/clock-orange.svg new file mode 100755 index 00000000..6236e6a8 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/clock-orange.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/exclamation-circle-regular-red.svg b/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/exclamation-circle-regular-red.svg new file mode 100755 index 00000000..e59ade4b --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/exclamation-circle-regular-red.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/exclamation-circle-solid-orange.svg b/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/exclamation-circle-solid-orange.svg new file mode 100755 index 00000000..26e742d7 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/exclamation-circle-solid-orange.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/exclamation-circle-solid-red.svg b/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/exclamation-circle-solid-red.svg new file mode 100755 index 00000000..8c9c1554 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/exclamation-circle-solid-red.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/info-circle-blue.svg b/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/info-circle-blue.svg new file mode 100755 index 00000000..198fb614 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/info-circle-blue.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/info-circle.svg b/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/info-circle.svg new file mode 100755 index 00000000..8c80048e --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/font-awesome/info-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/icons/arrow-up.svg b/wp-content/plugins/wp-mail-smtp/assets/images/icons/arrow-up.svg new file mode 100755 index 00000000..cfe6b880 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/icons/arrow-up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/icons/badge-percent.svg b/wp-content/plugins/wp-mail-smtp/assets/images/icons/badge-percent.svg new file mode 100755 index 00000000..6a08dd38 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/icons/badge-percent.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/icons/check-solid.svg b/wp-content/plugins/wp-mail-smtp/assets/images/icons/check-solid.svg new file mode 100755 index 00000000..230004ae --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/icons/check-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/icons/check.svg b/wp-content/plugins/wp-mail-smtp/assets/images/icons/check.svg new file mode 100755 index 00000000..d407cb82 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/icons/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/icons/close.svg b/wp-content/plugins/wp-mail-smtp/assets/images/icons/close.svg new file mode 100755 index 00000000..4ea6d124 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/icons/close.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/icons/dashicons/dashicons-pdf-grey.svg b/wp-content/plugins/wp-mail-smtp/assets/images/icons/dashicons/dashicons-pdf-grey.svg new file mode 100755 index 00000000..02d7f56b --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/icons/dashicons/dashicons-pdf-grey.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/icons/dashicons/dashicons-yes-alt-green.svg b/wp-content/plugins/wp-mail-smtp/assets/images/icons/dashicons/dashicons-yes-alt-green.svg new file mode 100755 index 00000000..c9bd25ca --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/icons/dashicons/dashicons-yes-alt-green.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/icons/error.svg b/wp-content/plugins/wp-mail-smtp/assets/images/icons/error.svg new file mode 100755 index 00000000..b084cd74 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/icons/error.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/icons/exclamation-circle.svg b/wp-content/plugins/wp-mail-smtp/assets/images/icons/exclamation-circle.svg new file mode 100755 index 00000000..c0f26670 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/icons/exclamation-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/icons/lightbulb.svg b/wp-content/plugins/wp-mail-smtp/assets/images/icons/lightbulb.svg new file mode 100755 index 00000000..46fb1eb0 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/icons/lightbulb.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/icons/success.svg b/wp-content/plugins/wp-mail-smtp/assets/images/icons/success.svg new file mode 100755 index 00000000..9bed367e --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/icons/success.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/icons/warning.svg b/wp-content/plugins/wp-mail-smtp/assets/images/icons/warning.svg new file mode 100755 index 00000000..abc20f85 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/icons/warning.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/icons/zoom.svg b/wp-content/plugins/wp-mail-smtp/assets/images/icons/zoom.svg new file mode 100755 index 00000000..1389afdb --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/icons/zoom.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/loaders/loading-blue.svg b/wp-content/plugins/wp-mail-smtp/assets/images/loaders/loading-blue.svg new file mode 100755 index 00000000..5519045f --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/loaders/loading-blue.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/loaders/loading-white.svg b/wp-content/plugins/wp-mail-smtp/assets/images/loaders/loading-white.svg new file mode 100755 index 00000000..ae6fe144 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/loaders/loading-white.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/loaders/loading.svg b/wp-content/plugins/wp-mail-smtp/assets/images/loaders/loading.svg new file mode 100755 index 00000000..84178328 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/loaders/loading.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/logo-whitelabel.svg b/wp-content/plugins/wp-mail-smtp/assets/images/logo-whitelabel.svg new file mode 100755 index 00000000..db8375b8 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/logo-whitelabel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/logo.svg b/wp-content/plugins/wp-mail-smtp/assets/images/logo.svg new file mode 100755 index 00000000..1295c813 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/logs/archive-thumbnail.png b/wp-content/plugins/wp-mail-smtp/assets/images/logs/archive-thumbnail.png new file mode 100755 index 00000000..459b016b Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/logs/archive-thumbnail.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/logs/archive.png b/wp-content/plugins/wp-mail-smtp/assets/images/logs/archive.png new file mode 100755 index 00000000..a3b024d3 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/logs/archive.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/logs/single-thumbnail.png b/wp-content/plugins/wp-mail-smtp/assets/images/logs/single-thumbnail.png new file mode 100755 index 00000000..231c421c Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/logs/single-thumbnail.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/logs/single.png b/wp-content/plugins/wp-mail-smtp/assets/images/logs/single.png new file mode 100755 index 00000000..215c956e Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/logs/single.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/menu-icon.svg b/wp-content/plugins/wp-mail-smtp/assets/images/menu-icon.svg new file mode 100755 index 00000000..a646b1a0 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/menu-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/pattie.svg b/wp-content/plugins/wp-mail-smtp/assets/images/pattie.svg new file mode 100755 index 00000000..2966ee32 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/pattie.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/pro-badge-small.svg b/wp-content/plugins/wp-mail-smtp/assets/images/pro-badge-small.svg new file mode 100755 index 00000000..99e058ac --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/pro-badge-small.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/pro-badge.svg b/wp-content/plugins/wp-mail-smtp/assets/images/pro-badge.svg new file mode 100755 index 00000000..4e1ced24 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/pro-badge.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/providers/aws.svg b/wp-content/plugins/wp-mail-smtp/assets/images/providers/aws.svg new file mode 100755 index 00000000..0338816b --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/providers/aws.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/providers/brevo.svg b/wp-content/plugins/wp-mail-smtp/assets/images/providers/brevo.svg new file mode 100755 index 00000000..473cf40a --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/providers/brevo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/providers/elasticemail.svg b/wp-content/plugins/wp-mail-smtp/assets/images/providers/elasticemail.svg new file mode 100755 index 00000000..96c1da44 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/providers/elasticemail.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/providers/google.svg b/wp-content/plugins/wp-mail-smtp/assets/images/providers/google.svg new file mode 100755 index 00000000..22150fc5 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/providers/google.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/providers/mailersend.svg b/wp-content/plugins/wp-mail-smtp/assets/images/providers/mailersend.svg new file mode 100755 index 00000000..f1e715e9 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/providers/mailersend.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/providers/mailgun.svg b/wp-content/plugins/wp-mail-smtp/assets/images/providers/mailgun.svg new file mode 100755 index 00000000..c76a86c2 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/providers/mailgun.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/providers/mailjet.svg b/wp-content/plugins/wp-mail-smtp/assets/images/providers/mailjet.svg new file mode 100755 index 00000000..37ba9162 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/providers/mailjet.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/providers/mandrill.svg b/wp-content/plugins/wp-mail-smtp/assets/images/providers/mandrill.svg new file mode 100755 index 00000000..690f0dd4 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/providers/mandrill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/providers/microsoft.svg b/wp-content/plugins/wp-mail-smtp/assets/images/providers/microsoft.svg new file mode 100755 index 00000000..1033de4c --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/providers/microsoft.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/providers/pepipost-smtp.png b/wp-content/plugins/wp-mail-smtp/assets/images/providers/pepipost-smtp.png new file mode 100755 index 00000000..6f67bcda Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/providers/pepipost-smtp.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/providers/pepipost.png b/wp-content/plugins/wp-mail-smtp/assets/images/providers/pepipost.png new file mode 100755 index 00000000..2ef20029 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/providers/pepipost.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/providers/php.svg b/wp-content/plugins/wp-mail-smtp/assets/images/providers/php.svg new file mode 100755 index 00000000..e036c2a4 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/providers/php.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/providers/postmark.svg b/wp-content/plugins/wp-mail-smtp/assets/images/providers/postmark.svg new file mode 100755 index 00000000..720dc8b4 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/providers/postmark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/providers/resend.svg b/wp-content/plugins/wp-mail-smtp/assets/images/providers/resend.svg new file mode 100755 index 00000000..c9d7529d --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/providers/resend.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/providers/sendgrid.svg b/wp-content/plugins/wp-mail-smtp/assets/images/providers/sendgrid.svg new file mode 100755 index 00000000..194e8bcb --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/providers/sendgrid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/providers/sendlayer.svg b/wp-content/plugins/wp-mail-smtp/assets/images/providers/sendlayer.svg new file mode 100755 index 00000000..59f14131 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/providers/sendlayer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/providers/smtp-com.svg b/wp-content/plugins/wp-mail-smtp/assets/images/providers/smtp-com.svg new file mode 100755 index 00000000..64b9351d --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/providers/smtp-com.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/providers/smtp.svg b/wp-content/plugins/wp-mail-smtp/assets/images/providers/smtp.svg new file mode 100755 index 00000000..770be9b6 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/providers/smtp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/providers/smtp2go.svg b/wp-content/plugins/wp-mail-smtp/assets/images/providers/smtp2go.svg new file mode 100755 index 00000000..993a6043 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/providers/smtp2go.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/providers/sparkpost.svg b/wp-content/plugins/wp-mail-smtp/assets/images/providers/sparkpost.svg new file mode 100755 index 00000000..8039da5d --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/providers/sparkpost.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/providers/zoho.svg b/wp-content/plugins/wp-mail-smtp/assets/images/providers/zoho.svg new file mode 100755 index 00000000..0bd65b4f --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/providers/zoho.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/recommended.svg b/wp-content/plugins/wp-mail-smtp/assets/images/recommended.svg new file mode 100755 index 00000000..a2c68d93 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/images/recommended.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-arrow-down.png b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-arrow-down.png new file mode 100755 index 00000000..f9bec5cb Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-arrow-down.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-arrow-up.png b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-arrow-up.png new file mode 100755 index 00000000..b3638dc8 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-arrow-up.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-check-gray.png b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-check-gray.png new file mode 100755 index 00000000..45179aa9 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-check-gray.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-check.png b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-check.png new file mode 100755 index 00000000..1eaa6751 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-check.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-click.png b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-click.png new file mode 100755 index 00000000..73701759 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-click.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-email.png b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-email.png new file mode 100755 index 00000000..e12acc1c Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-email.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-error.png b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-error.png new file mode 100755 index 00000000..22911743 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-error.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-open.png b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-open.png new file mode 100755 index 00000000..9f68a8a9 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/icon-open.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/wp-mail-smtp-logo-dark-whitelabel.png b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/wp-mail-smtp-logo-dark-whitelabel.png new file mode 100755 index 00000000..ad96fa2f Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/wp-mail-smtp-logo-dark-whitelabel.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/wp-mail-smtp-logo-dark.png b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/wp-mail-smtp-logo-dark.png new file mode 100755 index 00000000..13e704a0 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/wp-mail-smtp-logo-dark.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/wp-mail-smtp-logo-whitelabel.png b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/wp-mail-smtp-logo-whitelabel.png new file mode 100755 index 00000000..bf10c533 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/wp-mail-smtp-logo-whitelabel.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/wp-mail-smtp-logo.png b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/wp-mail-smtp-logo.png new file mode 100755 index 00000000..8d135f11 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/reports/email/wp-mail-smtp-logo.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/reports/icon-note.png b/wp-content/plugins/wp-mail-smtp/assets/images/reports/icon-note.png new file mode 100755 index 00000000..f3f32427 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/reports/icon-note.png differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/images/wp-spinner.gif b/wp-content/plugins/wp-mail-smtp/assets/images/wp-spinner.gif new file mode 100755 index 00000000..f4087c96 Binary files /dev/null and b/wp-content/plugins/wp-mail-smtp/assets/images/wp-spinner.gif differ diff --git a/wp-content/plugins/wp-mail-smtp/assets/js/connect.js b/wp-content/plugins/wp-mail-smtp/assets/js/connect.js new file mode 100755 index 00000000..938c2782 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/js/connect.js @@ -0,0 +1,178 @@ +/* globals wp_mail_smtp_connect */ + +/** + * Connect functionality - Upgrade plugin from Lite to Pro version. + * + * @since 2.6.0 + */ + +'use strict'; + +var WPMailSMTPConnect = window.WPMailSMTPConnect || ( function( document, window, $ ) { + + /** + * Elements reference. + * + * @since 2.6.0 + * + * @type {object} + */ + var el = { + $connectBtn: $( '#wp-mail-smtp-setting-upgrade-license-button' ), + $connectKey: $( '#wp-mail-smtp-setting-upgrade-license-key' ) + }; + + /** + * Public functions and properties. + * + * @since 2.6.0 + * + * @type {object} + */ + var app = { + + /** + * Start the engine. + * + * @since 2.6.0 + */ + init: function() { + + $( app.ready ); + }, + + /** + * Document ready. + * + * @since 2.6.0 + */ + ready: function() { + + app.events(); + }, + + /** + * Register JS events. + * + * @since 2.6.0 + */ + events: function() { + + app.connectBtnClick(); + }, + + /** + * Register connect button event. + * + * @since 2.6.0 + */ + connectBtnClick: function() { + + el.$connectBtn.on( 'click', function() { + app.gotoUpgradeUrl(); + } ); + }, + + /** + * Get the alert arguments in case of Pro already installed. + * + * @since 2.6.0 + * + * @param {object} res Ajax query result object. + * + * @returns {object} Alert arguments. + */ + proAlreadyInstalled: function( res ) { + + return { + title: wp_mail_smtp_connect.text.almost_done, + content: res.data.message, + icon: '">"+t.status+" "+t.statusText+" "+t.responseText,icon:'">' + successText + '' ); + $plugin.find( 'span.status-label' ) + .removeClass( 'status-active status-inactive status-download' ) + .addClass( cssClass ) + .removeClass( 'button button-primary button-secondary disabled' ) + .text( statusText ); + $btn + .removeClass( 'status-active status-inactive status-download' ) + .removeClass( 'button button-primary button-secondary disabled' ) + .addClass( cssClass ).html( buttonText ); + } else { + isInstallSuccessful = false; + + if ( + res.hasOwnProperty( 'data' ) && + res.data.hasOwnProperty( 0 ) && + res.data[ 0 ].hasOwnProperty( 'code' ) + ) { + + // Specific server-returned error. + $plugin.find( '.actions' ).append( '
' + wp_mail_smtp_about.plugin_install_error + '
' ); + } else { + + // Generic error. + $plugin.find( '.actions' ).append( '
' + res.data + '
' ); + } + + $btn.html( wp_mail_smtp_about.plugin_download_btn ); + } + + if ( ! isInstallSuccessful ) { + $btn.removeClass( 'disabled' ); + } + $btn.removeClass( 'loading' ); + + // Automatically clear plugin messages after 3 seconds. + setTimeout( function() { + $( '.plugin-item .msg' ).remove(); + }, 3000 ); + + } ).fail( function( xhr ) { + console.log( xhr.responseText ); + } ); + } ); + } + }; + + // Provide access to public functions/properties. + return app; +}( document, window, jQuery ) ); + +// Initialize. +WPMailSMTP.Admin.About.init(); diff --git a/wp-content/plugins/wp-mail-smtp/assets/js/smtp-about.min.js b/wp-content/plugins/wp-mail-smtp/assets/js/smtp-about.min.js new file mode 100755 index 00000000..e8c8279a --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/js/smtp-about.min.js @@ -0,0 +1 @@ +"use strict";var WPMailSMTP=window.WPMailSMTP||{};WPMailSMTP.Admin=WPMailSMTP.Admin||{},WPMailSMTP.Admin.About=WPMailSMTP.Admin.About||function(a,t,d){var i={init:function(){d(i.ready)},ready:function(){i.pageHolder=d(".wp-mail-smtp-page-about"),i.bindActions(),d(".wp-mail-smtp-page").trigger("WPMailSMTP.Admin.About.ready")},bindActions:function(){jQuery(".wp-mail-smtp-admin-about-plugins .plugin-item .details").matchHeight(),d(a).on("click",".wp-mail-smtp-admin-about-plugins .plugin-item .action-button .button",function(a){a.preventDefault();var i=d(this);if(i.hasClass("disabled")||i.hasClass("loading"))return!1;var s,n,l,e,o,u=i.closest(".plugin-item"),a=i.attr("data-plugin");if(i.addClass("loading disabled"),i.text(wp_mail_smtp_about.plugin_processing),i.hasClass("status-inactive"))s="about_plugin_activate",n="status-active button button-secondary disabled",l=wp_mail_smtp_about.plugin_active,e=wp_mail_smtp_about.plugin_activated;else{if(!i.hasClass("status-download"))return i.hasClass("status-open")?(t.open(i.attr("href"),"_blank").focus(),i.removeClass("loading disabled"),void i.text(wp_mail_smtp_about.plugin_visit)):void 0;s="about_plugin_install",n="status-active button disabled",l=wp_mail_smtp_about.plugin_active,e=wp_mail_smtp_about.plugin_activated}a={action:"wp_mail_smtp_ajax",task:s,nonce:wp_mail_smtp_about.nonce,plugin:a};d.post(wp_mail_smtp_about.ajax_url,a,function(a){var t;a.success?(t=!0,"about_plugin_install"===s?(i.attr("data-plugin",a.data.basename),o=a.data.msg,a.data.is_activated||(n="button",l=wp_mail_smtp_about.plugin_inactive,e=wp_mail_smtp_about.plugin_activate)):o=a.data,u.find(".actions").append('
'+o+"
"),u.find("span.status-label").removeClass("status-active status-inactive status-download").addClass(n).removeClass("button button-primary button-secondary disabled").text(l),i.removeClass("status-active status-inactive status-download").removeClass("button button-primary button-secondary disabled").addClass(n).html(e)):(t=!1,a.hasOwnProperty("data")&&a.data.hasOwnProperty(0)&&a.data[0].hasOwnProperty("code")?u.find(".actions").append('
'+wp_mail_smtp_about.plugin_install_error+"
"):u.find(".actions").append('
'+a.data+"
"),i.html(wp_mail_smtp_about.plugin_download_btn)),t||i.removeClass("disabled"),i.removeClass("loading"),setTimeout(function(){d(".plugin-item .msg").remove()},3e3)}).fail(function(a){console.log(a.responseText)})})}};return i}(document,window,jQuery),WPMailSMTP.Admin.About.init(); \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/js/smtp-admin-notices.js b/wp-content/plugins/wp-mail-smtp/assets/js/smtp-admin-notices.js new file mode 100755 index 00000000..0f3a7aff --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/js/smtp-admin-notices.js @@ -0,0 +1,93 @@ +/* global wp_mail_smtp_admin_notices, ajaxurl */ + +/** + * WP Mail SMTP Admin Notices. + * + * @since 4.4.0 + */ + +'use strict'; + +var WPMailSMTPAdminNotices = window.WPMailSMTPAdminNotices || ( function( document, window, $ ) { + + /** + * Public functions and properties. + * + * @since 4.4.0 + * + * @type {object} + */ + var app = { + + /** + * Start the engine. + * + * @since 4.4.0 + */ + init: function() { + + $( app.ready ); + }, + + /** + * Document ready. + * + * @since 4.4.0 + */ + ready: function() { + + app.events(); + }, + + /** + * Register JS events. + * + * @since 4.4.0 + */ + events: function() { + + $( '.wp-mail-smtp-notice.is-dismissible' ) + .on( 'click', '.notice-dismiss', app.dismiss ); + }, + + /** + * Click on the dismiss notice button. + * + * @since 4.4.0 + * + * @param {object} event Event object. + */ + dismiss: function( event ) { + + var $notice = $( this ).closest( '.wp-mail-smtp-notice' ); + + // If notice key is not defined, we can't dismiss it permanently. + if ( $notice.data( 'notice' ) === undefined ) { + return; + } + + var $button = $( this ); + + $.ajax( { + url: ajaxurl, + dataType: 'json', + type: 'POST', + data: { + action: 'wp_mail_smtp_ajax', + nonce: wp_mail_smtp_admin_notices.nonce, + task: 'notice_dismiss', + notice: $notice.data( 'notice' ), + }, + beforeSend: function() { + $button.prop( 'disabled', true ); + }, + } ); + }, + }; + + return app; + +}( document, window, jQuery ) ); + +// Initialize. +WPMailSMTPAdminNotices.init(); diff --git a/wp-content/plugins/wp-mail-smtp/assets/js/smtp-admin-notices.min.js b/wp-content/plugins/wp-mail-smtp/assets/js/smtp-admin-notices.min.js new file mode 100755 index 00000000..c3b52f17 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/js/smtp-admin-notices.min.js @@ -0,0 +1 @@ +"use strict";var WPMailSMTPAdminNotices=window.WPMailSMTPAdminNotices||function(s){var i={init:function(){s(i.ready)},ready:function(){i.events()},events:function(){s(".wp-mail-smtp-notice.is-dismissible").on("click",".notice-dismiss",i.dismiss)},dismiss:function(i){var n,t=s(this).closest(".wp-mail-smtp-notice");void 0!==t.data("notice")&&(n=s(this),s.ajax({url:ajaxurl,dataType:"json",type:"POST",data:{action:"wp_mail_smtp_ajax",nonce:wp_mail_smtp_admin_notices.nonce,task:"notice_dismiss",notice:t.data("notice")},beforeSend:function(){n.prop("disabled",!0)}}))}};return i}((document,window,jQuery));WPMailSMTPAdminNotices.init(); \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/js/smtp-admin.js b/wp-content/plugins/wp-mail-smtp/assets/js/smtp-admin.js new file mode 100755 index 00000000..b9b603bf --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/js/smtp-admin.js @@ -0,0 +1,581 @@ +/* globals wp_mail_smtp, jconfirm, ajaxurl */ +'use strict'; + +var WPMailSMTP = window.WPMailSMTP || {}; +WPMailSMTP.Admin = WPMailSMTP.Admin || {}; + +/** + * WP Mail SMTP Admin area module. + * + * @since 1.6.0 + */ +WPMailSMTP.Admin.Settings = WPMailSMTP.Admin.Settings || ( function( document, window, $ ) { + + /** + * Public functions and properties. + * + * @since 1.6.0 + * + * @type {object} + */ + var app = { + + /** + * State attribute showing if one of the plugin settings + * changed and was not yet saved. + * + * @since 1.9.0 + * + * @type {boolean} + */ + pluginSettingsChanged: false, + + /** + * Start the engine. DOM is not ready yet, use only to init something. + * + * @since 1.6.0 + */ + init: function() { + + // Do that when DOM is ready. + $( app.ready ); + }, + + /** + * DOM is fully loaded. + * + * @since 1.6.0 + */ + ready: function() { + + app.pageHolder = $( '.wp-mail-smtp-tab-settings' ); + + app.settingsForm = $( '.wp-mail-smtp-connection-settings-form' ); + + // If there are screen options we have to move them. + $( '#screen-meta-links, #screen-meta' ).prependTo( '#wp-mail-smtp-header-temp' ).show(); + + app.bindActions(); + + app.setJQueryConfirmDefaults(); + + // Flyout Menu. + app.initFlyoutMenu(); + }, + + /** + * Process all generic actions/events, mostly custom that were fired by our API. + * + * @since 1.6.0 + */ + bindActions: function() { + + // Mailer selection. + $( '.wp-mail-smtp-mailer-image', app.settingsForm ).on( 'click', function() { + $( this ).parents( '.wp-mail-smtp-mailer' ).find( 'input' ).trigger( 'click' ); + } ); + + $( '.wp-mail-smtp-mailer input', app.settingsForm ).on( 'click', function() { + var $input = $( this ); + + if ( $input.prop( 'disabled' ) ) { + + // Educational Popup. + if ( $input.hasClass( 'educate' ) ) { + app.education.upgradeMailer( $input ); + } + + return false; + } + + // Deselect the current mailer. + $( '.wp-mail-smtp-mailer', app.settingsForm ).removeClass( 'active' ); + + // Select the correct one. + $( this ).parents( '.wp-mail-smtp-mailer' ).addClass( 'active' ); + + // Hide all mailers options and display for a currently clicked one. + $( '.wp-mail-smtp-mailer-option', app.settingsForm ).addClass( 'hidden' ).removeClass( 'active' ); + $( '.wp-mail-smtp-mailer-option-' + $( this ).val(), app.settingsForm ).addClass( 'active' ).removeClass( 'hidden' ); + } ); + + app.mailers.smtp.bindActions(); + + // Dismiss Pro banner at the bottom of the page. + $( '#wp-mail-smtp-pro-banner-dismiss', app.pageHolder ).on( 'click', function() { + $.ajax( { + url: ajaxurl, + dataType: 'json', + type: 'POST', + data: { + action: 'wp_mail_smtp_ajax', + task: 'pro_banner_dismiss', + nonce: wp_mail_smtp.nonce + } + } ) + .always( function() { + $( '#wp-mail-smtp-pro-banner', app.pageHolder ).fadeOut( 'fast' ); + } ); + } ); + + // Dissmis educational notices for certain mailers. + $( '.js-wp-mail-smtp-mailer-notice-dismiss', app.settingsForm ).on( 'click', function( e ) { + e.preventDefault(); + + var $btn = $( this ), + $notice = $btn.parents( '.inline-notice' ); + + if ( $btn.hasClass( 'disabled' ) ) { + return false; + } + + $.ajax( { + url: ajaxurl, + dataType: 'json', + type: 'POST', + data: { + action: 'wp_mail_smtp_ajax', + nonce: wp_mail_smtp.nonce, + task: 'notice_dismiss', + notice: $notice.data( 'notice' ), + mailer: $notice.data( 'mailer' ) + }, + beforeSend: function() { + $btn.addClass( 'disabled' ); + } + } ) + .always( function() { + $notice.fadeOut( 'fast', function() { + $btn.removeClass( 'disabled' ); + } ); + } ); + } ); + + // Show/hide debug output. + $( '#wp-mail-smtp-debug .error-log-toggle' ).on( 'click', function( e ) { + e.preventDefault(); + + $( '#wp-mail-smtp-debug .error-log' ).slideToggle(); + } ); + + // Copy debug output to clipboard. + $( '#wp-mail-smtp-debug .error-log-copy' ).on( 'click', function( e ) { + e.preventDefault(); + + var $self = $( this ); + + // Get error log. + var $content = $( '#wp-mail-smtp-debug .error-log' ); + + // Copy to clipboard. + if ( ! $content.is( ':visible' ) ) { + $content.addClass( 'error-log-selection' ); + } + var range = document.createRange(); + range.selectNode( $content[0] ); + window.getSelection().removeAllRanges(); + window.getSelection().addRange( range ); + document.execCommand( 'Copy' ); + window.getSelection().removeAllRanges(); + $content.removeClass( 'error-log-selection' ); + + $self.addClass( 'error-log-copy-copied' ); + + setTimeout( + function() { + $self.removeClass( 'error-log-copy-copied' ); + }, + 1500 + ); + } ); + + // Remove mailer connection. + $( '.js-wp-mail-smtp-provider-remove', app.settingsForm ).on( 'click', function() { + return confirm( wp_mail_smtp.text_provider_remove ); + } ); + + // Copy input text to clipboard. + $( '.wp-mail-smtp-setting-copy', app.settingsForm ).on( 'click', function( e ) { + e.preventDefault(); + + var target = $( '#' + $( this ).data( 'source_id' ) ).get( 0 ); + + target.select(); + document.execCommand( 'Copy' ); + + var $buttonIcon = $( this ).find( '.dashicons' ); + + $buttonIcon + .removeClass( 'dashicons-admin-page' ) + .addClass( 'wp-mail-smtp-dashicons-yes-alt-green wp-mail-smtp-success wp-mail-smtp-animate' ); + + setTimeout( + function() { + $buttonIcon + .removeClass( 'wp-mail-smtp-dashicons-yes-alt-green wp-mail-smtp-success wp-mail-smtp-animate' ) + .addClass( 'dashicons-admin-page' ); + }, + 1000 + ); + } ); + + // Notice bar: click on the dissmiss button. + $( '#wp-mail-smtp-notice-bar' ).on( 'click', '.dismiss', function() { + var $notice = $( this ).closest( '#wp-mail-smtp-notice-bar' ); + + $notice.addClass( 'out' ); + setTimeout( + function() { + $notice.remove(); + }, + 300 + ); + + $.post( + ajaxurl, + { + action: 'wp_mail_smtp_notice_bar_dismiss', + nonce: wp_mail_smtp.nonce, + } + ); + } ); + + app.triggerExitNotice(); + app.beforeSaveChecks(); + + // Register change event to show/hide plugin supported settings for currently selected mailer. + $( '.js-wp-mail-smtp-setting-mailer-radio-input', app.settingsForm ).on( 'change', this.processMailerSettingsOnChange ); + + // Disable multiple click on the Email Test tab submit button and display a loader icon. + $( '.wp-mail-smtp-tab-tools-test #email-test-form' ).on( 'submit', function() { + var $button = $( this ).find( '.wp-mail-smtp-btn' ); + + $button.attr( 'disabled', true ); + $button.find( 'span' ).hide(); + $button.find( '.wp-mail-smtp-loading' ).show(); + } ); + + $( '#wp-mail-smtp-setting-gmail-one_click_setup_enabled-lite' ).on( 'click', function( e ) { + e.preventDefault(); + + app.education.gmailOneClickSetupUpgrade(); + } ); + + $( '#wp-mail-smtp-setting-misc-rate_limit-lite' ).on( 'click', function( e ) { + e.preventDefault(); + + app.education.rateLimitUpgrade(); + } ); + + // Obfuscated fields + $( '.wp-mail-smtp-btn[data-clear-field]' ).on( 'click', function( e ) { + var $button = $( this ); + var fieldId = $button.attr( 'data-clear-field' ); + var $field = $( `#${fieldId}` ); + + $field.prop( 'disabled', false ); + $field.attr( 'name', $field.attr( 'data-name' ) ); + $field.removeAttr( 'value' ); + $field.focus(); + $button.remove(); + } ); + + $( '.email_test_tab_removal_notice' ).on( 'click', '.notice-dismiss', function() { + var $button = $( this ); + + $.ajax( { + url: ajaxurl, + dataType: 'json', + type: 'POST', + data: { + action: 'wp_mail_smtp_ajax', + nonce: wp_mail_smtp.nonce, + task: 'email_test_tab_removal_notice_dismiss', + }, + beforeSend: function() { + $button.prop( 'disabled', true ); + }, + } ); + } ); + }, + + education: { + upgradeMailer: function( $input ) { + + var mailerName = $input.data( 'title' ).trim(); + + app.education.upgradeModal( + wp_mail_smtp.education.upgrade_title.replace( /%name%/g, mailerName ), + wp_mail_smtp.education.upgrade_content.replace( /%name%/g, mailerName ), + $input.val() + ); + }, + + gmailOneClickSetupUpgrade: function() { + + app.education.upgradeModal( + wp_mail_smtp.education.gmail.one_click_setup_upgrade_title, + wp_mail_smtp.education.gmail.one_click_setup_upgrade_content, + 'gmail-one-click-setup' + ); + }, + + rateLimitUpgrade: function() { + + app.education.upgradeModal( + wp_mail_smtp.education.rate_limit.upgrade_title, + wp_mail_smtp.education.rate_limit.upgrade_content, + 'rate-limit-setting' + ); + }, + + upgradeModal: function( title, content, upgradeUrlUtmContent ) { + + $.alert( { + backgroundDismiss: true, + escapeKey: true, + animationBounce: 1, + type: 'blue', + closeIcon: true, + title: title, + icon: '">
' + wp_mail_smtp.education.upgrade_icon_lock + '' + wp_mail_smtp.education.upgrade_bonus + wp_mail_smtp.education.upgrade_doc + '' ); + this.$body.addClass( 'wp-mail-smtp-upgrade-mailer-education-modal' ); + }, + buttons: { + confirm: { + text: wp_mail_smtp.education.upgrade_button, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + action: function() { + var appendChar = /(\?)/.test( wp_mail_smtp.education.upgrade_url ) ? '&' : '?', + upgradeURL = wp_mail_smtp.education.upgrade_url + appendChar + 'utm_content=' + encodeURIComponent( upgradeUrlUtmContent ); + + window.open( upgradeURL, '_blank' ); + } + } + } + } ); + } + }, + + /** + * Individual mailers specific js code. + * + * @since 1.6.0 + */ + mailers: { + smtp: { + bindActions: function() { + + // Hide SMTP-specific user/pass when Auth disabled. + $( '#wp-mail-smtp-setting-smtp-auth' ).on( 'change', function() { + $( '#wp-mail-smtp-setting-row-smtp-user, #wp-mail-smtp-setting-row-smtp-pass' ).toggleClass( 'inactive' ); + } ); + + // Port default values based on encryption type. + $( '#wp-mail-smtp-setting-row-smtp-encryption input' ).on( 'change', function() { + + var $input = $( this ), + $smtpPort = $( '#wp-mail-smtp-setting-smtp-port', app.settingsForm ); + + if ( 'tls' === $input.val() ) { + $smtpPort.val( '587' ); + $( '#wp-mail-smtp-setting-row-smtp-autotls' ).addClass( 'inactive' ); + } else if ( 'ssl' === $input.val() ) { + $smtpPort.val( '465' ); + $( '#wp-mail-smtp-setting-row-smtp-autotls' ).removeClass( 'inactive' ); + } else { + $smtpPort.val( '25' ); + $( '#wp-mail-smtp-setting-row-smtp-autotls' ).removeClass( 'inactive' ); + } + } ); + } + } + }, + + /** + * Exit notice JS code when plugin settings are not saved. + * + * @since 1.9.0 + */ + triggerExitNotice: function() { + + var $settingPages = $( '.wp-mail-smtp-page-general' ); + + // Display an exit notice, if settings are not saved. + $( window ).on( 'beforeunload', function() { + if ( app.pluginSettingsChanged ) { + return wp_mail_smtp.text_settings_not_saved; + } + } ); + + // Set settings changed attribute, if any input was changed. + $( ':input:not( #wp-mail-smtp-setting-license-key, .wp-mail-smtp-not-form-input, #wp-mail-smtp-setting-gmail-one_click_setup_enabled, #wp-mail-smtp-setting-outlook-one_click_setup_enabled )', $settingPages ).on( 'change', function() { + app.pluginSettingsChanged = true; + } ); + + // Clear the settings changed attribute, if the settings are about to be saved. + $( 'form', $settingPages ).on( 'submit', function() { + app.pluginSettingsChanged = false; + } ); + }, + + /** + * Perform any checks before the settings are saved. + * + * Checks: + * - warn users if they try to save the settings with the default (PHP) mailer selected. + * + * @since 2.1.0 + */ + beforeSaveChecks: function() { + + app.settingsForm.on( 'submit', function() { + if ( $( '.wp-mail-smtp-mailer input:checked', app.settingsForm ).val() === 'mail' ) { + var $thisForm = $( this ); + + $.alert( { + backgroundDismiss: false, + escapeKey: false, + animationBounce: 1, + type: 'orange', + icon: '">' + wp_mail_smtp.default_mailer_notice.icon_alt + ' 0 ? $overlap.offset().top + $overlap.height() + 85 : 0, + viewTop = $( window ).scrollTop(), + viewBottom = viewTop + $( window ).height(); + + if ( wpfooterBottom <= viewBottom && wpfooterTop >= viewTop && overlapBottom > viewBottom ) { + $flyoutMenu.addClass( 'out' ); + } else { + $flyoutMenu.removeClass( 'out' ); + } + }, 50 ) ); + + $( window ).trigger( 'scroll' ); + } + }; + + // Provide access to public functions/properties. + return app; +}( document, window, jQuery ) ); + +// Initialize. +WPMailSMTP.Admin.Settings.init(); diff --git a/wp-content/plugins/wp-mail-smtp/assets/js/smtp-admin.min.js b/wp-content/plugins/wp-mail-smtp/assets/js/smtp-admin.min.js new file mode 100755 index 00000000..b48efd30 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/js/smtp-admin.min.js @@ -0,0 +1 @@ +"use strict";var WPMailSMTP=window.WPMailSMTP||{};WPMailSMTP.Admin=WPMailSMTP.Admin||{},WPMailSMTP.Admin.Settings=WPMailSMTP.Admin.Settings||function(a,m,p){var n={pluginSettingsChanged:!1,init:function(){p(n.ready)},ready:function(){n.pageHolder=p(".wp-mail-smtp-tab-settings"),n.settingsForm=p(".wp-mail-smtp-connection-settings-form"),p("#screen-meta-links, #screen-meta").prependTo("#wp-mail-smtp-header-temp").show(),n.bindActions(),n.setJQueryConfirmDefaults(),n.initFlyoutMenu()},bindActions:function(){p(".wp-mail-smtp-mailer-image",n.settingsForm).on("click",function(){p(this).parents(".wp-mail-smtp-mailer").find("input").trigger("click")}),p(".wp-mail-smtp-mailer input",n.settingsForm).on("click",function(){var t=p(this);if(t.prop("disabled"))return t.hasClass("educate")&&n.education.upgradeMailer(t),!1;p(".wp-mail-smtp-mailer",n.settingsForm).removeClass("active"),p(this).parents(".wp-mail-smtp-mailer").addClass("active"),p(".wp-mail-smtp-mailer-option",n.settingsForm).addClass("hidden").removeClass("active"),p(".wp-mail-smtp-mailer-option-"+p(this).val(),n.settingsForm).addClass("active").removeClass("hidden")}),n.mailers.smtp.bindActions(),p("#wp-mail-smtp-pro-banner-dismiss",n.pageHolder).on("click",function(){p.ajax({url:ajaxurl,dataType:"json",type:"POST",data:{action:"wp_mail_smtp_ajax",task:"pro_banner_dismiss",nonce:wp_mail_smtp.nonce}}).always(function(){p("#wp-mail-smtp-pro-banner",n.pageHolder).fadeOut("fast")})}),p(".js-wp-mail-smtp-mailer-notice-dismiss",n.settingsForm).on("click",function(t){t.preventDefault();var e=p(this),i=e.parents(".inline-notice");if(e.hasClass("disabled"))return!1;p.ajax({url:ajaxurl,dataType:"json",type:"POST",data:{action:"wp_mail_smtp_ajax",nonce:wp_mail_smtp.nonce,task:"notice_dismiss",notice:i.data("notice"),mailer:i.data("mailer")},beforeSend:function(){e.addClass("disabled")}}).always(function(){i.fadeOut("fast",function(){e.removeClass("disabled")})})}),p("#wp-mail-smtp-debug .error-log-toggle").on("click",function(t){t.preventDefault(),p("#wp-mail-smtp-debug .error-log").slideToggle()}),p("#wp-mail-smtp-debug .error-log-copy").on("click",function(t){t.preventDefault();var e=p(this),i=p("#wp-mail-smtp-debug .error-log");i.is(":visible")||i.addClass("error-log-selection");t=a.createRange();t.selectNode(i[0]),m.getSelection().removeAllRanges(),m.getSelection().addRange(t),a.execCommand("Copy"),m.getSelection().removeAllRanges(),i.removeClass("error-log-selection"),e.addClass("error-log-copy-copied"),setTimeout(function(){e.removeClass("error-log-copy-copied")},1500)}),p(".js-wp-mail-smtp-provider-remove",n.settingsForm).on("click",function(){return confirm(wp_mail_smtp.text_provider_remove)}),p(".wp-mail-smtp-setting-copy",n.settingsForm).on("click",function(t){t.preventDefault(),p("#"+p(this).data("source_id")).get(0).select(),a.execCommand("Copy");var e=p(this).find(".dashicons");e.removeClass("dashicons-admin-page").addClass("wp-mail-smtp-dashicons-yes-alt-green wp-mail-smtp-success wp-mail-smtp-animate"),setTimeout(function(){e.removeClass("wp-mail-smtp-dashicons-yes-alt-green wp-mail-smtp-success wp-mail-smtp-animate").addClass("dashicons-admin-page")},1e3)}),p("#wp-mail-smtp-notice-bar").on("click",".dismiss",function(){var t=p(this).closest("#wp-mail-smtp-notice-bar");t.addClass("out"),setTimeout(function(){t.remove()},300),p.post(ajaxurl,{action:"wp_mail_smtp_notice_bar_dismiss",nonce:wp_mail_smtp.nonce})}),n.triggerExitNotice(),n.beforeSaveChecks(),p(".js-wp-mail-smtp-setting-mailer-radio-input",n.settingsForm).on("change",this.processMailerSettingsOnChange),p(".wp-mail-smtp-tab-tools-test #email-test-form").on("submit",function(){var t=p(this).find(".wp-mail-smtp-btn");t.attr("disabled",!0),t.find("span").hide(),t.find(".wp-mail-smtp-loading").show()}),p("#wp-mail-smtp-setting-gmail-one_click_setup_enabled-lite").on("click",function(t){t.preventDefault(),n.education.gmailOneClickSetupUpgrade()}),p("#wp-mail-smtp-setting-misc-rate_limit-lite").on("click",function(t){t.preventDefault(),n.education.rateLimitUpgrade()}),p(".wp-mail-smtp-btn[data-clear-field]").on("click",function(t){var e=p(this),i=e.attr("data-clear-field"),i=p(`#${i}`);i.prop("disabled",!1),i.attr("name",i.attr("data-name")),i.removeAttr("value"),i.focus(),e.remove()}),p(".email_test_tab_removal_notice").on("click",".notice-dismiss",function(){var t=p(this);p.ajax({url:ajaxurl,dataType:"json",type:"POST",data:{action:"wp_mail_smtp_ajax",nonce:wp_mail_smtp.nonce,task:"email_test_tab_removal_notice_dismiss"},beforeSend:function(){t.prop("disabled",!0)}})})},education:{upgradeMailer:function(t){var e=t.data("title").trim();n.education.upgradeModal(wp_mail_smtp.education.upgrade_title.replace(/%name%/g,e),wp_mail_smtp.education.upgrade_content.replace(/%name%/g,e),t.val())},gmailOneClickSetupUpgrade:function(){n.education.upgradeModal(wp_mail_smtp.education.gmail.one_click_setup_upgrade_title,wp_mail_smtp.education.gmail.one_click_setup_upgrade_content,"gmail-one-click-setup")},rateLimitUpgrade:function(){n.education.upgradeModal(wp_mail_smtp.education.rate_limit.upgrade_title,wp_mail_smtp.education.rate_limit.upgrade_content,"rate-limit-setting")},upgradeModal:function(t,e,i){p.alert({backgroundDismiss:!0,escapeKey:!0,animationBounce:1,type:"blue",closeIcon:!0,title:t,icon:'">'+wp_mail_smtp.education.upgrade_icon_lock+''+wp_mail_smtp.education.upgrade_bonus+wp_mail_smtp.education.upgrade_doc+""),this.$body.addClass("wp-mail-smtp-upgrade-mailer-education-modal")},buttons:{confirm:{text:wp_mail_smtp.education.upgrade_button,btnClass:"btn-confirm",keys:["enter"],action:function(){var t=/(\?)/.test(wp_mail_smtp.education.upgrade_url)?"&":"?",t=wp_mail_smtp.education.upgrade_url+t+"utm_content="+encodeURIComponent(i);m.open(t,"_blank")}}}})}},mailers:{smtp:{bindActions:function(){p("#wp-mail-smtp-setting-smtp-auth").on("change",function(){p("#wp-mail-smtp-setting-row-smtp-user, #wp-mail-smtp-setting-row-smtp-pass").toggleClass("inactive")}),p("#wp-mail-smtp-setting-row-smtp-encryption input").on("change",function(){var t=p(this),e=p("#wp-mail-smtp-setting-smtp-port",n.settingsForm);"tls"===t.val()?(e.val("587"),p("#wp-mail-smtp-setting-row-smtp-autotls").addClass("inactive")):("ssl"===t.val()?e.val("465"):e.val("25"),p("#wp-mail-smtp-setting-row-smtp-autotls").removeClass("inactive"))})}}},triggerExitNotice:function(){var t=p(".wp-mail-smtp-page-general");p(m).on("beforeunload",function(){if(n.pluginSettingsChanged)return wp_mail_smtp.text_settings_not_saved}),p(":input:not( #wp-mail-smtp-setting-license-key, .wp-mail-smtp-not-form-input, #wp-mail-smtp-setting-gmail-one_click_setup_enabled, #wp-mail-smtp-setting-outlook-one_click_setup_enabled )",t).on("change",function(){n.pluginSettingsChanged=!0}),p("form",t).on("submit",function(){n.pluginSettingsChanged=!1})},beforeSaveChecks:function(){n.settingsForm.on("submit",function(){if("mail"===p(".wp-mail-smtp-mailer input:checked",n.settingsForm).val()){var t=p(this);return p.alert({backgroundDismiss:!1,escapeKey:!1,animationBounce:1,type:"orange",icon:'">'+wp_mail_smtp.default_mailer_notice.icon_alt+' 1 ) { + --count; + el.$adminBarCounter.html( '' + count + '' ); + } else { + el.$adminBarCounter.remove(); + } + + // Remove notification. + var $nextMessage = el.$nextMessage.length < 1 ? el.$prevMessage : el.$nextMessage; + + if ( $nextMessage.length === 0 ) { + el.$notifications.remove(); + } else { + el.$currentMessage.remove(); + $nextMessage.addClass( 'current' ); + app.updateNavigation(); + } + } ); + }, + + /** + * Click on the Next notification button. + * + * @since 2.3.0 + * + * @param {object} event Event object. + */ + navNext: function( event ) { + + if ( el.$nextButton.hasClass( 'disabled' ) ) { + return; + } + + el.$currentMessage.removeClass( 'current' ); + el.$nextMessage.addClass( 'current' ); + + app.updateNavigation(); + }, + + /** + * Click on the Previous notification button. + * + * @since 2.3.0 + * + * @param {object} event Event object. + */ + navPrev: function( event ) { + + if ( el.$prevButton.hasClass( 'disabled' ) ) { + return; + } + + el.$currentMessage.removeClass( 'current' ); + el.$prevMessage.addClass( 'current' ); + + app.updateNavigation(); + }, + + /** + * Update navigation buttons. + * + * @since 2.3.0 + */ + updateNavigation: function() { + + el.$currentMessage = el.$notifications.find( '.wp-mail-smtp-notifications-message.current' ); + el.$nextMessage = el.$currentMessage.next( '.wp-mail-smtp-notifications-message' ); + el.$prevMessage = el.$currentMessage.prev( '.wp-mail-smtp-notifications-message' ); + + if ( el.$nextMessage.length === 0 ) { + el.$nextButton.addClass( 'disabled' ); + } else { + el.$nextButton.removeClass( 'disabled' ); + } + + if ( el.$prevMessage.length === 0 ) { + el.$prevButton.addClass( 'disabled' ); + } else { + el.$prevButton.removeClass( 'disabled' ); + } + }, + }; + + return app; + +}( document, window, jQuery ) ); + +// Initialize. +WPMailSMTPAdminNotifications.init(); diff --git a/wp-content/plugins/wp-mail-smtp/assets/js/smtp-notifications.min.js b/wp-content/plugins/wp-mail-smtp/assets/js/smtp-notifications.min.js new file mode 100755 index 00000000..43ee87af --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/js/smtp-notifications.min.js @@ -0,0 +1 @@ +"use strict";var WPMailSMTPAdminNotifications=window.WPMailSMTPAdminNotifications||function(t){var a={$notifications:t("#wp-mail-smtp-notifications"),$nextButton:t("#wp-mail-smtp-notifications .navigation .next"),$prevButton:t("#wp-mail-smtp-notifications .navigation .prev"),$adminBarCounter:t("#wp-admin-bar-wp-mail-smtp-menu .wp-mail-smtp-admin-bar-menu-notification-counter")},i={init:function(){t(i.ready)},ready:function(){i.updateNavigation(),i.events()},events:function(){a.$notifications.on("click",".dismiss",i.dismiss).on("click",".next",i.navNext).on("click",".prev",i.navPrev)},dismiss:function(e){var n;0!==a.$currentMessage.length&&(n={action:"wp_mail_smtp_notification_dismiss",nonce:wp_mail_smtp.nonce,id:a.$currentMessage.data("message-id")},t.post(ajaxurl,n,function(e){e.success&&(1<(e=parseInt(a.$adminBarCounter.text(),10))?a.$adminBarCounter.html(""+--e+""):a.$adminBarCounter.remove(),0===(e=a.$nextMessage.length<1?a.$prevMessage:a.$nextMessage).length?a.$notifications.remove():(a.$currentMessage.remove(),e.addClass("current"),i.updateNavigation()))}))},navNext:function(e){a.$nextButton.hasClass("disabled")||(a.$currentMessage.removeClass("current"),a.$nextMessage.addClass("current"),i.updateNavigation())},navPrev:function(e){a.$prevButton.hasClass("disabled")||(a.$currentMessage.removeClass("current"),a.$prevMessage.addClass("current"),i.updateNavigation())},updateNavigation:function(){a.$currentMessage=a.$notifications.find(".wp-mail-smtp-notifications-message.current"),a.$nextMessage=a.$currentMessage.next(".wp-mail-smtp-notifications-message"),a.$prevMessage=a.$currentMessage.prev(".wp-mail-smtp-notifications-message"),0===a.$nextMessage.length?a.$nextButton.addClass("disabled"):a.$nextButton.removeClass("disabled"),0===a.$prevMessage.length?a.$prevButton.addClass("disabled"):a.$prevButton.removeClass("disabled")}};return i}((document,window,jQuery));WPMailSMTPAdminNotifications.init(); \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/js/smtp-tools-debug-events.js b/wp-content/plugins/wp-mail-smtp/assets/js/smtp-tools-debug-events.js new file mode 100755 index 00000000..9b4ae8d3 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/js/smtp-tools-debug-events.js @@ -0,0 +1,360 @@ +/* global wp_mail_smtp_tools_debug_events, ajaxurl, flatpickr */ +/** + * WPMailSMTP Debug Events functionality. + * + * @since 3.0.0 + */ + +'use strict'; + +var WPMailSmtpDebugEvents = window.WPMailSmtpDebugEvents || ( function( document, window, $ ) { + + /** + * Elements. + * + * @since 3.0.0 + * + * @type {object} + */ + var el = { + $debugEventsPage: $( '.wp-mail-smtp-tab-tools-debug-events' ), + $dateFlatpickr: $( '.wp-mail-smtp-filter-date-selector' ), + }; + + /** + * Public functions and properties. + * + * @since 3.0.0 + * + * @type {object} + */ + var app = { + + /** + * Start the engine. + * + * @since 3.0.0 + */ + init: function() { + + $( app.ready ); + }, + + /** + * Document ready. + * + * @since 3.0.0 + */ + ready: function() { + + app.initDateRange(); + app.events(); + + // Open debug event popup from the query string. + var searchParams = new URLSearchParams( location.search ); + + if ( searchParams.has( 'debug_event_id' ) ) { + app.openDebugEventPopup( searchParams.get( 'debug_event_id' ) ); + } + }, + + /** + * Register JS events. + * + * @since 3.0.0 + */ + events: function() { + + el.$debugEventsPage.on( 'click', '#wp-mail-smtp-reset-filter .reset', app.resetFilter ); + el.$debugEventsPage.on( 'click', '#wp-mail-smtp-delete-all-debug-events-button', app.deleteAllDebugEvents ); + el.$debugEventsPage.on( 'click', '.js-wp-mail-smtp-debug-event-preview', app.eventClicked ); + }, + + /** + * Init Flatpickr at Date Range field. + * + * @since 3.0.0 + */ + initDateRange: function() { + + var langCode = wp_mail_smtp_tools_debug_events.lang_code, + flatpickrLocale = { + rangeSeparator: ' - ', + }; + + if ( + flatpickr !== 'undefined' && + Object.prototype.hasOwnProperty.call( flatpickr, 'l10ns' ) && + Object.prototype.hasOwnProperty.call( flatpickr.l10ns, langCode ) + ) { + flatpickrLocale = flatpickr.l10ns[ langCode ]; + flatpickrLocale.rangeSeparator = ' - '; + } + + el.$dateFlatpickr.flatpickr( { + altInput : true, + altFormat : 'M j, Y', + dateFormat: 'Y-m-d', + locale : flatpickrLocale, + mode : 'range' + } ); + }, + + /** + * Reset filter handler. + * + * @since 3.0.0 + */ + resetFilter: function() { + + var $form = $( this ).parents( 'form' ); + + $form.find( $( this ).data( 'scope' ) ).find( 'input,select' ).each( function() { + + var $this = $( this ); + if ( app.isIgnoredForResetInput( $this ) ) { + return; + } + app.resetInput( $this ); + } ); + + // Submit the form. + $form.submit(); + }, + + /** + * Reset input. + * + * @since 3.0.0 + * + * @param {object} $input Input element. + */ + resetInput: function( $input ) { + + switch ( $input.prop( 'tagName' ).toLowerCase() ) { + case 'input': + $input.val( '' ); + break; + case 'select': + $input.val( $input.find( 'option' ).first().val() ); + break; + } + }, + + /** + * Input is ignored for reset. + * + * @since 3.0.0 + * + * @param {object} $input Input element. + * + * @returns {boolean} Is ignored. + */ + isIgnoredForResetInput: function( $input ) { + + return [ 'submit', 'hidden' ].indexOf( ( $input.attr( 'type' ) || '' ).toLowerCase() ) !== -1 && + ! $input.hasClass( 'flatpickr-input' ); + }, + + /** + * Process the click on the delete all debug events button. + * + * @since 3.0.0 + * + * @param {object} event jQuery event. + */ + deleteAllDebugEvents: function( event ) { + + event.preventDefault(); + + var $btn = $( event.target ); + + $.confirm( { + backgroundDismiss: false, + escapeKey: true, + animationBounce: 1, + closeIcon: true, + type: 'orange', + icon: app.getModalIcon( 'exclamation-circle-solid-orange' ), + title: wp_mail_smtp_tools_debug_events.texts.notice_title, + content: wp_mail_smtp_tools_debug_events.texts.delete_all_notice, + buttons: { + confirm: { + text: wp_mail_smtp_tools_debug_events.texts.yes, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + action: function() { + app.executeAllDebugEventsDeletion( $btn ); + } + }, + cancel: { + text: wp_mail_smtp_tools_debug_events.texts.cancel, + btnClass: 'btn-cancel', + } + } + } ); + }, + + /** + * Process the click on the event item. + * + * @since 3.0.0 + * + * @param {object} event jQuery event. + */ + eventClicked: function( event ) { + + event.preventDefault(); + + app.openDebugEventPopup( $( this ).data( 'event-id' ) ); + }, + + /** + * Open debug event popup. + * + * @since 3.5.0 + * + * @param {int} eventId Debug event ID. + */ + openDebugEventPopup: function( eventId ) { + + var data = { + action: 'wp_mail_smtp_debug_event_preview', + id: eventId, + nonce: $( '#wp-mail-smtp-debug-events-nonce', el.$debugEventsPage ).val() + }; + + var popup = $.alert( { + backgroundDismiss: true, + escapeKey: true, + animationBounce: 1, + type: 'blue', + icon: app.getModalIcon( 'info-circle-blue' ), + title: false, + content: wp_mail_smtp_tools_debug_events.loader, + boxWidth: '550px', + buttons: { + confirm: { + text: wp_mail_smtp_tools_debug_events.texts.close, + btnClass: 'btn-confirm', + keys: [ 'enter' ] + } + }, + onOpenBefore: function() { + this.$contentPane.addClass( 'no-scroll' ); + } + } ); + + $.post( ajaxurl, data, function( response ) { + if ( response.success ) { + popup.setTitle( response.data.title ); + popup.setContent( response.data.content ); + } else { + popup.setIcon( app.getModalIcon( 'exclamation-circle-regular-red' ) ); + popup.setType( 'red' ); + popup.setContent( response.data ); + } + } ).fail( function() { + popup.setContent( wp_mail_smtp_tools_debug_events.texts.error_occurred ); + } ); + }, + + /** + * AJAX call for deleting all debug events. + * + * @since 3.0.0 + * + * @param {object} $btn jQuery object of the clicked button. + */ + executeAllDebugEventsDeletion: function( $btn ) { + + $btn.prop( 'disabled', true ); + + var data = { + action: 'wp_mail_smtp_delete_all_debug_events', + nonce: $( '#wp-mail-smtp-debug-events-nonce', el.$debugEventsPage ).val() + }; + + $.post( ajaxurl, data, function( response ) { + var message = response.data, + icon, + type, + callback; + + if ( response.success ) { + icon = 'check-circle-solid-green'; + type = 'green'; + callback = function() { + location.reload(); + return false; + }; + } else { + icon = 'exclamation-circle-regular-red'; + type = 'red'; + } + + app.displayModal( message, icon, type, callback ); + $btn.prop( 'disabled', false ); + } ).fail( function() { + app.displayModal( wp_mail_smtp_tools_debug_events.texts.error_occurred, 'exclamation-circle-regular-red', 'red' ); + $btn.prop( 'disabled', false ); + } ); + }, + + /** + * Display the modal with provided text and icon. + * + * @since 3.0.0 + * + * @param {string} message The message to be displayed in the modal. + * @param {string} icon The icon name from /assets/images/font-awesome/ to be used in modal. + * @param {string} type The type of the message (red, green, orange, blue, purple, dark). + * @param {Function} actionCallback The action callback function. + */ + displayModal: function( message, icon, type, actionCallback ) { + + type = type || 'default'; + actionCallback = actionCallback || function() {}; + + $.alert( { + backgroundDismiss: true, + escapeKey: true, + animationBounce: 1, + type: type, + closeIcon: true, + title: false, + icon: icon ? app.getModalIcon( icon ) : '', + content: message, + buttons: { + confirm: { + text: wp_mail_smtp_tools_debug_events.texts.ok, + btnClass: 'wp-mail-smtp-btn wp-mail-smtp-btn-md', + keys: [ 'enter' ], + action: actionCallback + } + } + } ); + }, + + /** + * Returns prepared modal icon. + * + * @since 3.0.0 + * + * @param {string} icon The icon name from /assets/images/font-awesome/ to be used in modal. + * + * @returns {string} Modal icon HTML. + */ + getModalIcon: function( icon ) { + + return '">{let t=0;return()=>t++})();function s(t){return null==t}function n(t){if(Array.isArray&&Array.isArray(t))return!0;const e=Object.prototype.toString.call(t);return"[object"===e.slice(0,7)&&"Array]"===e.slice(-6)}function o(t){return null!==t&&"[object Object]"===Object.prototype.toString.call(t)}function a(t){return("number"==typeof t||t instanceof Number)&&isFinite(+t)}function r(t,e){return a(t)?t:e}function l(t,e){return void 0===t?e:t}const h=(t,e)=>"string"==typeof t&&t.endsWith("%")?parseFloat(t)/100:+t/e,c=(t,e)=>"string"==typeof t&&t.endsWith("%")?parseFloat(t)/100*e:+t;function d(t,e,i){if(t&&"function"==typeof t.call)return t.apply(i,e)}function u(t,e,i,s){let a,r,l;if(n(t))if(r=t.length,s)for(a=r-1;a>=0;a--)e.call(i,t[a],a);else for(a=0;at,x:t=>t.x,y:t=>t.y};function v(t){const e=t.split("."),i=[];let s="";for(const t of e)s+=t,s.endsWith("\\")?s=s.slice(0,-1)+".":(i.push(s),s="");return i}function M(t,e){const i=y[e]||(y[e]=function(t){const e=v(t);return t=>{for(const i of e){if(""===i)break;t=t&&t[i]}return t}}(e));return i(t)}function w(t){return t.charAt(0).toUpperCase()+t.slice(1)}const k=t=>void 0!==t,S=t=>"function"==typeof t,P=(t,e)=>{if(t.size!==e.size)return!1;for(const i of t)if(!e.has(i))return!1;return!0};function D(t){return"mouseup"===t.type||"click"===t.type||"contextmenu"===t.type}const C=Math.PI,O=2*C,A=O+C,T=Number.POSITIVE_INFINITY,L=C/180,E=C/2,R=C/4,I=2*C/3,z=Math.log10,F=Math.sign;function V(t,e,i){return Math.abs(t-e)t-e)).pop(),e}function N(t){return!function(t){return"symbol"==typeof t||"object"==typeof t&&null!==t&&!(Symbol.toPrimitive in t||"toString"in t||"valueOf"in t)}(t)&&!isNaN(parseFloat(t))&&isFinite(t)}function H(t,e){const i=Math.round(t);return i-e<=t&&i+e>=t}function j(t,e,i){let s,n,o;for(s=0,n=t.length;sl&&h=Math.min(e,i)-s&&t<=Math.max(e,i)+s}function et(t,e,i){i=i||(i=>t[i]1;)s=o+n>>1,i(s)?o=s:n=s;return{lo:o,hi:n}}const it=(t,e,i,s)=>et(t,i,s?s=>{const n=t[s][e];return nt[s][e]et(t,i,(s=>t[s][e]>=i));function nt(t,e,i){let s=0,n=t.length;for(;ss&&t[n-1]>i;)n--;return s>0||n{const i="_onData"+w(e),s=t[e];Object.defineProperty(t,e,{configurable:!0,enumerable:!1,value(...e){const n=s.apply(this,e);return t._chartjs.listeners.forEach((t=>{"function"==typeof t[i]&&t[i](...e)})),n}})})))}function rt(t,e){const i=t._chartjs;if(!i)return;const s=i.listeners,n=s.indexOf(e);-1!==n&&s.splice(n,1),s.length>0||(ot.forEach((e=>{delete t[e]})),delete t._chartjs)}function lt(t){const e=new Set(t);return e.size===t.length?t:Array.from(e)}const ht="undefined"==typeof window?function(t){return t()}:window.requestAnimationFrame;function ct(t,e){let i=[],s=!1;return function(...n){i=n,s||(s=!0,ht.call(window,(()=>{s=!1,t.apply(e,i)})))}}function dt(t,e){let i;return function(...s){return e?(clearTimeout(i),i=setTimeout(t,e,s)):t.apply(this,s),e}}const ut=t=>"start"===t?"left":"end"===t?"right":"center",ft=(t,e,i)=>"start"===t?e:"end"===t?i:(e+i)/2,gt=(t,e,i,s)=>t===(s?"left":"right")?i:"center"===t?(e+i)/2:e;function pt(t,e,i){const n=e.length;let o=0,a=n;if(t._sorted){const{iScale:r,vScale:l,_parsed:h}=t,c=t.dataset&&t.dataset.options?t.dataset.options.spanGaps:null,d=r.axis,{min:u,max:f,minDefined:g,maxDefined:p}=r.getUserBounds();if(g){if(o=Math.min(it(h,d,u).lo,i?n:it(e,d,r.getPixelForValue(u)).lo),c){const t=h.slice(0,o+1).reverse().findIndex((t=>!s(t[l.axis])));o-=Math.max(0,t)}o=J(o,0,n-1)}if(p){let t=Math.max(it(h,r.axis,f,!0).hi+1,i?0:it(e,d,r.getPixelForValue(f),!0).hi+1);if(c){const e=h.slice(t-1).findIndex((t=>!s(t[l.axis])));t+=Math.max(0,e)}a=J(t,o,n)-o}else a=n-o}return{start:o,count:a}}function mt(t){const{xScale:e,yScale:i,_scaleRanges:s}=t,n={xmin:e.min,xmax:e.max,ymin:i.min,ymax:i.max};if(!s)return t._scaleRanges=n,!0;const o=s.xmin!==e.min||s.xmax!==e.max||s.ymin!==i.min||s.ymax!==i.max;return Object.assign(s,n),o}class xt{constructor(){this._request=null,this._charts=new Map,this._running=!1,this._lastDate=void 0}_notify(t,e,i,s){const n=e.listeners[s],o=e.duration;n.forEach((s=>s({chart:t,initial:e.initial,numSteps:o,currentStep:Math.min(i-e.start,o)})))}_refresh(){this._request||(this._running=!0,this._request=ht.call(window,(()=>{this._update(),this._request=null,this._running&&this._refresh()})))}_update(t=Date.now()){let e=0;this._charts.forEach(((i,s)=>{if(!i.running||!i.items.length)return;const n=i.items;let o,a=n.length-1,r=!1;for(;a>=0;--a)o=n[a],o._active?(o._total>i.duration&&(i.duration=o._total),o.tick(t),r=!0):(n[a]=n[n.length-1],n.pop());r&&(s.draw(),this._notify(s,i,t,"progress")),n.length||(i.running=!1,this._notify(s,i,t,"complete"),i.initial=!1),e+=n.length})),this._lastDate=t,0===e&&(this._running=!1)}_getAnims(t){const e=this._charts;let i=e.get(t);return i||(i={running:!1,initial:!0,items:[],listeners:{complete:[],progress:[]}},e.set(t,i)),i}listen(t,e,i){this._getAnims(t).listeners[e].push(i)}add(t,e){e&&e.length&&this._getAnims(t).items.push(...e)}has(t){return this._getAnims(t).items.length>0}start(t){const e=this._charts.get(t);e&&(e.running=!0,e.start=Date.now(),e.duration=e.items.reduce(((t,e)=>Math.max(t,e._duration)),0),this._refresh())}running(t){if(!this._running)return!1;const e=this._charts.get(t);return!!(e&&e.running&&e.items.length)}stop(t){const e=this._charts.get(t);if(!e||!e.items.length)return;const i=e.items;let s=i.length-1;for(;s>=0;--s)i[s].cancel();e.items=[],this._notify(t,e,Date.now(),"complete")}remove(t){return this._charts.delete(t)}}var bt=new xt; + /*! + * @kurkle/color v0.3.2 + * https://github.com/kurkle/color#readme + * (c) 2023 Jukka Kurkela + * Released under the MIT License + */function _t(t){return t+.5|0}const yt=(t,e,i)=>Math.max(Math.min(t,i),e);function vt(t){return yt(_t(2.55*t),0,255)}function Mt(t){return yt(_t(255*t),0,255)}function wt(t){return yt(_t(t/2.55)/100,0,1)}function kt(t){return yt(_t(100*t),0,100)}const St={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,A:10,B:11,C:12,D:13,E:14,F:15,a:10,b:11,c:12,d:13,e:14,f:15},Pt=[..."0123456789ABCDEF"],Dt=t=>Pt[15&t],Ct=t=>Pt[(240&t)>>4]+Pt[15&t],Ot=t=>(240&t)>>4==(15&t);function At(t){var e=(t=>Ot(t.r)&&Ot(t.g)&&Ot(t.b)&&Ot(t.a))(t)?Dt:Ct;return t?"#"+e(t.r)+e(t.g)+e(t.b)+((t,e)=>t<255?e(t):"")(t.a,e):void 0}const Tt=/^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;function Lt(t,e,i){const s=e*Math.min(i,1-i),n=(e,n=(e+t/30)%12)=>i-s*Math.max(Math.min(n-3,9-n,1),-1);return[n(0),n(8),n(4)]}function Et(t,e,i){const s=(s,n=(s+t/60)%6)=>i-i*e*Math.max(Math.min(n,4-n,1),0);return[s(5),s(3),s(1)]}function Rt(t,e,i){const s=Lt(t,1,.5);let n;for(e+i>1&&(n=1/(e+i),e*=n,i*=n),n=0;n<3;n++)s[n]*=1-e-i,s[n]+=e;return s}function It(t){const e=t.r/255,i=t.g/255,s=t.b/255,n=Math.max(e,i,s),o=Math.min(e,i,s),a=(n+o)/2;let r,l,h;return n!==o&&(h=n-o,l=a>.5?h/(2-n-o):h/(n+o),r=function(t,e,i,s,n){return t===n?(e-i)/s+(e>16&255,o>>8&255,255&o]}return t}(),Ht.transparent=[0,0,0,0]);const e=Ht[t.toLowerCase()];return e&&{r:e[0],g:e[1],b:e[2],a:4===e.length?e[3]:255}}const $t=/^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/;const Yt=t=>t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055,Ut=t=>t<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4);function Xt(t,e,i){if(t){let s=It(t);s[e]=Math.max(0,Math.min(s[e]+s[e]*i,0===e?360:1)),s=Ft(s),t.r=s[0],t.g=s[1],t.b=s[2]}}function qt(t,e){return t?Object.assign(e||{},t):t}function Kt(t){var e={r:0,g:0,b:0,a:255};return Array.isArray(t)?t.length>=3&&(e={r:t[0],g:t[1],b:t[2],a:255},t.length>3&&(e.a=Mt(t[3]))):(e=qt(t,{r:0,g:0,b:0,a:1})).a=Mt(e.a),e}function Gt(t){return"r"===t.charAt(0)?function(t){const e=$t.exec(t);let i,s,n,o=255;if(e){if(e[7]!==i){const t=+e[7];o=e[8]?vt(t):yt(255*t,0,255)}return i=+e[1],s=+e[3],n=+e[5],i=255&(e[2]?vt(i):yt(i,0,255)),s=255&(e[4]?vt(s):yt(s,0,255)),n=255&(e[6]?vt(n):yt(n,0,255)),{r:i,g:s,b:n,a:o}}}(t):Bt(t)}class Zt{constructor(t){if(t instanceof Zt)return t;const e=typeof t;let i;var s,n,o;"object"===e?i=Kt(t):"string"===e&&(o=(s=t).length,"#"===s[0]&&(4===o||5===o?n={r:255&17*St[s[1]],g:255&17*St[s[2]],b:255&17*St[s[3]],a:5===o?17*St[s[4]]:255}:7!==o&&9!==o||(n={r:St[s[1]]<<4|St[s[2]],g:St[s[3]]<<4|St[s[4]],b:St[s[5]]<<4|St[s[6]],a:9===o?St[s[7]]<<4|St[s[8]]:255})),i=n||jt(t)||Gt(t)),this._rgb=i,this._valid=!!i}get valid(){return this._valid}get rgb(){var t=qt(this._rgb);return t&&(t.a=wt(t.a)),t}set rgb(t){this._rgb=Kt(t)}rgbString(){return this._valid?(t=this._rgb)&&(t.a<255?`rgba(${t.r}, ${t.g}, ${t.b}, ${wt(t.a)})`:`rgb(${t.r}, ${t.g}, ${t.b})`):void 0;var t}hexString(){return this._valid?At(this._rgb):void 0}hslString(){return this._valid?function(t){if(!t)return;const e=It(t),i=e[0],s=kt(e[1]),n=kt(e[2]);return t.a<255?`hsla(${i}, ${s}%, ${n}%, ${wt(t.a)})`:`hsl(${i}, ${s}%, ${n}%)`}(this._rgb):void 0}mix(t,e){if(t){const i=this.rgb,s=t.rgb;let n;const o=e===n?.5:e,a=2*o-1,r=i.a-s.a,l=((a*r==-1?a:(a+r)/(1+a*r))+1)/2;n=1-l,i.r=255&l*i.r+n*s.r+.5,i.g=255&l*i.g+n*s.g+.5,i.b=255&l*i.b+n*s.b+.5,i.a=o*i.a+(1-o)*s.a,this.rgb=i}return this}interpolate(t,e){return t&&(this._rgb=function(t,e,i){const s=Ut(wt(t.r)),n=Ut(wt(t.g)),o=Ut(wt(t.b));return{r:Mt(Yt(s+i*(Ut(wt(e.r))-s))),g:Mt(Yt(n+i*(Ut(wt(e.g))-n))),b:Mt(Yt(o+i*(Ut(wt(e.b))-o))),a:t.a+i*(e.a-t.a)}}(this._rgb,t._rgb,e)),this}clone(){return new Zt(this.rgb)}alpha(t){return this._rgb.a=Mt(t),this}clearer(t){return this._rgb.a*=1-t,this}greyscale(){const t=this._rgb,e=_t(.3*t.r+.59*t.g+.11*t.b);return t.r=t.g=t.b=e,this}opaquer(t){return this._rgb.a*=1+t,this}negate(){const t=this._rgb;return t.r=255-t.r,t.g=255-t.g,t.b=255-t.b,this}lighten(t){return Xt(this._rgb,2,t),this}darken(t){return Xt(this._rgb,2,-t),this}saturate(t){return Xt(this._rgb,1,t),this}desaturate(t){return Xt(this._rgb,1,-t),this}rotate(t){return function(t,e){var i=It(t);i[0]=Vt(i[0]+e),i=Ft(i),t.r=i[0],t.g=i[1],t.b=i[2]}(this._rgb,t),this}}function Jt(t){if(t&&"object"==typeof t){const e=t.toString();return"[object CanvasPattern]"===e||"[object CanvasGradient]"===e}return!1}function Qt(t){return Jt(t)?t:new Zt(t)}function te(t){return Jt(t)?t:new Zt(t).saturate(.5).darken(.1).hexString()}const ee=["x","y","borderWidth","radius","tension"],ie=["color","borderColor","backgroundColor"];const se=new Map;function ne(t,e,i){return function(t,e){e=e||{};const i=t+JSON.stringify(e);let s=se.get(i);return s||(s=new Intl.NumberFormat(t,e),se.set(i,s)),s}(e,i).format(t)}const oe={values:t=>n(t)?t:""+t,numeric(t,e,i){if(0===t)return"0";const s=this.chart.options.locale;let n,o=t;if(i.length>1){const e=Math.max(Math.abs(i[0].value),Math.abs(i[i.length-1].value));(e<1e-4||e>1e15)&&(n="scientific"),o=function(t,e){let i=e.length>3?e[2].value-e[1].value:e[1].value-e[0].value;Math.abs(i)>=1&&t!==Math.floor(t)&&(i=t-Math.floor(t));return i}(t,i)}const a=z(Math.abs(o)),r=isNaN(a)?1:Math.max(Math.min(-1*Math.floor(a),20),0),l={notation:n,minimumFractionDigits:r,maximumFractionDigits:r};return Object.assign(l,this.options.ticks.format),ne(t,s,l)},logarithmic(t,e,i){if(0===t)return"0";const s=i[e].significand||t/Math.pow(10,Math.floor(z(t)));return[1,2,3,5,10,15].includes(s)||e>.8*i.length?oe.numeric.call(this,t,e,i):""}};var ae={formatters:oe};const re=Object.create(null),le=Object.create(null);function he(t,e){if(!e)return t;const i=e.split(".");for(let e=0,s=i.length;et.chart.platform.getDevicePixelRatio(),this.elements={},this.events=["mousemove","mouseout","click","touchstart","touchmove"],this.font={family:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",size:12,style:"normal",lineHeight:1.2,weight:null},this.hover={},this.hoverBackgroundColor=(t,e)=>te(e.backgroundColor),this.hoverBorderColor=(t,e)=>te(e.borderColor),this.hoverColor=(t,e)=>te(e.color),this.indexAxis="x",this.interaction={mode:"nearest",intersect:!0,includeInvisible:!1},this.maintainAspectRatio=!0,this.onHover=null,this.onClick=null,this.parsing=!0,this.plugins={},this.responsive=!0,this.scale=void 0,this.scales={},this.showLine=!0,this.drawActiveElementsOnTop=!0,this.describe(t),this.apply(e)}set(t,e){return ce(this,t,e)}get(t){return he(this,t)}describe(t,e){return ce(le,t,e)}override(t,e){return ce(re,t,e)}route(t,e,i,s){const n=he(this,t),a=he(this,i),r="_"+e;Object.defineProperties(n,{[r]:{value:n[e],writable:!0},[e]:{enumerable:!0,get(){const t=this[r],e=a[s];return o(t)?Object.assign({},e,t):l(t,e)},set(t){this[r]=t}}})}apply(t){t.forEach((t=>t(this)))}}var ue=new de({_scriptable:t=>!t.startsWith("on"),_indexable:t=>"events"!==t,hover:{_fallback:"interaction"},interaction:{_scriptable:!1,_indexable:!1}},[function(t){t.set("animation",{delay:void 0,duration:1e3,easing:"easeOutQuart",fn:void 0,from:void 0,loop:void 0,to:void 0,type:void 0}),t.describe("animation",{_fallback:!1,_indexable:!1,_scriptable:t=>"onProgress"!==t&&"onComplete"!==t&&"fn"!==t}),t.set("animations",{colors:{type:"color",properties:ie},numbers:{type:"number",properties:ee}}),t.describe("animations",{_fallback:"animation"}),t.set("transitions",{active:{animation:{duration:400}},resize:{animation:{duration:0}},show:{animations:{colors:{from:"transparent"},visible:{type:"boolean",duration:0}}},hide:{animations:{colors:{to:"transparent"},visible:{type:"boolean",easing:"linear",fn:t=>0|t}}}})},function(t){t.set("layout",{autoPadding:!0,padding:{top:0,right:0,bottom:0,left:0}})},function(t){t.set("scale",{display:!0,offset:!1,reverse:!1,beginAtZero:!1,bounds:"ticks",clip:!0,grace:0,grid:{display:!0,lineWidth:1,drawOnChartArea:!0,drawTicks:!0,tickLength:8,tickWidth:(t,e)=>e.lineWidth,tickColor:(t,e)=>e.color,offset:!1},border:{display:!0,dash:[],dashOffset:0,width:1},title:{display:!1,text:"",padding:{top:4,bottom:4}},ticks:{minRotation:0,maxRotation:50,mirror:!1,textStrokeWidth:0,textStrokeColor:"",padding:3,display:!0,autoSkip:!0,autoSkipPadding:3,labelOffset:0,callback:ae.formatters.values,minor:{},major:{},align:"center",crossAlign:"near",showLabelBackdrop:!1,backdropColor:"rgba(255, 255, 255, 0.75)",backdropPadding:2}}),t.route("scale.ticks","color","","color"),t.route("scale.grid","color","","borderColor"),t.route("scale.border","color","","borderColor"),t.route("scale.title","color","","color"),t.describe("scale",{_fallback:!1,_scriptable:t=>!t.startsWith("before")&&!t.startsWith("after")&&"callback"!==t&&"parser"!==t,_indexable:t=>"borderDash"!==t&&"tickBorderDash"!==t&&"dash"!==t}),t.describe("scales",{_fallback:"scale"}),t.describe("scale.ticks",{_scriptable:t=>"backdropPadding"!==t&&"callback"!==t,_indexable:t=>"backdropPadding"!==t})}]);function fe(){return"undefined"!=typeof window&&"undefined"!=typeof document}function ge(t){let e=t.parentNode;return e&&"[object ShadowRoot]"===e.toString()&&(e=e.host),e}function pe(t,e,i){let s;return"string"==typeof t?(s=parseInt(t,10),-1!==t.indexOf("%")&&(s=s/100*e.parentNode[i])):s=t,s}const me=t=>t.ownerDocument.defaultView.getComputedStyle(t,null);function xe(t,e){return me(t).getPropertyValue(e)}const be=["top","right","bottom","left"];function _e(t,e,i){const s={};i=i?"-"+i:"";for(let n=0;n<4;n++){const o=be[n];s[o]=parseFloat(t[e+"-"+o+i])||0}return s.width=s.left+s.right,s.height=s.top+s.bottom,s}const ye=(t,e,i)=>(t>0||e>0)&&(!i||!i.shadowRoot);function ve(t,e){if("native"in t)return t;const{canvas:i,currentDevicePixelRatio:s}=e,n=me(i),o="border-box"===n.boxSizing,a=_e(n,"padding"),r=_e(n,"border","width"),{x:l,y:h,box:c}=function(t,e){const i=t.touches,s=i&&i.length?i[0]:t,{offsetX:n,offsetY:o}=s;let a,r,l=!1;if(ye(n,o,t.target))a=n,r=o;else{const t=e.getBoundingClientRect();a=s.clientX-t.left,r=s.clientY-t.top,l=!0}return{x:a,y:r,box:l}}(t,i),d=a.left+(c&&r.left),u=a.top+(c&&r.top);let{width:f,height:g}=e;return o&&(f-=a.width+r.width,g-=a.height+r.height),{x:Math.round((l-d)/f*i.width/s),y:Math.round((h-u)/g*i.height/s)}}const Me=t=>Math.round(10*t)/10;function we(t,e,i,s){const n=me(t),o=_e(n,"margin"),a=pe(n.maxWidth,t,"clientWidth")||T,r=pe(n.maxHeight,t,"clientHeight")||T,l=function(t,e,i){let s,n;if(void 0===e||void 0===i){const o=t&&ge(t);if(o){const t=o.getBoundingClientRect(),a=me(o),r=_e(a,"border","width"),l=_e(a,"padding");e=t.width-l.width-r.width,i=t.height-l.height-r.height,s=pe(a.maxWidth,o,"clientWidth"),n=pe(a.maxHeight,o,"clientHeight")}else e=t.clientWidth,i=t.clientHeight}return{width:e,height:i,maxWidth:s||T,maxHeight:n||T}}(t,e,i);let{width:h,height:c}=l;if("content-box"===n.boxSizing){const t=_e(n,"border","width"),e=_e(n,"padding");h-=e.width+t.width,c-=e.height+t.height}h=Math.max(0,h-o.width),c=Math.max(0,s?h/s:c-o.height),h=Me(Math.min(h,a,l.maxWidth)),c=Me(Math.min(c,r,l.maxHeight)),h&&!c&&(c=Me(h/2));return(void 0!==e||void 0!==i)&&s&&l.height&&c>l.height&&(c=l.height,h=Me(Math.floor(c*s))),{width:h,height:c}}function ke(t,e,i){const s=e||1,n=Math.floor(t.height*s),o=Math.floor(t.width*s);t.height=Math.floor(t.height),t.width=Math.floor(t.width);const a=t.canvas;return a.style&&(i||!a.style.height&&!a.style.width)&&(a.style.height=`${t.height}px`,a.style.width=`${t.width}px`),(t.currentDevicePixelRatio!==s||a.height!==n||a.width!==o)&&(t.currentDevicePixelRatio=s,a.height=n,a.width=o,t.ctx.setTransform(s,0,0,s,0,0),!0)}const Se=function(){let t=!1;try{const e={get passive(){return t=!0,!1}};fe()&&(window.addEventListener("test",null,e),window.removeEventListener("test",null,e))}catch(t){}return t}();function Pe(t,e){const i=xe(t,e),s=i&&i.match(/^(\d+)(\.\d+)?px$/);return s?+s[1]:void 0}function De(t){return!t||s(t.size)||s(t.family)?null:(t.style?t.style+" ":"")+(t.weight?t.weight+" ":"")+t.size+"px "+t.family}function Ce(t,e,i,s,n){let o=e[n];return o||(o=e[n]=t.measureText(n).width,i.push(n)),o>s&&(s=o),s}function Oe(t,e,i,s){let o=(s=s||{}).data=s.data||{},a=s.garbageCollect=s.garbageCollect||[];s.font!==e&&(o=s.data={},a=s.garbageCollect=[],s.font=e),t.save(),t.font=e;let r=0;const l=i.length;let h,c,d,u,f;for(h=0;hi.length){for(h=0;h0&&t.stroke()}}function Re(t,e,i){return i=i||.5,!e||t&&t.x>e.left-i&&t.xe.top-i&&t.y0&&""!==r.strokeColor;let c,d;for(t.save(),t.font=a.string,function(t,e){e.translation&&t.translate(e.translation[0],e.translation[1]),s(e.rotation)||t.rotate(e.rotation),e.color&&(t.fillStyle=e.color),e.textAlign&&(t.textAlign=e.textAlign),e.textBaseline&&(t.textBaseline=e.textBaseline)}(t,r),c=0;ct[0])){const o=i||t;void 0===s&&(s=ti("_fallback",t));const a={[Symbol.toStringTag]:"Object",_cacheable:!0,_scopes:t,_rootScopes:o,_fallback:s,_getTarget:n,override:i=>je([i,...t],e,o,s)};return new Proxy(a,{deleteProperty:(e,i)=>(delete e[i],delete e._keys,delete t[0][i],!0),get:(i,s)=>qe(i,s,(()=>function(t,e,i,s){let n;for(const o of e)if(n=ti(Ue(o,t),i),void 0!==n)return Xe(t,n)?Je(i,s,t,n):n}(s,e,t,i))),getOwnPropertyDescriptor:(t,e)=>Reflect.getOwnPropertyDescriptor(t._scopes[0],e),getPrototypeOf:()=>Reflect.getPrototypeOf(t[0]),has:(t,e)=>ei(t).includes(e),ownKeys:t=>ei(t),set(t,e,i){const s=t._storage||(t._storage=n());return t[e]=s[e]=i,delete t._keys,!0}})}function $e(t,e,i,s){const a={_cacheable:!1,_proxy:t,_context:e,_subProxy:i,_stack:new Set,_descriptors:Ye(t,s),setContext:e=>$e(t,e,i,s),override:n=>$e(t.override(n),e,i,s)};return new Proxy(a,{deleteProperty:(e,i)=>(delete e[i],delete t[i],!0),get:(t,e,i)=>qe(t,e,(()=>function(t,e,i){const{_proxy:s,_context:a,_subProxy:r,_descriptors:l}=t;let h=s[e];S(h)&&l.isScriptable(e)&&(h=function(t,e,i,s){const{_proxy:n,_context:o,_subProxy:a,_stack:r}=i;if(r.has(t))throw new Error("Recursion detected: "+Array.from(r).join("->")+"->"+t);r.add(t);let l=e(o,a||s);r.delete(t),Xe(t,l)&&(l=Je(n._scopes,n,t,l));return l}(e,h,t,i));n(h)&&h.length&&(h=function(t,e,i,s){const{_proxy:n,_context:a,_subProxy:r,_descriptors:l}=i;if(void 0!==a.index&&s(t))return e[a.index%e.length];if(o(e[0])){const i=e,s=n._scopes.filter((t=>t!==i));e=[];for(const o of i){const i=Je(s,n,t,o);e.push($e(i,a,r&&r[t],l))}}return e}(e,h,t,l.isIndexable));Xe(e,h)&&(h=$e(h,a,r&&r[e],l));return h}(t,e,i))),getOwnPropertyDescriptor:(e,i)=>e._descriptors.allKeys?Reflect.has(t,i)?{enumerable:!0,configurable:!0}:void 0:Reflect.getOwnPropertyDescriptor(t,i),getPrototypeOf:()=>Reflect.getPrototypeOf(t),has:(e,i)=>Reflect.has(t,i),ownKeys:()=>Reflect.ownKeys(t),set:(e,i,s)=>(t[i]=s,delete e[i],!0)})}function Ye(t,e={scriptable:!0,indexable:!0}){const{_scriptable:i=e.scriptable,_indexable:s=e.indexable,_allKeys:n=e.allKeys}=t;return{allKeys:n,scriptable:i,indexable:s,isScriptable:S(i)?i:()=>i,isIndexable:S(s)?s:()=>s}}const Ue=(t,e)=>t?t+w(e):e,Xe=(t,e)=>o(e)&&"adapters"!==t&&(null===Object.getPrototypeOf(e)||e.constructor===Object);function qe(t,e,i){if(Object.prototype.hasOwnProperty.call(t,e)||"constructor"===e)return t[e];const s=i();return t[e]=s,s}function Ke(t,e,i){return S(t)?t(e,i):t}const Ge=(t,e)=>!0===t?e:"string"==typeof t?M(e,t):void 0;function Ze(t,e,i,s,n){for(const o of e){const e=Ge(i,o);if(e){t.add(e);const o=Ke(e._fallback,i,n);if(void 0!==o&&o!==i&&o!==s)return o}else if(!1===e&&void 0!==s&&i!==s)return null}return!1}function Je(t,e,i,s){const a=e._rootScopes,r=Ke(e._fallback,i,s),l=[...t,...a],h=new Set;h.add(s);let c=Qe(h,l,i,r||i,s);return null!==c&&((void 0===r||r===i||(c=Qe(h,l,r,c,s),null!==c))&&je(Array.from(h),[""],a,r,(()=>function(t,e,i){const s=t._getTarget();e in s||(s[e]={});const a=s[e];if(n(a)&&o(i))return i;return a||{}}(e,i,s))))}function Qe(t,e,i,s,n){for(;i;)i=Ze(t,e,i,s,n);return i}function ti(t,e){for(const i of e){if(!i)continue;const e=i[t];if(void 0!==e)return e}}function ei(t){let e=t._keys;return e||(e=t._keys=function(t){const e=new Set;for(const i of t)for(const t of Object.keys(i).filter((t=>!t.startsWith("_"))))e.add(t);return Array.from(e)}(t._scopes)),e}function ii(t,e,i,s){const{iScale:n}=t,{key:o="r"}=this._parsing,a=new Array(s);let r,l,h,c;for(r=0,l=s;re"x"===t?"y":"x";function ai(t,e,i,s){const n=t.skip?e:t,o=e,a=i.skip?e:i,r=q(o,n),l=q(a,o);let h=r/(r+l),c=l/(r+l);h=isNaN(h)?0:h,c=isNaN(c)?0:c;const d=s*h,u=s*c;return{previous:{x:o.x-d*(a.x-n.x),y:o.y-d*(a.y-n.y)},next:{x:o.x+u*(a.x-n.x),y:o.y+u*(a.y-n.y)}}}function ri(t,e="x"){const i=oi(e),s=t.length,n=Array(s).fill(0),o=Array(s);let a,r,l,h=ni(t,0);for(a=0;a!t.skip))),"monotone"===e.cubicInterpolationMode)ri(t,n);else{let i=s?t[t.length-1]:t[0];for(o=0,a=t.length;o0===t||1===t,di=(t,e,i)=>-Math.pow(2,10*(t-=1))*Math.sin((t-e)*O/i),ui=(t,e,i)=>Math.pow(2,-10*t)*Math.sin((t-e)*O/i)+1,fi={linear:t=>t,easeInQuad:t=>t*t,easeOutQuad:t=>-t*(t-2),easeInOutQuad:t=>(t/=.5)<1?.5*t*t:-.5*(--t*(t-2)-1),easeInCubic:t=>t*t*t,easeOutCubic:t=>(t-=1)*t*t+1,easeInOutCubic:t=>(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2),easeInQuart:t=>t*t*t*t,easeOutQuart:t=>-((t-=1)*t*t*t-1),easeInOutQuart:t=>(t/=.5)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2),easeInQuint:t=>t*t*t*t*t,easeOutQuint:t=>(t-=1)*t*t*t*t+1,easeInOutQuint:t=>(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2),easeInSine:t=>1-Math.cos(t*E),easeOutSine:t=>Math.sin(t*E),easeInOutSine:t=>-.5*(Math.cos(C*t)-1),easeInExpo:t=>0===t?0:Math.pow(2,10*(t-1)),easeOutExpo:t=>1===t?1:1-Math.pow(2,-10*t),easeInOutExpo:t=>ci(t)?t:t<.5?.5*Math.pow(2,10*(2*t-1)):.5*(2-Math.pow(2,-10*(2*t-1))),easeInCirc:t=>t>=1?t:-(Math.sqrt(1-t*t)-1),easeOutCirc:t=>Math.sqrt(1-(t-=1)*t),easeInOutCirc:t=>(t/=.5)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1),easeInElastic:t=>ci(t)?t:di(t,.075,.3),easeOutElastic:t=>ci(t)?t:ui(t,.075,.3),easeInOutElastic(t){const e=.1125;return ci(t)?t:t<.5?.5*di(2*t,e,.45):.5+.5*ui(2*t-1,e,.45)},easeInBack(t){const e=1.70158;return t*t*((e+1)*t-e)},easeOutBack(t){const e=1.70158;return(t-=1)*t*((e+1)*t+e)+1},easeInOutBack(t){let e=1.70158;return(t/=.5)<1?t*t*((1+(e*=1.525))*t-e)*.5:.5*((t-=2)*t*((1+(e*=1.525))*t+e)+2)},easeInBounce:t=>1-fi.easeOutBounce(1-t),easeOutBounce(t){const e=7.5625,i=2.75;return t<1/i?e*t*t:t<2/i?e*(t-=1.5/i)*t+.75:t<2.5/i?e*(t-=2.25/i)*t+.9375:e*(t-=2.625/i)*t+.984375},easeInOutBounce:t=>t<.5?.5*fi.easeInBounce(2*t):.5*fi.easeOutBounce(2*t-1)+.5};function gi(t,e,i,s){return{x:t.x+i*(e.x-t.x),y:t.y+i*(e.y-t.y)}}function pi(t,e,i,s){return{x:t.x+i*(e.x-t.x),y:"middle"===s?i<.5?t.y:e.y:"after"===s?i<1?t.y:e.y:i>0?e.y:t.y}}function mi(t,e,i,s){const n={x:t.cp2x,y:t.cp2y},o={x:e.cp1x,y:e.cp1y},a=gi(t,n,i),r=gi(n,o,i),l=gi(o,e,i),h=gi(a,r,i),c=gi(r,l,i);return gi(h,c,i)}const xi=/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/,bi=/^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/;function _i(t,e){const i=(""+t).match(xi);if(!i||"normal"===i[1])return 1.2*e;switch(t=+i[2],i[3]){case"px":return t;case"%":t/=100}return e*t}const yi=t=>+t||0;function vi(t,e){const i={},s=o(e),n=s?Object.keys(e):e,a=o(t)?s?i=>l(t[i],t[e[i]]):e=>t[e]:()=>t;for(const t of n)i[t]=yi(a(t));return i}function Mi(t){return vi(t,{top:"y",right:"x",bottom:"y",left:"x"})}function wi(t){return vi(t,["topLeft","topRight","bottomLeft","bottomRight"])}function ki(t){const e=Mi(t);return e.width=e.left+e.right,e.height=e.top+e.bottom,e}function Si(t,e){t=t||{},e=e||ue.font;let i=l(t.size,e.size);"string"==typeof i&&(i=parseInt(i,10));let s=l(t.style,e.style);s&&!(""+s).match(bi)&&(console.warn('Invalid font style specified: "'+s+'"'),s=void 0);const n={family:l(t.family,e.family),lineHeight:_i(l(t.lineHeight,e.lineHeight),i),size:i,style:s,weight:l(t.weight,e.weight),string:""};return n.string=De(n),n}function Pi(t,e,i,s){let o,a,r,l=!0;for(o=0,a=t.length;oi&&0===t?0:t+e;return{min:a(s,-Math.abs(o)),max:a(n,o)}}function Ci(t,e){return Object.assign(Object.create(t),e)}function Oi(t,e,i){return t?function(t,e){return{x:i=>t+t+e-i,setWidth(t){e=t},textAlign:t=>"center"===t?t:"right"===t?"left":"right",xPlus:(t,e)=>t-e,leftForLtr:(t,e)=>t-e}}(e,i):{x:t=>t,setWidth(t){},textAlign:t=>t,xPlus:(t,e)=>t+e,leftForLtr:(t,e)=>t}}function Ai(t,e){let i,s;"ltr"!==e&&"rtl"!==e||(i=t.canvas.style,s=[i.getPropertyValue("direction"),i.getPropertyPriority("direction")],i.setProperty("direction",e,"important"),t.prevTextDirection=s)}function Ti(t,e){void 0!==e&&(delete t.prevTextDirection,t.canvas.style.setProperty("direction",e[0],e[1]))}function Li(t){return"angle"===t?{between:Z,compare:K,normalize:G}:{between:tt,compare:(t,e)=>t-e,normalize:t=>t}}function Ei({start:t,end:e,count:i,loop:s,style:n}){return{start:t%i,end:e%i,loop:s&&(e-t+1)%i==0,style:n}}function Ri(t,e,i){if(!i)return[t];const{property:s,start:n,end:o}=i,a=e.length,{compare:r,between:l,normalize:h}=Li(s),{start:c,end:d,loop:u,style:f}=function(t,e,i){const{property:s,start:n,end:o}=i,{between:a,normalize:r}=Li(s),l=e.length;let h,c,{start:d,end:u,loop:f}=t;if(f){for(d+=l,u+=l,h=0,c=l;hb||l(n,x,p)&&0!==r(n,x),v=()=>!b||0===r(o,p)||l(o,x,p);for(let t=c,i=c;t<=d;++t)m=e[t%a],m.skip||(p=h(m[s]),p!==x&&(b=l(p,n,o),null===_&&y()&&(_=0===r(p,n)?t:i),null!==_&&v()&&(g.push(Ei({start:_,end:t,loop:u,count:a,style:f})),_=null),i=t,x=p));return null!==_&&g.push(Ei({start:_,end:d,loop:u,count:a,style:f})),g}function Ii(t,e){const i=[],s=t.segments;for(let n=0;nn&&t[o%e].skip;)o--;return o%=e,{start:n,end:o}}(i,n,o,s);if(!0===s)return Fi(t,[{start:a,end:r,loop:o}],i,e);return Fi(t,function(t,e,i,s){const n=t.length,o=[];let a,r=e,l=t[e];for(a=e+1;a<=i;++a){const i=t[a%n];i.skip||i.stop?l.skip||(s=!1,o.push({start:e%n,end:(a-1)%n,loop:s}),e=r=i.stop?a:null):(r=a,l.skip&&(e=a)),l=i}return null!==r&&o.push({start:e%n,end:r%n,loop:s}),o}(i,a,r!s(t[e.axis])));n.lo-=Math.max(0,a);const r=i.slice(n.hi).findIndex((t=>!s(t[e.axis])));n.hi+=Math.max(0,r)}return n}if(o._sharedOptions){const t=a[0],s="function"==typeof t.getRange&&t.getRange(e);if(s){const t=r(a,e,i-s),n=r(a,e,i+s);return{lo:t.lo,hi:n.hi}}}}return{lo:0,hi:a.length-1}}function $i(t,e,i,s,n){const o=t.getSortedVisibleDatasetMetas(),a=i[e];for(let t=0,i=o.length;t{t[a]&&t[a](e[i],n)&&(o.push({element:t,datasetIndex:s,index:l}),r=r||t.inRange(e.x,e.y,n))})),s&&!r?[]:o}var Ki={evaluateInteractionItems:$i,modes:{index(t,e,i,s){const n=ve(e,t),o=i.axis||"x",a=i.includeInvisible||!1,r=i.intersect?Yi(t,n,o,s,a):Xi(t,n,o,!1,s,a),l=[];return r.length?(t.getSortedVisibleDatasetMetas().forEach((t=>{const e=r[0].index,i=t.data[e];i&&!i.skip&&l.push({element:i,datasetIndex:t.index,index:e})})),l):[]},dataset(t,e,i,s){const n=ve(e,t),o=i.axis||"xy",a=i.includeInvisible||!1;let r=i.intersect?Yi(t,n,o,s,a):Xi(t,n,o,!1,s,a);if(r.length>0){const e=r[0].datasetIndex,i=t.getDatasetMeta(e).data;r=[];for(let t=0;tYi(t,ve(e,t),i.axis||"xy",s,i.includeInvisible||!1),nearest(t,e,i,s){const n=ve(e,t),o=i.axis||"xy",a=i.includeInvisible||!1;return Xi(t,n,o,i.intersect,s,a)},x:(t,e,i,s)=>qi(t,ve(e,t),"x",i.intersect,s),y:(t,e,i,s)=>qi(t,ve(e,t),"y",i.intersect,s)}};const Gi=["left","top","right","bottom"];function Zi(t,e){return t.filter((t=>t.pos===e))}function Ji(t,e){return t.filter((t=>-1===Gi.indexOf(t.pos)&&t.box.axis===e))}function Qi(t,e){return t.sort(((t,i)=>{const s=e?i:t,n=e?t:i;return s.weight===n.weight?s.index-n.index:s.weight-n.weight}))}function ts(t,e){const i=function(t){const e={};for(const i of t){const{stack:t,pos:s,stackWeight:n}=i;if(!t||!Gi.includes(s))continue;const o=e[t]||(e[t]={count:0,placed:0,weight:0,size:0});o.count++,o.weight+=n}return e}(t),{vBoxMaxWidth:s,hBoxMaxHeight:n}=e;let o,a,r;for(o=0,a=t.length;o{s[t]=Math.max(e[t],i[t])})),s}return s(t?["left","right"]:["top","bottom"])}function os(t,e,i,s){const n=[];let o,a,r,l,h,c;for(o=0,a=t.length,h=0;ot.box.fullSize)),!0),s=Qi(Zi(e,"left"),!0),n=Qi(Zi(e,"right")),o=Qi(Zi(e,"top"),!0),a=Qi(Zi(e,"bottom")),r=Ji(e,"x"),l=Ji(e,"y");return{fullSize:i,leftAndTop:s.concat(o),rightAndBottom:n.concat(l).concat(a).concat(r),chartArea:Zi(e,"chartArea"),vertical:s.concat(n).concat(l),horizontal:o.concat(a).concat(r)}}(t.boxes),l=r.vertical,h=r.horizontal;u(t.boxes,(t=>{"function"==typeof t.beforeLayout&&t.beforeLayout()}));const c=l.reduce(((t,e)=>e.box.options&&!1===e.box.options.display?t:t+1),0)||1,d=Object.freeze({outerWidth:e,outerHeight:i,padding:n,availableWidth:o,availableHeight:a,vBoxMaxWidth:o/2/c,hBoxMaxHeight:a/2}),f=Object.assign({},n);is(f,ki(s));const g=Object.assign({maxPadding:f,w:o,h:a,x:n.left,y:n.top},n),p=ts(l.concat(h),d);os(r.fullSize,g,d,p),os(l,g,d,p),os(h,g,d,p)&&os(l,g,d,p),function(t){const e=t.maxPadding;function i(i){const s=Math.max(e[i]-t[i],0);return t[i]+=s,s}t.y+=i("top"),t.x+=i("left"),i("right"),i("bottom")}(g),rs(r.leftAndTop,g,d,p),g.x+=g.w,g.y+=g.h,rs(r.rightAndBottom,g,d,p),t.chartArea={left:g.left,top:g.top,right:g.left+g.w,bottom:g.top+g.h,height:g.h,width:g.w},u(r.chartArea,(e=>{const i=e.box;Object.assign(i,t.chartArea),i.update(g.w,g.h,{left:0,top:0,right:0,bottom:0})}))}};class hs{acquireContext(t,e){}releaseContext(t){return!1}addEventListener(t,e,i){}removeEventListener(t,e,i){}getDevicePixelRatio(){return 1}getMaximumSize(t,e,i,s){return e=Math.max(0,e||t.width),i=i||t.height,{width:e,height:Math.max(0,s?Math.floor(e/s):i)}}isAttached(t){return!0}updateConfig(t){}}class cs extends hs{acquireContext(t){return t&&t.getContext&&t.getContext("2d")||null}updateConfig(t){t.options.animation=!1}}const ds="$chartjs",us={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"},fs=t=>null===t||""===t;const gs=!!Se&&{passive:!0};function ps(t,e,i){t&&t.canvas&&t.canvas.removeEventListener(e,i,gs)}function ms(t,e){for(const i of t)if(i===e||i.contains(e))return!0}function xs(t,e,i){const s=t.canvas,n=new MutationObserver((t=>{let e=!1;for(const i of t)e=e||ms(i.addedNodes,s),e=e&&!ms(i.removedNodes,s);e&&i()}));return n.observe(document,{childList:!0,subtree:!0}),n}function bs(t,e,i){const s=t.canvas,n=new MutationObserver((t=>{let e=!1;for(const i of t)e=e||ms(i.removedNodes,s),e=e&&!ms(i.addedNodes,s);e&&i()}));return n.observe(document,{childList:!0,subtree:!0}),n}const _s=new Map;let ys=0;function vs(){const t=window.devicePixelRatio;t!==ys&&(ys=t,_s.forEach(((e,i)=>{i.currentDevicePixelRatio!==t&&e()})))}function Ms(t,e,i){const s=t.canvas,n=s&&ge(s);if(!n)return;const o=ct(((t,e)=>{const s=n.clientWidth;i(t,e),s{const e=t[0],i=e.contentRect.width,s=e.contentRect.height;0===i&&0===s||o(i,s)}));return a.observe(n),function(t,e){_s.size||window.addEventListener("resize",vs),_s.set(t,e)}(t,o),a}function ws(t,e,i){i&&i.disconnect(),"resize"===e&&function(t){_s.delete(t),_s.size||window.removeEventListener("resize",vs)}(t)}function ks(t,e,i){const s=t.canvas,n=ct((e=>{null!==t.ctx&&i(function(t,e){const i=us[t.type]||t.type,{x:s,y:n}=ve(t,e);return{type:i,chart:e,native:t,x:void 0!==s?s:null,y:void 0!==n?n:null}}(e,t))}),t);return function(t,e,i){t&&t.addEventListener(e,i,gs)}(s,e,n),n}class Ss extends hs{acquireContext(t,e){const i=t&&t.getContext&&t.getContext("2d");return i&&i.canvas===t?(function(t,e){const i=t.style,s=t.getAttribute("height"),n=t.getAttribute("width");if(t[ds]={initial:{height:s,width:n,style:{display:i.display,height:i.height,width:i.width}}},i.display=i.display||"block",i.boxSizing=i.boxSizing||"border-box",fs(n)){const e=Pe(t,"width");void 0!==e&&(t.width=e)}if(fs(s))if(""===t.style.height)t.height=t.width/(e||2);else{const e=Pe(t,"height");void 0!==e&&(t.height=e)}}(t,e),i):null}releaseContext(t){const e=t.canvas;if(!e[ds])return!1;const i=e[ds].initial;["height","width"].forEach((t=>{const n=i[t];s(n)?e.removeAttribute(t):e.setAttribute(t,n)}));const n=i.style||{};return Object.keys(n).forEach((t=>{e.style[t]=n[t]})),e.width=e.width,delete e[ds],!0}addEventListener(t,e,i){this.removeEventListener(t,e);const s=t.$proxies||(t.$proxies={}),n={attach:xs,detach:bs,resize:Ms}[e]||ks;s[e]=n(t,e,i)}removeEventListener(t,e){const i=t.$proxies||(t.$proxies={}),s=i[e];if(!s)return;({attach:ws,detach:ws,resize:ws}[e]||ps)(t,e,s),i[e]=void 0}getDevicePixelRatio(){return window.devicePixelRatio}getMaximumSize(t,e,i,s){return we(t,e,i,s)}isAttached(t){const e=t&&ge(t);return!(!e||!e.isConnected)}}function Ps(t){return!fe()||"undefined"!=typeof OffscreenCanvas&&t instanceof OffscreenCanvas?cs:Ss}var Ds=Object.freeze({__proto__:null,BasePlatform:hs,BasicPlatform:cs,DomPlatform:Ss,_detectPlatform:Ps});const Cs="transparent",Os={boolean:(t,e,i)=>i>.5?e:t,color(t,e,i){const s=Qt(t||Cs),n=s.valid&&Qt(e||Cs);return n&&n.valid?n.mix(s,i).hexString():e},number:(t,e,i)=>t+(e-t)*i};class As{constructor(t,e,i,s){const n=e[i];s=Pi([t.to,s,n,t.from]);const o=Pi([t.from,n,s]);this._active=!0,this._fn=t.fn||Os[t.type||typeof o],this._easing=fi[t.easing]||fi.linear,this._start=Math.floor(Date.now()+(t.delay||0)),this._duration=this._total=Math.floor(t.duration),this._loop=!!t.loop,this._target=e,this._prop=i,this._from=o,this._to=s,this._promises=void 0}active(){return this._active}update(t,e,i){if(this._active){this._notify(!1);const s=this._target[this._prop],n=i-this._start,o=this._duration-n;this._start=i,this._duration=Math.floor(Math.max(o,t.duration)),this._total+=n,this._loop=!!t.loop,this._to=Pi([t.to,e,s,t.from]),this._from=Pi([t.from,s,e])}}cancel(){this._active&&(this.tick(Date.now()),this._active=!1,this._notify(!1))}tick(t){const e=t-this._start,i=this._duration,s=this._prop,n=this._from,o=this._loop,a=this._to;let r;if(this._active=n!==a&&(o||e1?2-r:r,r=this._easing(Math.min(1,Math.max(0,r))),this._target[s]=this._fn(n,a,r))}wait(){const t=this._promises||(this._promises=[]);return new Promise(((e,i)=>{t.push({res:e,rej:i})}))}_notify(t){const e=t?"res":"rej",i=this._promises||[];for(let t=0;t{const a=t[s];if(!o(a))return;const r={};for(const t of e)r[t]=a[t];(n(a.properties)&&a.properties||[s]).forEach((t=>{t!==s&&i.has(t)||i.set(t,r)}))}))}_animateOptions(t,e){const i=e.options,s=function(t,e){if(!e)return;let i=t.options;if(!i)return void(t.options=e);i.$shared&&(t.options=i=Object.assign({},i,{$shared:!1,$animations:{}}));return i}(t,i);if(!s)return[];const n=this._createAnimations(s,i);return i.$shared&&function(t,e){const i=[],s=Object.keys(e);for(let e=0;e{t.options=i}),(()=>{})),n}_createAnimations(t,e){const i=this._properties,s=[],n=t.$animations||(t.$animations={}),o=Object.keys(e),a=Date.now();let r;for(r=o.length-1;r>=0;--r){const l=o[r];if("$"===l.charAt(0))continue;if("options"===l){s.push(...this._animateOptions(t,e));continue}const h=e[l];let c=n[l];const d=i.get(l);if(c){if(d&&c.active()){c.update(d,h,a);continue}c.cancel()}d&&d.duration?(n[l]=c=new As(d,t,l,h),s.push(c)):t[l]=h}return s}update(t,e){if(0===this._properties.size)return void Object.assign(t,e);const i=this._createAnimations(t,e);return i.length?(bt.add(this._chart,i),!0):void 0}}function Ls(t,e){const i=t&&t.options||{},s=i.reverse,n=void 0===i.min?e:0,o=void 0===i.max?e:0;return{start:s?o:n,end:s?n:o}}function Es(t,e){const i=[],s=t._getSortedDatasetMetas(e);let n,o;for(n=0,o=s.length;n0||!i&&e<0)return n.index}return null}function Vs(t,e){const{chart:i,_cachedMeta:s}=t,n=i._stacks||(i._stacks={}),{iScale:o,vScale:a,index:r}=s,l=o.axis,h=a.axis,c=function(t,e,i){return`${t.id}.${e.id}.${i.stack||i.type}`}(o,a,s),d=e.length;let u;for(let t=0;ti[t].axis===e)).shift()}function Ws(t,e){const i=t.controller.index,s=t.vScale&&t.vScale.axis;if(s){e=e||t._parsed;for(const t of e){const e=t._stacks;if(!e||void 0===e[s]||void 0===e[s][i])return;delete e[s][i],void 0!==e[s]._visualValues&&void 0!==e[s]._visualValues[i]&&delete e[s]._visualValues[i]}}}const Ns=t=>"reset"===t||"none"===t,Hs=(t,e)=>e?t:Object.assign({},t);class js{static defaults={};static datasetElementType=null;static dataElementType=null;constructor(t,e){this.chart=t,this._ctx=t.ctx,this.index=e,this._cachedDataOpts={},this._cachedMeta=this.getMeta(),this._type=this._cachedMeta.type,this.options=void 0,this._parsing=!1,this._data=void 0,this._objectData=void 0,this._sharedOptions=void 0,this._drawStart=void 0,this._drawCount=void 0,this.enableOptionSharing=!1,this.supportsDecimation=!1,this.$context=void 0,this._syncList=[],this.datasetElementType=new.target.datasetElementType,this.dataElementType=new.target.dataElementType,this.initialize()}initialize(){const t=this._cachedMeta;this.configure(),this.linkScales(),t._stacked=Is(t.vScale,t),this.addElements(),this.options.fill&&!this.chart.isPluginEnabled("filler")&&console.warn("Tried to use the 'fill' option without the 'Filler' plugin enabled. Please import and register the 'Filler' plugin and make sure it is not disabled in the options")}updateIndex(t){this.index!==t&&Ws(this._cachedMeta),this.index=t}linkScales(){const t=this.chart,e=this._cachedMeta,i=this.getDataset(),s=(t,e,i,s)=>"x"===t?e:"r"===t?s:i,n=e.xAxisID=l(i.xAxisID,Bs(t,"x")),o=e.yAxisID=l(i.yAxisID,Bs(t,"y")),a=e.rAxisID=l(i.rAxisID,Bs(t,"r")),r=e.indexAxis,h=e.iAxisID=s(r,n,o,a),c=e.vAxisID=s(r,o,n,a);e.xScale=this.getScaleForId(n),e.yScale=this.getScaleForId(o),e.rScale=this.getScaleForId(a),e.iScale=this.getScaleForId(h),e.vScale=this.getScaleForId(c)}getDataset(){return this.chart.data.datasets[this.index]}getMeta(){return this.chart.getDatasetMeta(this.index)}getScaleForId(t){return this.chart.scales[t]}_getOtherScale(t){const e=this._cachedMeta;return t===e.iScale?e.vScale:e.iScale}reset(){this._update("reset")}_destroy(){const t=this._cachedMeta;this._data&&rt(this._data,this),t._stacked&&Ws(t)}_dataCheck(){const t=this.getDataset(),e=t.data||(t.data=[]),i=this._data;if(o(e)){const t=this._cachedMeta;this._data=function(t,e){const{iScale:i,vScale:s}=e,n="x"===i.axis?"x":"y",o="x"===s.axis?"x":"y",a=Object.keys(t),r=new Array(a.length);let l,h,c;for(l=0,h=a.length;l0&&i._parsed[t-1];if(!1===this._parsing)i._parsed=s,i._sorted=!0,d=s;else{d=n(s[t])?this.parseArrayData(i,s,t,e):o(s[t])?this.parseObjectData(i,s,t,e):this.parsePrimitiveData(i,s,t,e);const a=()=>null===c[l]||f&&c[l]t&&!e.hidden&&e._stacked&&{keys:Es(i,!0),values:null})(e,i,this.chart),h={min:Number.POSITIVE_INFINITY,max:Number.NEGATIVE_INFINITY},{min:c,max:d}=function(t){const{min:e,max:i,minDefined:s,maxDefined:n}=t.getUserBounds();return{min:s?e:Number.NEGATIVE_INFINITY,max:n?i:Number.POSITIVE_INFINITY}}(r);let u,f;function g(){f=s[u];const e=f[r.axis];return!a(f[t.axis])||c>e||d=0;--u)if(!g()){this.updateRangeFromParsed(h,t,f,l);break}return h}getAllParsedValues(t){const e=this._cachedMeta._parsed,i=[];let s,n,o;for(s=0,n=e.length;s=0&&tthis.getContext(i,s,e)),c);return f.$shared&&(f.$shared=r,n[o]=Object.freeze(Hs(f,r))),f}_resolveAnimations(t,e,i){const s=this.chart,n=this._cachedDataOpts,o=`animation-${e}`,a=n[o];if(a)return a;let r;if(!1!==s.options.animation){const s=this.chart.config,n=s.datasetAnimationScopeKeys(this._type,e),o=s.getOptionScopes(this.getDataset(),n);r=s.createResolver(o,this.getContext(t,i,e))}const l=new Ts(s,r&&r.animations);return r&&r._cacheable&&(n[o]=Object.freeze(l)),l}getSharedOptions(t){if(t.$shared)return this._sharedOptions||(this._sharedOptions=Object.assign({},t))}includeOptions(t,e){return!e||Ns(t)||this.chart._animationsDisabled}_getSharedOptions(t,e){const i=this.resolveDataElementOptions(t,e),s=this._sharedOptions,n=this.getSharedOptions(i),o=this.includeOptions(e,n)||n!==s;return this.updateSharedOptions(n,e,i),{sharedOptions:n,includeOptions:o}}updateElement(t,e,i,s){Ns(s)?Object.assign(t,i):this._resolveAnimations(e,s).update(t,i)}updateSharedOptions(t,e,i){t&&!Ns(e)&&this._resolveAnimations(void 0,e).update(t,i)}_setStyle(t,e,i,s){t.active=s;const n=this.getStyle(e,s);this._resolveAnimations(e,i,s).update(t,{options:!s&&this.getSharedOptions(n)||n})}removeHoverStyle(t,e,i){this._setStyle(t,i,"active",!1)}setHoverStyle(t,e,i){this._setStyle(t,i,"active",!0)}_removeDatasetHoverStyle(){const t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!1)}_setDatasetHoverStyle(){const t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!0)}_resyncElements(t){const e=this._data,i=this._cachedMeta.data;for(const[t,e,i]of this._syncList)this[t](e,i);this._syncList=[];const s=i.length,n=e.length,o=Math.min(n,s);o&&this.parse(0,o),n>s?this._insertElements(s,n-s,t):n{for(t.length+=e,a=t.length-1;a>=o;a--)t[a]=t[a-e]};for(r(n),a=t;a{s[t]=i[t]&&i[t].active()?i[t]._to:this[t]})),s}}function Ys(t,e){const i=t.options.ticks,n=function(t){const e=t.options.offset,i=t._tickSize(),s=t._length/i+(e?0:1),n=t._maxLength/i;return Math.floor(Math.min(s,n))}(t),o=Math.min(i.maxTicksLimit||n,n),a=i.major.enabled?function(t){const e=[];let i,s;for(i=0,s=t.length;io)return function(t,e,i,s){let n,o=0,a=i[0];for(s=Math.ceil(s),n=0;nn)return e}return Math.max(n,1)}(a,e,o);if(r>0){let t,i;const n=r>1?Math.round((h-l)/(r-1)):null;for(Us(e,c,d,s(n)?0:l-n,l),t=0,i=r-1;t"top"===e||"left"===e?t[e]+i:t[e]-i,qs=(t,e)=>Math.min(e||t,t);function Ks(t,e){const i=[],s=t.length/e,n=t.length;let o=0;for(;oa+r)))return h}function Zs(t){return t.drawTicks?t.tickLength:0}function Js(t,e){if(!t.display)return 0;const i=Si(t.font,e),s=ki(t.padding);return(n(t.text)?t.text.length:1)*i.lineHeight+s.height}function Qs(t,e,i){let s=ut(t);return(i&&"right"!==e||!i&&"right"===e)&&(s=(t=>"left"===t?"right":"right"===t?"left":t)(s)),s}class tn extends $s{constructor(t){super(),this.id=t.id,this.type=t.type,this.options=void 0,this.ctx=t.ctx,this.chart=t.chart,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this._margins={left:0,right:0,top:0,bottom:0},this.maxWidth=void 0,this.maxHeight=void 0,this.paddingTop=void 0,this.paddingBottom=void 0,this.paddingLeft=void 0,this.paddingRight=void 0,this.axis=void 0,this.labelRotation=void 0,this.min=void 0,this.max=void 0,this._range=void 0,this.ticks=[],this._gridLineItems=null,this._labelItems=null,this._labelSizes=null,this._length=0,this._maxLength=0,this._longestTextCache={},this._startPixel=void 0,this._endPixel=void 0,this._reversePixels=!1,this._userMax=void 0,this._userMin=void 0,this._suggestedMax=void 0,this._suggestedMin=void 0,this._ticksLength=0,this._borderValue=0,this._cache={},this._dataLimitsCached=!1,this.$context=void 0}init(t){this.options=t.setContext(this.getContext()),this.axis=t.axis,this._userMin=this.parse(t.min),this._userMax=this.parse(t.max),this._suggestedMin=this.parse(t.suggestedMin),this._suggestedMax=this.parse(t.suggestedMax)}parse(t,e){return t}getUserBounds(){let{_userMin:t,_userMax:e,_suggestedMin:i,_suggestedMax:s}=this;return t=r(t,Number.POSITIVE_INFINITY),e=r(e,Number.NEGATIVE_INFINITY),i=r(i,Number.POSITIVE_INFINITY),s=r(s,Number.NEGATIVE_INFINITY),{min:r(t,i),max:r(e,s),minDefined:a(t),maxDefined:a(e)}}getMinMax(t){let e,{min:i,max:s,minDefined:n,maxDefined:o}=this.getUserBounds();if(n&&o)return{min:i,max:s};const a=this.getMatchingVisibleMetas();for(let r=0,l=a.length;rs?s:i,s=n&&i>s?i:s,{min:r(i,r(s,i)),max:r(s,r(i,s))}}getPadding(){return{left:this.paddingLeft||0,top:this.paddingTop||0,right:this.paddingRight||0,bottom:this.paddingBottom||0}}getTicks(){return this.ticks}getLabels(){const t=this.chart.data;return this.options.labels||(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels||[]}getLabelItems(t=this.chart.chartArea){return this._labelItems||(this._labelItems=this._computeLabelItems(t))}beforeLayout(){this._cache={},this._dataLimitsCached=!1}beforeUpdate(){d(this.options.beforeUpdate,[this])}update(t,e,i){const{beginAtZero:s,grace:n,ticks:o}=this.options,a=o.sampleSize;this.beforeUpdate(),this.maxWidth=t,this.maxHeight=e,this._margins=i=Object.assign({left:0,right:0,top:0,bottom:0},i),this.ticks=null,this._labelSizes=null,this._gridLineItems=null,this._labelItems=null,this.beforeSetDimensions(),this.setDimensions(),this.afterSetDimensions(),this._maxLength=this.isHorizontal()?this.width+i.left+i.right:this.height+i.top+i.bottom,this._dataLimitsCached||(this.beforeDataLimits(),this.determineDataLimits(),this.afterDataLimits(),this._range=Di(this,n,s),this._dataLimitsCached=!0),this.beforeBuildTicks(),this.ticks=this.buildTicks()||[],this.afterBuildTicks();const r=a=n||i<=1||!this.isHorizontal())return void(this.labelRotation=s);const h=this._getLabelSizes(),c=h.widest.width,d=h.highest.height,u=J(this.chart.width-c,0,this.maxWidth);o=t.offset?this.maxWidth/i:u/(i-1),c+6>o&&(o=u/(i-(t.offset?.5:1)),a=this.maxHeight-Zs(t.grid)-e.padding-Js(t.title,this.chart.options.font),r=Math.sqrt(c*c+d*d),l=Y(Math.min(Math.asin(J((h.highest.height+6)/o,-1,1)),Math.asin(J(a/r,-1,1))-Math.asin(J(d/r,-1,1)))),l=Math.max(s,Math.min(n,l))),this.labelRotation=l}afterCalculateLabelRotation(){d(this.options.afterCalculateLabelRotation,[this])}afterAutoSkip(){}beforeFit(){d(this.options.beforeFit,[this])}fit(){const t={width:0,height:0},{chart:e,options:{ticks:i,title:s,grid:n}}=this,o=this._isVisible(),a=this.isHorizontal();if(o){const o=Js(s,e.options.font);if(a?(t.width=this.maxWidth,t.height=Zs(n)+o):(t.height=this.maxHeight,t.width=Zs(n)+o),i.display&&this.ticks.length){const{first:e,last:s,widest:n,highest:o}=this._getLabelSizes(),r=2*i.padding,l=$(this.labelRotation),h=Math.cos(l),c=Math.sin(l);if(a){const e=i.mirror?0:c*n.width+h*o.height;t.height=Math.min(this.maxHeight,t.height+e+r)}else{const e=i.mirror?0:h*n.width+c*o.height;t.width=Math.min(this.maxWidth,t.width+e+r)}this._calculatePadding(e,s,c,h)}}this._handleMargins(),a?(this.width=this._length=e.width-this._margins.left-this._margins.right,this.height=t.height):(this.width=t.width,this.height=this._length=e.height-this._margins.top-this._margins.bottom)}_calculatePadding(t,e,i,s){const{ticks:{align:n,padding:o},position:a}=this.options,r=0!==this.labelRotation,l="top"!==a&&"x"===this.axis;if(this.isHorizontal()){const a=this.getPixelForTick(0)-this.left,h=this.right-this.getPixelForTick(this.ticks.length-1);let c=0,d=0;r?l?(c=s*t.width,d=i*e.height):(c=i*t.height,d=s*e.width):"start"===n?d=e.width:"end"===n?c=t.width:"inner"!==n&&(c=t.width/2,d=e.width/2),this.paddingLeft=Math.max((c-a+o)*this.width/(this.width-a),0),this.paddingRight=Math.max((d-h+o)*this.width/(this.width-h),0)}else{let i=e.height/2,s=t.height/2;"start"===n?(i=0,s=t.height):"end"===n&&(i=e.height,s=0),this.paddingTop=i+o,this.paddingBottom=s+o}}_handleMargins(){this._margins&&(this._margins.left=Math.max(this.paddingLeft,this._margins.left),this._margins.top=Math.max(this.paddingTop,this._margins.top),this._margins.right=Math.max(this.paddingRight,this._margins.right),this._margins.bottom=Math.max(this.paddingBottom,this._margins.bottom))}afterFit(){d(this.options.afterFit,[this])}isHorizontal(){const{axis:t,position:e}=this.options;return"top"===e||"bottom"===e||"x"===t}isFullSize(){return this.options.fullSize}_convertTicksToLabels(t){let e,i;for(this.beforeTickToLabelConversion(),this.generateTickLabels(t),e=0,i=t.length;e{const i=t.gc,s=i.length/2;let n;if(s>e){for(n=0;n({width:r[t]||0,height:l[t]||0});return{first:P(0),last:P(e-1),widest:P(k),highest:P(S),widths:r,heights:l}}getLabelForValue(t){return t}getPixelForValue(t,e){return NaN}getValueForPixel(t){}getPixelForTick(t){const e=this.ticks;return t<0||t>e.length-1?null:this.getPixelForValue(e[t].value)}getPixelForDecimal(t){this._reversePixels&&(t=1-t);const e=this._startPixel+t*this._length;return Q(this._alignToPixels?Ae(this.chart,e,0):e)}getDecimalForPixel(t){const e=(t-this._startPixel)/this._length;return this._reversePixels?1-e:e}getBasePixel(){return this.getPixelForValue(this.getBaseValue())}getBaseValue(){const{min:t,max:e}=this;return t<0&&e<0?e:t>0&&e>0?t:0}getContext(t){const e=this.ticks||[];if(t>=0&&ta*s?a/i:r/s:r*s0}_computeGridLineItems(t){const e=this.axis,i=this.chart,s=this.options,{grid:n,position:a,border:r}=s,h=n.offset,c=this.isHorizontal(),d=this.ticks.length+(h?1:0),u=Zs(n),f=[],g=r.setContext(this.getContext()),p=g.display?g.width:0,m=p/2,x=function(t){return Ae(i,t,p)};let b,_,y,v,M,w,k,S,P,D,C,O;if("top"===a)b=x(this.bottom),w=this.bottom-u,S=b-m,D=x(t.top)+m,O=t.bottom;else if("bottom"===a)b=x(this.top),D=t.top,O=x(t.bottom)-m,w=b+m,S=this.top+u;else if("left"===a)b=x(this.right),M=this.right-u,k=b-m,P=x(t.left)+m,C=t.right;else if("right"===a)b=x(this.left),P=t.left,C=x(t.right)-m,M=b+m,k=this.left+u;else if("x"===e){if("center"===a)b=x((t.top+t.bottom)/2+.5);else if(o(a)){const t=Object.keys(a)[0],e=a[t];b=x(this.chart.scales[t].getPixelForValue(e))}D=t.top,O=t.bottom,w=b+m,S=w+u}else if("y"===e){if("center"===a)b=x((t.left+t.right)/2);else if(o(a)){const t=Object.keys(a)[0],e=a[t];b=x(this.chart.scales[t].getPixelForValue(e))}M=b-m,k=M-u,P=t.left,C=t.right}const A=l(s.ticks.maxTicksLimit,d),T=Math.max(1,Math.ceil(d/A));for(_=0;_0&&(o-=s/2)}d={left:o,top:n,width:s+e.width,height:i+e.height,color:t.backdropColor}}x.push({label:v,font:P,textOffset:O,options:{rotation:m,color:i,strokeColor:o,strokeWidth:h,textAlign:f,textBaseline:A,translation:[M,w],backdrop:d}})}return x}_getXAxisLabelAlignment(){const{position:t,ticks:e}=this.options;if(-$(this.labelRotation))return"top"===t?"left":"right";let i="center";return"start"===e.align?i="left":"end"===e.align?i="right":"inner"===e.align&&(i="inner"),i}_getYAxisLabelAlignment(t){const{position:e,ticks:{crossAlign:i,mirror:s,padding:n}}=this.options,o=t+n,a=this._getLabelSizes().widest.width;let r,l;return"left"===e?s?(l=this.right+n,"near"===i?r="left":"center"===i?(r="center",l+=a/2):(r="right",l+=a)):(l=this.right-o,"near"===i?r="right":"center"===i?(r="center",l-=a/2):(r="left",l=this.left)):"right"===e?s?(l=this.left+n,"near"===i?r="right":"center"===i?(r="center",l-=a/2):(r="left",l-=a)):(l=this.left+o,"near"===i?r="left":"center"===i?(r="center",l+=a/2):(r="right",l=this.right)):r="right",{textAlign:r,x:l}}_computeLabelArea(){if(this.options.ticks.mirror)return;const t=this.chart,e=this.options.position;return"left"===e||"right"===e?{top:0,left:this.left,bottom:t.height,right:this.right}:"top"===e||"bottom"===e?{top:this.top,left:0,bottom:this.bottom,right:t.width}:void 0}drawBackground(){const{ctx:t,options:{backgroundColor:e},left:i,top:s,width:n,height:o}=this;e&&(t.save(),t.fillStyle=e,t.fillRect(i,s,n,o),t.restore())}getLineWidthForValue(t){const e=this.options.grid;if(!this._isVisible()||!e.display)return 0;const i=this.ticks.findIndex((e=>e.value===t));if(i>=0){return e.setContext(this.getContext(i)).lineWidth}return 0}drawGrid(t){const e=this.options.grid,i=this.ctx,s=this._gridLineItems||(this._gridLineItems=this._computeGridLineItems(t));let n,o;const a=(t,e,s)=>{s.width&&s.color&&(i.save(),i.lineWidth=s.width,i.strokeStyle=s.color,i.setLineDash(s.borderDash||[]),i.lineDashOffset=s.borderDashOffset,i.beginPath(),i.moveTo(t.x,t.y),i.lineTo(e.x,e.y),i.stroke(),i.restore())};if(e.display)for(n=0,o=s.length;n{this.drawBackground(),this.drawGrid(t),this.drawTitle()}},{z:s,draw:()=>{this.drawBorder()}},{z:e,draw:t=>{this.drawLabels(t)}}]:[{z:e,draw:t=>{this.draw(t)}}]}getMatchingVisibleMetas(t){const e=this.chart.getSortedVisibleDatasetMetas(),i=this.axis+"AxisID",s=[];let n,o;for(n=0,o=e.length;n{const s=i.split("."),n=s.pop(),o=[t].concat(s).join("."),a=e[i].split("."),r=a.pop(),l=a.join(".");ue.route(o,n,l,r)}))}(e,t.defaultRoutes);t.descriptors&&ue.describe(e,t.descriptors)}(t,o,i),this.override&&ue.override(t.id,t.overrides)),o}get(t){return this.items[t]}unregister(t){const e=this.items,i=t.id,s=this.scope;i in e&&delete e[i],s&&i in ue[s]&&(delete ue[s][i],this.override&&delete re[i])}}class sn{constructor(){this.controllers=new en(js,"datasets",!0),this.elements=new en($s,"elements"),this.plugins=new en(Object,"plugins"),this.scales=new en(tn,"scales"),this._typedRegistries=[this.controllers,this.scales,this.elements]}add(...t){this._each("register",t)}remove(...t){this._each("unregister",t)}addControllers(...t){this._each("register",t,this.controllers)}addElements(...t){this._each("register",t,this.elements)}addPlugins(...t){this._each("register",t,this.plugins)}addScales(...t){this._each("register",t,this.scales)}getController(t){return this._get(t,this.controllers,"controller")}getElement(t){return this._get(t,this.elements,"element")}getPlugin(t){return this._get(t,this.plugins,"plugin")}getScale(t){return this._get(t,this.scales,"scale")}removeControllers(...t){this._each("unregister",t,this.controllers)}removeElements(...t){this._each("unregister",t,this.elements)}removePlugins(...t){this._each("unregister",t,this.plugins)}removeScales(...t){this._each("unregister",t,this.scales)}_each(t,e,i){[...e].forEach((e=>{const s=i||this._getRegistryForType(e);i||s.isForType(e)||s===this.plugins&&e.id?this._exec(t,s,e):u(e,(e=>{const s=i||this._getRegistryForType(e);this._exec(t,s,e)}))}))}_exec(t,e,i){const s=w(t);d(i["before"+s],[],i),e[t](i),d(i["after"+s],[],i)}_getRegistryForType(t){for(let e=0;et.filter((t=>!e.some((e=>t.plugin.id===e.plugin.id))));this._notify(s(e,i),t,"stop"),this._notify(s(i,e),t,"start")}}function an(t,e){return e||!1!==t?!0===t?{}:t:null}function rn(t,{plugin:e,local:i},s,n){const o=t.pluginScopeKeys(e),a=t.getOptionScopes(s,o);return i&&e.defaults&&a.push(e.defaults),t.createResolver(a,n,[""],{scriptable:!1,indexable:!1,allKeys:!0})}function ln(t,e){const i=ue.datasets[t]||{};return((e.datasets||{})[t]||{}).indexAxis||e.indexAxis||i.indexAxis||"x"}function hn(t){if("x"===t||"y"===t||"r"===t)return t}function cn(t,...e){if(hn(t))return t;for(const s of e){const e=s.axis||("top"===(i=s.position)||"bottom"===i?"x":"left"===i||"right"===i?"y":void 0)||t.length>1&&hn(t[0].toLowerCase());if(e)return e}var i;throw new Error(`Cannot determine type of '${t}' axis. Please provide 'axis' or 'position' option.`)}function dn(t,e,i){if(i[e+"AxisID"]===t)return{axis:e}}function un(t,e){const i=re[t.type]||{scales:{}},s=e.scales||{},n=ln(t.type,e),a=Object.create(null);return Object.keys(s).forEach((e=>{const r=s[e];if(!o(r))return console.error(`Invalid scale configuration for scale: ${e}`);if(r._proxy)return console.warn(`Ignoring resolver passed as options for scale: ${e}`);const l=cn(e,r,function(t,e){if(e.data&&e.data.datasets){const i=e.data.datasets.filter((e=>e.xAxisID===t||e.yAxisID===t));if(i.length)return dn(t,"x",i[0])||dn(t,"y",i[0])}return{}}(e,t),ue.scales[r.type]),h=function(t,e){return t===e?"_index_":"_value_"}(l,n),c=i.scales||{};a[e]=b(Object.create(null),[{axis:l},r,c[l],c[h]])})),t.data.datasets.forEach((i=>{const n=i.type||t.type,o=i.indexAxis||ln(n,e),r=(re[n]||{}).scales||{};Object.keys(r).forEach((t=>{const e=function(t,e){let i=t;return"_index_"===t?i=e:"_value_"===t&&(i="x"===e?"y":"x"),i}(t,o),n=i[e+"AxisID"]||e;a[n]=a[n]||Object.create(null),b(a[n],[{axis:e},s[n],r[t]])}))})),Object.keys(a).forEach((t=>{const e=a[t];b(e,[ue.scales[e.type],ue.scale])})),a}function fn(t){const e=t.options||(t.options={});e.plugins=l(e.plugins,{}),e.scales=un(t,e)}function gn(t){return(t=t||{}).datasets=t.datasets||[],t.labels=t.labels||[],t}const pn=new Map,mn=new Set;function xn(t,e){let i=pn.get(t);return i||(i=e(),pn.set(t,i),mn.add(i)),i}const bn=(t,e,i)=>{const s=M(e,i);void 0!==s&&t.add(s)};class _n{constructor(t){this._config=function(t){return(t=t||{}).data=gn(t.data),fn(t),t}(t),this._scopeCache=new Map,this._resolverCache=new Map}get platform(){return this._config.platform}get type(){return this._config.type}set type(t){this._config.type=t}get data(){return this._config.data}set data(t){this._config.data=gn(t)}get options(){return this._config.options}set options(t){this._config.options=t}get plugins(){return this._config.plugins}update(){const t=this._config;this.clearCache(),fn(t)}clearCache(){this._scopeCache.clear(),this._resolverCache.clear()}datasetScopeKeys(t){return xn(t,(()=>[[`datasets.${t}`,""]]))}datasetAnimationScopeKeys(t,e){return xn(`${t}.transition.${e}`,(()=>[[`datasets.${t}.transitions.${e}`,`transitions.${e}`],[`datasets.${t}`,""]]))}datasetElementScopeKeys(t,e){return xn(`${t}-${e}`,(()=>[[`datasets.${t}.elements.${e}`,`datasets.${t}`,`elements.${e}`,""]]))}pluginScopeKeys(t){const e=t.id;return xn(`${this.type}-plugin-${e}`,(()=>[[`plugins.${e}`,...t.additionalOptionScopes||[]]]))}_cachedScopes(t,e){const i=this._scopeCache;let s=i.get(t);return s&&!e||(s=new Map,i.set(t,s)),s}getOptionScopes(t,e,i){const{options:s,type:n}=this,o=this._cachedScopes(t,i),a=o.get(e);if(a)return a;const r=new Set;e.forEach((e=>{t&&(r.add(t),e.forEach((e=>bn(r,t,e)))),e.forEach((t=>bn(r,s,t))),e.forEach((t=>bn(r,re[n]||{},t))),e.forEach((t=>bn(r,ue,t))),e.forEach((t=>bn(r,le,t)))}));const l=Array.from(r);return 0===l.length&&l.push(Object.create(null)),mn.has(e)&&o.set(e,l),l}chartOptionScopes(){const{options:t,type:e}=this;return[t,re[e]||{},ue.datasets[e]||{},{type:e},ue,le]}resolveNamedOptions(t,e,i,s=[""]){const o={$shared:!0},{resolver:a,subPrefixes:r}=yn(this._resolverCache,t,s);let l=a;if(function(t,e){const{isScriptable:i,isIndexable:s}=Ye(t);for(const o of e){const e=i(o),a=s(o),r=(a||e)&&t[o];if(e&&(S(r)||vn(r))||a&&n(r))return!0}return!1}(a,e)){o.$shared=!1;l=$e(a,i=S(i)?i():i,this.createResolver(t,i,r))}for(const t of e)o[t]=l[t];return o}createResolver(t,e,i=[""],s){const{resolver:n}=yn(this._resolverCache,t,i);return o(e)?$e(n,e,void 0,s):n}}function yn(t,e,i){let s=t.get(e);s||(s=new Map,t.set(e,s));const n=i.join();let o=s.get(n);if(!o){o={resolver:je(e,i),subPrefixes:i.filter((t=>!t.toLowerCase().includes("hover")))},s.set(n,o)}return o}const vn=t=>o(t)&&Object.getOwnPropertyNames(t).some((e=>S(t[e])));const Mn=["top","bottom","left","right","chartArea"];function wn(t,e){return"top"===t||"bottom"===t||-1===Mn.indexOf(t)&&"x"===e}function kn(t,e){return function(i,s){return i[t]===s[t]?i[e]-s[e]:i[t]-s[t]}}function Sn(t){const e=t.chart,i=e.options.animation;e.notifyPlugins("afterRender"),d(i&&i.onComplete,[t],e)}function Pn(t){const e=t.chart,i=e.options.animation;d(i&&i.onProgress,[t],e)}function Dn(t){return fe()&&"string"==typeof t?t=document.getElementById(t):t&&t.length&&(t=t[0]),t&&t.canvas&&(t=t.canvas),t}const Cn={},On=t=>{const e=Dn(t);return Object.values(Cn).filter((t=>t.canvas===e)).pop()};function An(t,e,i){const s=Object.keys(t);for(const n of s){const s=+n;if(s>=e){const o=t[n];delete t[n],(i>0||s>e)&&(t[s+i]=o)}}}class Tn{static defaults=ue;static instances=Cn;static overrides=re;static registry=nn;static version="4.4.9";static getChart=On;static register(...t){nn.add(...t),Ln()}static unregister(...t){nn.remove(...t),Ln()}constructor(t,e){const s=this.config=new _n(e),n=Dn(t),o=On(n);if(o)throw new Error("Canvas is already in use. Chart with ID '"+o.id+"' must be destroyed before the canvas with ID '"+o.canvas.id+"' can be reused.");const a=s.createResolver(s.chartOptionScopes(),this.getContext());this.platform=new(s.platform||Ps(n)),this.platform.updateConfig(s);const r=this.platform.acquireContext(n,a.aspectRatio),l=r&&r.canvas,h=l&&l.height,c=l&&l.width;this.id=i(),this.ctx=r,this.canvas=l,this.width=c,this.height=h,this._options=a,this._aspectRatio=this.aspectRatio,this._layers=[],this._metasets=[],this._stacks=void 0,this.boxes=[],this.currentDevicePixelRatio=void 0,this.chartArea=void 0,this._active=[],this._lastEvent=void 0,this._listeners={},this._responsiveListeners=void 0,this._sortedMetasets=[],this.scales={},this._plugins=new on,this.$proxies={},this._hiddenIndices={},this.attached=!1,this._animationsDisabled=void 0,this.$context=void 0,this._doResize=dt((t=>this.update(t)),a.resizeDelay||0),this._dataChanges=[],Cn[this.id]=this,r&&l?(bt.listen(this,"complete",Sn),bt.listen(this,"progress",Pn),this._initialize(),this.attached&&this.update()):console.error("Failed to create chart: can't acquire context from the given item")}get aspectRatio(){const{options:{aspectRatio:t,maintainAspectRatio:e},width:i,height:n,_aspectRatio:o}=this;return s(t)?e&&o?o:n?i/n:null:t}get data(){return this.config.data}set data(t){this.config.data=t}get options(){return this._options}set options(t){this.config.options=t}get registry(){return nn}_initialize(){return this.notifyPlugins("beforeInit"),this.options.responsive?this.resize():ke(this,this.options.devicePixelRatio),this.bindEvents(),this.notifyPlugins("afterInit"),this}clear(){return Te(this.canvas,this.ctx),this}stop(){return bt.stop(this),this}resize(t,e){bt.running(this)?this._resizeBeforeDraw={width:t,height:e}:this._resize(t,e)}_resize(t,e){const i=this.options,s=this.canvas,n=i.maintainAspectRatio&&this.aspectRatio,o=this.platform.getMaximumSize(s,t,e,n),a=i.devicePixelRatio||this.platform.getDevicePixelRatio(),r=this.width?"resize":"attach";this.width=o.width,this.height=o.height,this._aspectRatio=this.aspectRatio,ke(this,a,!0)&&(this.notifyPlugins("resize",{size:o}),d(i.onResize,[this,o],this),this.attached&&this._doResize(r)&&this.render())}ensureScalesHaveIDs(){u(this.options.scales||{},((t,e)=>{t.id=e}))}buildOrUpdateScales(){const t=this.options,e=t.scales,i=this.scales,s=Object.keys(i).reduce(((t,e)=>(t[e]=!1,t)),{});let n=[];e&&(n=n.concat(Object.keys(e).map((t=>{const i=e[t],s=cn(t,i),n="r"===s,o="x"===s;return{options:i,dposition:n?"chartArea":o?"bottom":"left",dtype:n?"radialLinear":o?"category":"linear"}})))),u(n,(e=>{const n=e.options,o=n.id,a=cn(o,n),r=l(n.type,e.dtype);void 0!==n.position&&wn(n.position,a)===wn(e.dposition)||(n.position=e.dposition),s[o]=!0;let h=null;if(o in i&&i[o].type===r)h=i[o];else{h=new(nn.getScale(r))({id:o,type:r,ctx:this.ctx,chart:this}),i[h.id]=h}h.init(n,t)})),u(s,((t,e)=>{t||delete i[e]})),u(i,(t=>{ls.configure(this,t,t.options),ls.addBox(this,t)}))}_updateMetasets(){const t=this._metasets,e=this.data.datasets.length,i=t.length;if(t.sort(((t,e)=>t.index-e.index)),i>e){for(let t=e;te.length&&delete this._stacks,t.forEach(((t,i)=>{0===e.filter((e=>e===t._dataset)).length&&this._destroyDatasetMeta(i)}))}buildOrUpdateControllers(){const t=[],e=this.data.datasets;let i,s;for(this._removeUnreferencedMetasets(),i=0,s=e.length;i{this.getDatasetMeta(e).controller.reset()}),this)}reset(){this._resetElements(),this.notifyPlugins("reset")}update(t){const e=this.config;e.update();const i=this._options=e.createResolver(e.chartOptionScopes(),this.getContext()),s=this._animationsDisabled=!i.animation;if(this._updateScales(),this._checkEventBindings(),this._updateHiddenIndices(),this._plugins.invalidate(),!1===this.notifyPlugins("beforeUpdate",{mode:t,cancelable:!0}))return;const n=this.buildOrUpdateControllers();this.notifyPlugins("beforeElementsUpdate");let o=0;for(let t=0,e=this.data.datasets.length;t{t.reset()})),this._updateDatasets(t),this.notifyPlugins("afterUpdate",{mode:t}),this._layers.sort(kn("z","_idx"));const{_active:a,_lastEvent:r}=this;r?this._eventHandler(r,!0):a.length&&this._updateHoverStyles(a,a,!0),this.render()}_updateScales(){u(this.scales,(t=>{ls.removeBox(this,t)})),this.ensureScalesHaveIDs(),this.buildOrUpdateScales()}_checkEventBindings(){const t=this.options,e=new Set(Object.keys(this._listeners)),i=new Set(t.events);P(e,i)&&!!this._responsiveListeners===t.responsive||(this.unbindEvents(),this.bindEvents())}_updateHiddenIndices(){const{_hiddenIndices:t}=this,e=this._getUniformDataChanges()||[];for(const{method:i,start:s,count:n}of e){An(t,s,"_removeElements"===i?-n:n)}}_getUniformDataChanges(){const t=this._dataChanges;if(!t||!t.length)return;this._dataChanges=[];const e=this.data.datasets.length,i=e=>new Set(t.filter((t=>t[0]===e)).map(((t,e)=>e+","+t.splice(1).join(",")))),s=i(0);for(let t=1;tt.split(","))).map((t=>({method:t[1],start:+t[2],count:+t[3]})))}_updateLayout(t){if(!1===this.notifyPlugins("beforeLayout",{cancelable:!0}))return;ls.update(this,this.width,this.height,t);const e=this.chartArea,i=e.width<=0||e.height<=0;this._layers=[],u(this.boxes,(t=>{i&&"chartArea"===t.position||(t.configure&&t.configure(),this._layers.push(...t._layers()))}),this),this._layers.forEach(((t,e)=>{t._idx=e})),this.notifyPlugins("afterLayout")}_updateDatasets(t){if(!1!==this.notifyPlugins("beforeDatasetsUpdate",{mode:t,cancelable:!0})){for(let t=0,e=this.data.datasets.length;t=0;--e)this._drawDataset(t[e]);this.notifyPlugins("afterDatasetsDraw")}_drawDataset(t){const e=this.ctx,i={meta:t,index:t.index,cancelable:!0},s=Ni(this,t);!1!==this.notifyPlugins("beforeDatasetDraw",i)&&(s&&Ie(e,s),t.controller.draw(),s&&ze(e),i.cancelable=!1,this.notifyPlugins("afterDatasetDraw",i))}isPointInArea(t){return Re(t,this.chartArea,this._minPadding)}getElementsAtEventForMode(t,e,i,s){const n=Ki.modes[e];return"function"==typeof n?n(this,t,i,s):[]}getDatasetMeta(t){const e=this.data.datasets[t],i=this._metasets;let s=i.filter((t=>t&&t._dataset===e)).pop();return s||(s={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null,order:e&&e.order||0,index:t,_dataset:e,_parsed:[],_sorted:!1},i.push(s)),s}getContext(){return this.$context||(this.$context=Ci(null,{chart:this,type:"chart"}))}getVisibleDatasetCount(){return this.getSortedVisibleDatasetMetas().length}isDatasetVisible(t){const e=this.data.datasets[t];if(!e)return!1;const i=this.getDatasetMeta(t);return"boolean"==typeof i.hidden?!i.hidden:!e.hidden}setDatasetVisibility(t,e){this.getDatasetMeta(t).hidden=!e}toggleDataVisibility(t){this._hiddenIndices[t]=!this._hiddenIndices[t]}getDataVisibility(t){return!this._hiddenIndices[t]}_updateVisibility(t,e,i){const s=i?"show":"hide",n=this.getDatasetMeta(t),o=n.controller._resolveAnimations(void 0,s);k(e)?(n.data[e].hidden=!i,this.update()):(this.setDatasetVisibility(t,i),o.update(n,{visible:i}),this.update((e=>e.datasetIndex===t?s:void 0)))}hide(t,e){this._updateVisibility(t,e,!1)}show(t,e){this._updateVisibility(t,e,!0)}_destroyDatasetMeta(t){const e=this._metasets[t];e&&e.controller&&e.controller._destroy(),delete this._metasets[t]}_stop(){let t,e;for(this.stop(),bt.remove(this),t=0,e=this.data.datasets.length;t{e.addEventListener(this,i,s),t[i]=s},s=(t,e,i)=>{t.offsetX=e,t.offsetY=i,this._eventHandler(t)};u(this.options.events,(t=>i(t,s)))}bindResponsiveEvents(){this._responsiveListeners||(this._responsiveListeners={});const t=this._responsiveListeners,e=this.platform,i=(i,s)=>{e.addEventListener(this,i,s),t[i]=s},s=(i,s)=>{t[i]&&(e.removeEventListener(this,i,s),delete t[i])},n=(t,e)=>{this.canvas&&this.resize(t,e)};let o;const a=()=>{s("attach",a),this.attached=!0,this.resize(),i("resize",n),i("detach",o)};o=()=>{this.attached=!1,s("resize",n),this._stop(),this._resize(0,0),i("attach",a)},e.isAttached(this.canvas)?a():o()}unbindEvents(){u(this._listeners,((t,e)=>{this.platform.removeEventListener(this,e,t)})),this._listeners={},u(this._responsiveListeners,((t,e)=>{this.platform.removeEventListener(this,e,t)})),this._responsiveListeners=void 0}updateHoverStyle(t,e,i){const s=i?"set":"remove";let n,o,a,r;for("dataset"===e&&(n=this.getDatasetMeta(t[0].datasetIndex),n.controller["_"+s+"DatasetHoverStyle"]()),a=0,r=t.length;a{const i=this.getDatasetMeta(t);if(!i)throw new Error("No dataset found at index "+t);return{datasetIndex:t,element:i.data[e],index:e}}));!f(i,e)&&(this._active=i,this._lastEvent=null,this._updateHoverStyles(i,e))}notifyPlugins(t,e,i){return this._plugins.notify(this,t,e,i)}isPluginEnabled(t){return 1===this._plugins._cache.filter((e=>e.plugin.id===t)).length}_updateHoverStyles(t,e,i){const s=this.options.hover,n=(t,e)=>t.filter((t=>!e.some((e=>t.datasetIndex===e.datasetIndex&&t.index===e.index)))),o=n(e,t),a=i?t:n(t,e);o.length&&this.updateHoverStyle(o,s.mode,!1),a.length&&s.mode&&this.updateHoverStyle(a,s.mode,!0)}_eventHandler(t,e){const i={event:t,replay:e,cancelable:!0,inChartArea:this.isPointInArea(t)},s=e=>(e.options.events||this.options.events).includes(t.native.type);if(!1===this.notifyPlugins("beforeEvent",i,s))return;const n=this._handleEvent(t,e,i.inChartArea);return i.cancelable=!1,this.notifyPlugins("afterEvent",i,s),(n||i.changed)&&this.render(),this}_handleEvent(t,e,i){const{_active:s=[],options:n}=this,o=e,a=this._getActiveElements(t,s,i,o),r=D(t),l=function(t,e,i,s){return i&&"mouseout"!==t.type?s?e:t:null}(t,this._lastEvent,i,r);i&&(this._lastEvent=null,d(n.onHover,[t,a,this],this),r&&d(n.onClick,[t,a,this],this));const h=!f(a,s);return(h||e)&&(this._active=a,this._updateHoverStyles(a,s,e)),this._lastEvent=l,h}_getActiveElements(t,e,i,s){if("mouseout"===t.type)return[];if(!i)return e;const n=this.options.hover;return this.getElementsAtEventForMode(t,n.mode,n,s)}}function Ln(){return u(Tn.instances,(t=>t._plugins.invalidate()))}function En(){throw new Error("This method is not implemented: Check that a complete date adapter is provided.")}class Rn{static override(t){Object.assign(Rn.prototype,t)}options;constructor(t){this.options=t||{}}init(){}formats(){return En()}parse(){return En()}format(){return En()}add(){return En()}diff(){return En()}startOf(){return En()}endOf(){return En()}}var In={_date:Rn};function zn(t){const e=t.iScale,i=function(t,e){if(!t._cache.$bar){const i=t.getMatchingVisibleMetas(e);let s=[];for(let e=0,n=i.length;et-e)))}return t._cache.$bar}(e,t.type);let s,n,o,a,r=e._length;const l=()=>{32767!==o&&-32768!==o&&(k(a)&&(r=Math.min(r,Math.abs(o-a)||r)),a=o)};for(s=0,n=i.length;sMath.abs(r)&&(l=r,h=a),e[i.axis]=h,e._custom={barStart:l,barEnd:h,start:n,end:o,min:a,max:r}}(t,e,i,s):e[i.axis]=i.parse(t,s),e}function Vn(t,e,i,s){const n=t.iScale,o=t.vScale,a=n.getLabels(),r=n===o,l=[];let h,c,d,u;for(h=i,c=i+s;ht.x,i="left",s="right"):(e=t.base"spacing"!==t,_indexable:t=>"spacing"!==t&&!t.startsWith("borderDash")&&!t.startsWith("hoverBorderDash")};static overrides={aspectRatio:1,plugins:{legend:{labels:{generateLabels(t){const e=t.data;if(e.labels.length&&e.datasets.length){const{labels:{pointStyle:i,color:s}}=t.legend.options;return e.labels.map(((e,n)=>{const o=t.getDatasetMeta(0).controller.getStyle(n);return{text:e,fillStyle:o.backgroundColor,strokeStyle:o.borderColor,fontColor:s,lineWidth:o.borderWidth,pointStyle:i,hidden:!t.getDataVisibility(n),index:n}}))}return[]}},onClick(t,e,i){i.chart.toggleDataVisibility(e.index),i.chart.update()}}}};constructor(t,e){super(t,e),this.enableOptionSharing=!0,this.innerRadius=void 0,this.outerRadius=void 0,this.offsetX=void 0,this.offsetY=void 0}linkScales(){}parse(t,e){const i=this.getDataset().data,s=this._cachedMeta;if(!1===this._parsing)s._parsed=i;else{let n,a,r=t=>+i[t];if(o(i[t])){const{key:t="value"}=this._parsing;r=e=>+M(i[e],t)}for(n=t,a=t+e;nZ(t,r,l,!0)?1:Math.max(e,e*i,s,s*i),g=(t,e,s)=>Z(t,r,l,!0)?-1:Math.min(e,e*i,s,s*i),p=f(0,h,d),m=f(E,c,u),x=g(C,h,d),b=g(C+E,c,u);s=(p-x)/2,n=(m-b)/2,o=-(p+x)/2,a=-(m+b)/2}return{ratioX:s,ratioY:n,offsetX:o,offsetY:a}}(u,d,r),x=(i.width-o)/f,b=(i.height-o)/g,_=Math.max(Math.min(x,b)/2,0),y=c(this.options.radius,_),v=(y-Math.max(y*r,0))/this._getVisibleDatasetWeightTotal();this.offsetX=p*y,this.offsetY=m*y,s.total=this.calculateTotal(),this.outerRadius=y-v*this._getRingWeightOffset(this.index),this.innerRadius=Math.max(this.outerRadius-v*l,0),this.updateElements(n,0,n.length,t)}_circumference(t,e){const i=this.options,s=this._cachedMeta,n=this._getCircumference();return e&&i.animation.animateRotate||!this.chart.getDataVisibility(t)||null===s._parsed[t]||s.data[t].hidden?0:this.calculateCircumference(s._parsed[t]*n/O)}updateElements(t,e,i,s){const n="reset"===s,o=this.chart,a=o.chartArea,r=o.options.animation,l=(a.left+a.right)/2,h=(a.top+a.bottom)/2,c=n&&r.animateScale,d=c?0:this.innerRadius,u=c?0:this.outerRadius,{sharedOptions:f,includeOptions:g}=this._getSharedOptions(e,s);let p,m=this._getRotation();for(p=0;p0&&!isNaN(t)?O*(Math.abs(t)/e):0}getLabelAndValue(t){const e=this._cachedMeta,i=this.chart,s=i.data.labels||[],n=ne(e._parsed[t],i.options.locale);return{label:s[t]||"",value:n}}getMaxBorderWidth(t){let e=0;const i=this.chart;let s,n,o,a,r;if(!t)for(s=0,n=i.data.datasets.length;s{const o=t.getDatasetMeta(0).controller.getStyle(n);return{text:e,fillStyle:o.backgroundColor,strokeStyle:o.borderColor,fontColor:s,lineWidth:o.borderWidth,pointStyle:i,hidden:!t.getDataVisibility(n),index:n}}))}return[]}},onClick(t,e,i){i.chart.toggleDataVisibility(e.index),i.chart.update()}}},scales:{r:{type:"radialLinear",angleLines:{display:!1},beginAtZero:!0,grid:{circular:!0},pointLabels:{display:!1},startAngle:0}}};constructor(t,e){super(t,e),this.innerRadius=void 0,this.outerRadius=void 0}getLabelAndValue(t){const e=this._cachedMeta,i=this.chart,s=i.data.labels||[],n=ne(e._parsed[t].r,i.options.locale);return{label:s[t]||"",value:n}}parseObjectData(t,e,i,s){return ii.bind(this)(t,e,i,s)}update(t){const e=this._cachedMeta.data;this._updateRadius(),this.updateElements(e,0,e.length,t)}getMinMax(){const t=this._cachedMeta,e={min:Number.POSITIVE_INFINITY,max:Number.NEGATIVE_INFINITY};return t.data.forEach(((t,i)=>{const s=this.getParsed(i).r;!isNaN(s)&&this.chart.getDataVisibility(i)&&(se.max&&(e.max=s))})),e}_updateRadius(){const t=this.chart,e=t.chartArea,i=t.options,s=Math.min(e.right-e.left,e.bottom-e.top),n=Math.max(s/2,0),o=(n-Math.max(i.cutoutPercentage?n/100*i.cutoutPercentage:1,0))/t.getVisibleDatasetCount();this.outerRadius=n-o*this.index,this.innerRadius=this.outerRadius-o}updateElements(t,e,i,s){const n="reset"===s,o=this.chart,a=o.options.animation,r=this._cachedMeta.rScale,l=r.xCenter,h=r.yCenter,c=r.getIndexAngle(0)-.5*C;let d,u=c;const f=360/this.countVisibleElements();for(d=0;d{!isNaN(this.getParsed(i).r)&&this.chart.getDataVisibility(i)&&e++})),e}_computeAngle(t,e,i){return this.chart.getDataVisibility(t)?$(this.resolveDataElementOptions(t,e).angle||i):0}}var Un=Object.freeze({__proto__:null,BarController:class extends js{static id="bar";static defaults={datasetElementType:!1,dataElementType:"bar",categoryPercentage:.8,barPercentage:.9,grouped:!0,animations:{numbers:{type:"number",properties:["x","y","base","width","height"]}}};static overrides={scales:{_index_:{type:"category",offset:!0,grid:{offset:!0}},_value_:{type:"linear",beginAtZero:!0}}};parsePrimitiveData(t,e,i,s){return Vn(t,e,i,s)}parseArrayData(t,e,i,s){return Vn(t,e,i,s)}parseObjectData(t,e,i,s){const{iScale:n,vScale:o}=t,{xAxisKey:a="x",yAxisKey:r="y"}=this._parsing,l="x"===n.axis?a:r,h="x"===o.axis?a:r,c=[];let d,u,f,g;for(d=i,u=i+s;dt.controller.options.grouped)),o=i.options.stacked,a=[],r=this._cachedMeta.controller.getParsed(e),l=r&&r[i.axis],h=t=>{const e=t._parsed.find((t=>t[i.axis]===l)),n=e&&e[t.vScale.axis];if(s(n)||isNaN(n))return!0};for(const i of n)if((void 0===e||!h(i))&&((!1===o||-1===a.indexOf(i.stack)||void 0===o&&void 0===i.stack)&&a.push(i.stack),i.index===t))break;return a.length||a.push(void 0),a}_getStackCount(t){return this._getStacks(void 0,t).length}_getStackIndex(t,e,i){const s=this._getStacks(t,i),n=void 0!==e?s.indexOf(e):-1;return-1===n?s.length-1:n}_getRuler(){const t=this.options,e=this._cachedMeta,i=e.iScale,s=[];let n,o;for(n=0,o=e.data.length;n=i?1:-1)}(u,e,r)*a,f===r&&(x-=u/2);const t=e.getPixelForDecimal(0),s=e.getPixelForDecimal(1),o=Math.min(t,s),h=Math.max(t,s);x=Math.max(Math.min(x,h),o),d=x+u,i&&!c&&(l._stacks[e.axis]._visualValues[n]=e.getValueForPixel(d)-e.getValueForPixel(x))}if(x===e.getPixelForValue(r)){const t=F(u)*e.getLineWidthForValue(r)/2;x+=t,u-=t}return{size:u,base:x,head:d,center:d+u/2}}_calculateBarIndexPixels(t,e){const i=e.scale,n=this.options,o=n.skipNull,a=l(n.maxBarThickness,1/0);let r,h;if(e.grouped){const i=o?this._getStackCount(t):e.stackCount,l="flex"===n.barThickness?function(t,e,i,s){const n=e.pixels,o=n[t];let a=t>0?n[t-1]:null,r=t=0;--i)e=Math.max(e,t[i].size(this.resolveDataElementOptions(i))/2);return e>0&&e}getLabelAndValue(t){const e=this._cachedMeta,i=this.chart.data.labels||[],{xScale:s,yScale:n}=e,o=this.getParsed(t),a=s.getLabelForValue(o.x),r=n.getLabelForValue(o.y),l=o._custom;return{label:i[t]||"",value:"("+a+", "+r+(l?", "+l:"")+")"}}update(t){const e=this._cachedMeta.data;this.updateElements(e,0,e.length,t)}updateElements(t,e,i,s){const n="reset"===s,{iScale:o,vScale:a}=this._cachedMeta,{sharedOptions:r,includeOptions:l}=this._getSharedOptions(e,s),h=o.axis,c=a.axis;for(let d=e;d0&&this.getParsed(e-1);for(let i=0;i<_;++i){const g=t[i],_=x?g:{};if(i=b){_.skip=!0;continue}const v=this.getParsed(i),M=s(v[f]),w=_[u]=a.getPixelForValue(v[u],i),k=_[f]=o||M?r.getBasePixel():r.getPixelForValue(l?this.applyStack(r,v,l):v[f],i);_.skip=isNaN(w)||isNaN(k)||M,_.stop=i>0&&Math.abs(v[u]-y[u])>m,p&&(_.parsed=v,_.raw=h.data[i]),d&&(_.options=c||this.resolveDataElementOptions(i,g.active?"active":n)),x||this.updateElement(g,i,_,n),y=v}}getMaxOverflow(){const t=this._cachedMeta,e=t.dataset,i=e.options&&e.options.borderWidth||0,s=t.data||[];if(!s.length)return i;const n=s[0].size(this.resolveDataElementOptions(0)),o=s[s.length-1].size(this.resolveDataElementOptions(s.length-1));return Math.max(i,n,o)/2}draw(){const t=this._cachedMeta;t.dataset.updateControlPoints(this.chart.chartArea,t.iScale.axis),super.draw()}},PieController:class extends $n{static id="pie";static defaults={cutout:0,rotation:0,circumference:360,radius:"100%"}},PolarAreaController:Yn,RadarController:class extends js{static id="radar";static defaults={datasetElementType:"line",dataElementType:"point",indexAxis:"r",showLine:!0,elements:{line:{fill:"start"}}};static overrides={aspectRatio:1,scales:{r:{type:"radialLinear"}}};getLabelAndValue(t){const e=this._cachedMeta.vScale,i=this.getParsed(t);return{label:e.getLabels()[t],value:""+e.getLabelForValue(i[e.axis])}}parseObjectData(t,e,i,s){return ii.bind(this)(t,e,i,s)}update(t){const e=this._cachedMeta,i=e.dataset,s=e.data||[],n=e.iScale.getLabels();if(i.points=s,"resize"!==t){const e=this.resolveDatasetElementOptions(t);this.options.showLine||(e.borderWidth=0);const o={_loop:!0,_fullLoop:n.length===s.length,options:e};this.updateElement(i,void 0,o,t)}this.updateElements(s,0,s.length,t)}updateElements(t,e,i,s){const n=this._cachedMeta.rScale,o="reset"===s;for(let a=e;a0&&this.getParsed(e-1);for(let c=e;c0&&Math.abs(i[f]-_[f])>x,m&&(p.parsed=i,p.raw=h.data[c]),u&&(p.options=d||this.resolveDataElementOptions(c,e.active?"active":n)),b||this.updateElement(e,c,p,n),_=i}this.updateSharedOptions(d,n,c)}getMaxOverflow(){const t=this._cachedMeta,e=t.data||[];if(!this.options.showLine){let t=0;for(let i=e.length-1;i>=0;--i)t=Math.max(t,e[i].size(this.resolveDataElementOptions(i))/2);return t>0&&t}const i=t.dataset,s=i.options&&i.options.borderWidth||0;if(!e.length)return s;const n=e[0].size(this.resolveDataElementOptions(0)),o=e[e.length-1].size(this.resolveDataElementOptions(e.length-1));return Math.max(s,n,o)/2}}});function Xn(t,e,i,s){const n=vi(t.options.borderRadius,["outerStart","outerEnd","innerStart","innerEnd"]);const o=(i-e)/2,a=Math.min(o,s*e/2),r=t=>{const e=(i-Math.min(o,t))*s/2;return J(t,0,Math.min(o,e))};return{outerStart:r(n.outerStart),outerEnd:r(n.outerEnd),innerStart:J(n.innerStart,0,a),innerEnd:J(n.innerEnd,0,a)}}function qn(t,e,i,s){return{x:i+t*Math.cos(e),y:s+t*Math.sin(e)}}function Kn(t,e,i,s,n,o){const{x:a,y:r,startAngle:l,pixelMargin:h,innerRadius:c}=e,d=Math.max(e.outerRadius+s+i-h,0),u=c>0?c+s+i+h:0;let f=0;const g=n-l;if(s){const t=((c>0?c-s:0)+(d>0?d-s:0))/2;f=(g-(0!==t?g*t/(t+s):g))/2}const p=(g-Math.max(.001,g*d-i/C)/d)/2,m=l+p+f,x=n-p-f,{outerStart:b,outerEnd:_,innerStart:y,innerEnd:v}=Xn(e,u,d,x-m),M=d-b,w=d-_,k=m+b/M,S=x-_/w,P=u+y,D=u+v,O=m+y/P,A=x-v/D;if(t.beginPath(),o){const e=(k+S)/2;if(t.arc(a,r,d,k,e),t.arc(a,r,d,e,S),_>0){const e=qn(w,S,a,r);t.arc(e.x,e.y,_,S,x+E)}const i=qn(D,x,a,r);if(t.lineTo(i.x,i.y),v>0){const e=qn(D,A,a,r);t.arc(e.x,e.y,v,x+E,A+Math.PI)}const s=(x-v/u+(m+y/u))/2;if(t.arc(a,r,u,x-v/u,s,!0),t.arc(a,r,u,s,m+y/u,!0),y>0){const e=qn(P,O,a,r);t.arc(e.x,e.y,y,O+Math.PI,m-E)}const n=qn(M,m,a,r);if(t.lineTo(n.x,n.y),b>0){const e=qn(M,k,a,r);t.arc(e.x,e.y,b,m-E,k)}}else{t.moveTo(a,r);const e=Math.cos(k)*d+a,i=Math.sin(k)*d+r;t.lineTo(e,i);const s=Math.cos(S)*d+a,n=Math.sin(S)*d+r;t.lineTo(s,n)}t.closePath()}function Gn(t,e,i,s,n){const{fullCircles:o,startAngle:a,circumference:r,options:l}=e,{borderWidth:h,borderJoinStyle:c,borderDash:d,borderDashOffset:u}=l,f="inner"===l.borderAlign;if(!h)return;t.setLineDash(d||[]),t.lineDashOffset=u,f?(t.lineWidth=2*h,t.lineJoin=c||"round"):(t.lineWidth=h,t.lineJoin=c||"bevel");let g=e.endAngle;if(o){Kn(t,e,i,s,g,n);for(let e=0;en?(h=n/l,t.arc(o,a,l,i+h,s-h,!0)):t.arc(o,a,n,i+E,s-E),t.closePath(),t.clip()}(t,e,g),o||(Kn(t,e,i,s,g,n),t.stroke())}function Zn(t,e,i=e){t.lineCap=l(i.borderCapStyle,e.borderCapStyle),t.setLineDash(l(i.borderDash,e.borderDash)),t.lineDashOffset=l(i.borderDashOffset,e.borderDashOffset),t.lineJoin=l(i.borderJoinStyle,e.borderJoinStyle),t.lineWidth=l(i.borderWidth,e.borderWidth),t.strokeStyle=l(i.borderColor,e.borderColor)}function Jn(t,e,i){t.lineTo(i.x,i.y)}function Qn(t,e,i={}){const s=t.length,{start:n=0,end:o=s-1}=i,{start:a,end:r}=e,l=Math.max(n,a),h=Math.min(o,r),c=nr&&o>r;return{count:s,start:l,loop:e.loop,ilen:h(a+(h?r-t:t))%o,_=()=>{f!==g&&(t.lineTo(m,g),t.lineTo(m,f),t.lineTo(m,p))};for(l&&(d=n[b(0)],t.moveTo(d.x,d.y)),c=0;c<=r;++c){if(d=n[b(c)],d.skip)continue;const e=d.x,i=d.y,s=0|e;s===u?(ig&&(g=i),m=(x*m+e)/++x):(_(),t.lineTo(e,i),u=s,x=0,f=g=i),p=i}_()}function io(t){const e=t.options,i=e.borderDash&&e.borderDash.length;return!(t._decimated||t._loop||e.tension||"monotone"===e.cubicInterpolationMode||e.stepped||i)?eo:to}const so="function"==typeof Path2D;function no(t,e,i,s){so&&!e.options.segment?function(t,e,i,s){let n=e._path;n||(n=e._path=new Path2D,e.path(n,i,s)&&n.closePath()),Zn(t,e.options),t.stroke(n)}(t,e,i,s):function(t,e,i,s){const{segments:n,options:o}=e,a=io(e);for(const r of n)Zn(t,o,r.style),t.beginPath(),a(t,e,r,{start:i,end:i+s-1})&&t.closePath(),t.stroke()}(t,e,i,s)}class oo extends $s{static id="line";static defaults={borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",borderWidth:3,capBezierPoints:!0,cubicInterpolationMode:"default",fill:!1,spanGaps:!1,stepped:!1,tension:0};static defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"};static descriptors={_scriptable:!0,_indexable:t=>"borderDash"!==t&&"fill"!==t};constructor(t){super(),this.animated=!0,this.options=void 0,this._chart=void 0,this._loop=void 0,this._fullLoop=void 0,this._path=void 0,this._points=void 0,this._segments=void 0,this._decimated=!1,this._pointsUpdated=!1,this._datasetIndex=void 0,t&&Object.assign(this,t)}updateControlPoints(t,e){const i=this.options;if((i.tension||"monotone"===i.cubicInterpolationMode)&&!i.stepped&&!this._pointsUpdated){const s=i.spanGaps?this._loop:this._fullLoop;hi(this._points,i,t,s,e),this._pointsUpdated=!0}}set points(t){this._points=t,delete this._segments,delete this._path,this._pointsUpdated=!1}get points(){return this._points}get segments(){return this._segments||(this._segments=zi(this,this.options.segment))}first(){const t=this.segments,e=this.points;return t.length&&e[t[0].start]}last(){const t=this.segments,e=this.points,i=t.length;return i&&e[t[i-1].end]}interpolate(t,e){const i=this.options,s=t[e],n=this.points,o=Ii(this,{property:e,start:s,end:s});if(!o.length)return;const a=[],r=function(t){return t.stepped?pi:t.tension||"monotone"===t.cubicInterpolationMode?mi:gi}(i);let l,h;for(l=0,h=o.length;l"borderDash"!==t};circumference;endAngle;fullCircles;innerRadius;outerRadius;pixelMargin;startAngle;constructor(t){super(),this.options=void 0,this.circumference=void 0,this.startAngle=void 0,this.endAngle=void 0,this.innerRadius=void 0,this.outerRadius=void 0,this.pixelMargin=0,this.fullCircles=0,t&&Object.assign(this,t)}inRange(t,e,i){const s=this.getProps(["x","y"],i),{angle:n,distance:o}=X(s,{x:t,y:e}),{startAngle:a,endAngle:r,innerRadius:h,outerRadius:c,circumference:d}=this.getProps(["startAngle","endAngle","innerRadius","outerRadius","circumference"],i),u=(this.options.spacing+this.options.borderWidth)/2,f=l(d,r-a),g=Z(n,a,r)&&a!==r,p=f>=O||g,m=tt(o,h+u,c+u);return p&&m}getCenterPoint(t){const{x:e,y:i,startAngle:s,endAngle:n,innerRadius:o,outerRadius:a}=this.getProps(["x","y","startAngle","endAngle","innerRadius","outerRadius"],t),{offset:r,spacing:l}=this.options,h=(s+n)/2,c=(o+a+l+r)/2;return{x:e+Math.cos(h)*c,y:i+Math.sin(h)*c}}tooltipPosition(t){return this.getCenterPoint(t)}draw(t){const{options:e,circumference:i}=this,s=(e.offset||0)/4,n=(e.spacing||0)/2,o=e.circular;if(this.pixelMargin="inner"===e.borderAlign?.33:0,this.fullCircles=i>O?Math.floor(i/O):0,0===i||this.innerRadius<0||this.outerRadius<0)return;t.save();const a=(this.startAngle+this.endAngle)/2;t.translate(Math.cos(a)*s,Math.sin(a)*s);const r=s*(1-Math.sin(Math.min(C,i||0)));t.fillStyle=e.backgroundColor,t.strokeStyle=e.borderColor,function(t,e,i,s,n){const{fullCircles:o,startAngle:a,circumference:r}=e;let l=e.endAngle;if(o){Kn(t,e,i,s,l,n);for(let e=0;e("string"==typeof e?(i=t.push(e)-1,s.unshift({index:i,label:e})):isNaN(e)&&(i=null),i))(t,e,i,s);return n!==t.lastIndexOf(e)?i:n}function mo(t){const e=this.getLabels();return t>=0&&ts=e?s:t,a=t=>n=i?n:t;if(t){const t=F(s),e=F(n);t<0&&e<0?a(0):t>0&&e>0&&o(0)}if(s===n){let e=0===n?1:Math.abs(.05*n);a(n+e),t||o(s-e)}this.min=s,this.max=n}getTickLimit(){const t=this.options.ticks;let e,{maxTicksLimit:i,stepSize:s}=t;return s?(e=Math.ceil(this.max/s)-Math.floor(this.min/s)+1,e>1e3&&(console.warn(`scales.${this.id}.ticks.stepSize: ${s} would result generating up to ${e} ticks. Limiting to 1000.`),e=1e3)):(e=this.computeTickLimit(),i=i||11),i&&(e=Math.min(i,e)),e}computeTickLimit(){return Number.POSITIVE_INFINITY}buildTicks(){const t=this.options,e=t.ticks;let i=this.getTickLimit();i=Math.max(2,i);const n=function(t,e){const i=[],{bounds:n,step:o,min:a,max:r,precision:l,count:h,maxTicks:c,maxDigits:d,includeBounds:u}=t,f=o||1,g=c-1,{min:p,max:m}=e,x=!s(a),b=!s(r),_=!s(h),y=(m-p)/(d+1);let v,M,w,k,S=B((m-p)/g/f)*f;if(S<1e-14&&!x&&!b)return[{value:p},{value:m}];k=Math.ceil(m/S)-Math.floor(p/S),k>g&&(S=B(k*S/g/f)*f),s(l)||(v=Math.pow(10,l),S=Math.ceil(S*v)/v),"ticks"===n?(M=Math.floor(p/S)*S,w=Math.ceil(m/S)*S):(M=p,w=m),x&&b&&o&&H((r-a)/o,S/1e3)?(k=Math.round(Math.min((r-a)/S,c)),S=(r-a)/k,M=a,w=r):_?(M=x?a:M,w=b?r:w,k=h-1,S=(w-M)/k):(k=(w-M)/S,k=V(k,Math.round(k),S/1e3)?Math.round(k):Math.ceil(k));const P=Math.max(U(S),U(M));v=Math.pow(10,s(l)?P:l),M=Math.round(M*v)/v,w=Math.round(w*v)/v;let D=0;for(x&&(u&&M!==a?(i.push({value:a}),Mr)break;i.push({value:t})}return b&&u&&w!==r?i.length&&V(i[i.length-1].value,r,xo(r,y,t))?i[i.length-1].value=r:i.push({value:r}):b&&w!==r||i.push({value:w}),i}({maxTicks:i,bounds:t.bounds,min:t.min,max:t.max,precision:e.precision,step:e.stepSize,count:e.count,maxDigits:this._maxDigits(),horizontal:this.isHorizontal(),minRotation:e.minRotation||0,includeBounds:!1!==e.includeBounds},this._range||this);return"ticks"===t.bounds&&j(n,this,"value"),t.reverse?(n.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),n}configure(){const t=this.ticks;let e=this.min,i=this.max;if(super.configure(),this.options.offset&&t.length){const s=(i-e)/Math.max(t.length-1,1)/2;e-=s,i+=s}this._startValue=e,this._endValue=i,this._valueRange=i-e}getLabelForValue(t){return ne(t,this.chart.options.locale,this.options.ticks.format)}}class _o extends bo{static id="linear";static defaults={ticks:{callback:ae.formatters.numeric}};determineDataLimits(){const{min:t,max:e}=this.getMinMax(!0);this.min=a(t)?t:0,this.max=a(e)?e:1,this.handleTickRangeOptions()}computeTickLimit(){const t=this.isHorizontal(),e=t?this.width:this.height,i=$(this.options.ticks.minRotation),s=(t?Math.sin(i):Math.cos(i))||.001,n=this._resolveTickFontOptions(0);return Math.ceil(e/Math.min(40,n.lineHeight/s))}getPixelForValue(t){return null===t?NaN:this.getPixelForDecimal((t-this._startValue)/this._valueRange)}getValueForPixel(t){return this._startValue+this.getDecimalForPixel(t)*this._valueRange}}const yo=t=>Math.floor(z(t)),vo=(t,e)=>Math.pow(10,yo(t)+e);function Mo(t){return 1===t/Math.pow(10,yo(t))}function wo(t,e,i){const s=Math.pow(10,i),n=Math.floor(t/s);return Math.ceil(e/s)-n}function ko(t,{min:e,max:i}){e=r(t.min,e);const s=[],n=yo(e);let o=function(t,e){let i=yo(e-t);for(;wo(t,e,i)>10;)i++;for(;wo(t,e,i)<10;)i--;return Math.min(i,yo(t))}(e,i),a=o<0?Math.pow(10,Math.abs(o)):1;const l=Math.pow(10,o),h=n>o?Math.pow(10,n):0,c=Math.round((e-h)*a)/a,d=Math.floor((e-h)/l/10)*l*10;let u=Math.floor((c-d)/Math.pow(10,o)),f=r(t.min,Math.round((h+d+u*Math.pow(10,o))*a)/a);for(;f=10?u=u<15?15:20:u++,u>=20&&(o++,u=2,a=o>=0?1:a),f=Math.round((h+d+u*Math.pow(10,o))*a)/a;const g=r(t.max,f);return s.push({value:g,major:Mo(g),significand:u}),s}class So extends tn{static id="logarithmic";static defaults={ticks:{callback:ae.formatters.logarithmic,major:{enabled:!0}}};constructor(t){super(t),this.start=void 0,this.end=void 0,this._startValue=void 0,this._valueRange=0}parse(t,e){const i=bo.prototype.parse.apply(this,[t,e]);if(0!==i)return a(i)&&i>0?i:null;this._zero=!0}determineDataLimits(){const{min:t,max:e}=this.getMinMax(!0);this.min=a(t)?Math.max(0,t):null,this.max=a(e)?Math.max(0,e):null,this.options.beginAtZero&&(this._zero=!0),this._zero&&this.min!==this._suggestedMin&&!a(this._userMin)&&(this.min=t===vo(this.min,0)?vo(this.min,-1):vo(this.min,0)),this.handleTickRangeOptions()}handleTickRangeOptions(){const{minDefined:t,maxDefined:e}=this.getUserBounds();let i=this.min,s=this.max;const n=e=>i=t?i:e,o=t=>s=e?s:t;i===s&&(i<=0?(n(1),o(10)):(n(vo(i,-1)),o(vo(s,1)))),i<=0&&n(vo(s,-1)),s<=0&&o(vo(i,1)),this.min=i,this.max=s}buildTicks(){const t=this.options,e=ko({min:this._userMin,max:this._userMax},this);return"ticks"===t.bounds&&j(e,this,"value"),t.reverse?(e.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),e}getLabelForValue(t){return void 0===t?"0":ne(t,this.chart.options.locale,this.options.ticks.format)}configure(){const t=this.min;super.configure(),this._startValue=z(t),this._valueRange=z(this.max)-z(t)}getPixelForValue(t){return void 0!==t&&0!==t||(t=this.min),null===t||isNaN(t)?NaN:this.getPixelForDecimal(t===this.min?0:(z(t)-this._startValue)/this._valueRange)}getValueForPixel(t){const e=this.getDecimalForPixel(t);return Math.pow(10,this._startValue+e*this._valueRange)}}function Po(t){const e=t.ticks;if(e.display&&t.display){const t=ki(e.backdropPadding);return l(e.font&&e.font.size,ue.font.size)+t.height}return 0}function Do(t,e,i,s,n){return t===s||t===n?{start:e-i/2,end:e+i/2}:tn?{start:e-i,end:e}:{start:e,end:e+i}}function Co(t){const e={l:t.left+t._padding.left,r:t.right-t._padding.right,t:t.top+t._padding.top,b:t.bottom-t._padding.bottom},i=Object.assign({},e),s=[],o=[],a=t._pointLabels.length,r=t.options.pointLabels,l=r.centerPointLabels?C/a:0;for(let u=0;ue.r&&(r=(s.end-e.r)/o,t.r=Math.max(t.r,e.r+r)),n.starte.b&&(l=(n.end-e.b)/a,t.b=Math.max(t.b,e.b+l))}function Ao(t,e,i){const s=t.drawingArea,{extra:n,additionalAngle:o,padding:a,size:r}=i,l=t.getPointPosition(e,s+n+a,o),h=Math.round(Y(G(l.angle+E))),c=function(t,e,i){90===i||270===i?t-=e/2:(i>270||i<90)&&(t-=e);return t}(l.y,r.h,h),d=function(t){if(0===t||180===t)return"center";if(t<180)return"left";return"right"}(h),u=function(t,e,i){"right"===i?t-=e:"center"===i&&(t-=e/2);return t}(l.x,r.w,d);return{visible:!0,x:l.x,y:c,textAlign:d,left:u,top:c,right:u+r.w,bottom:c+r.h}}function To(t,e){if(!e)return!0;const{left:i,top:s,right:n,bottom:o}=t;return!(Re({x:i,y:s},e)||Re({x:i,y:o},e)||Re({x:n,y:s},e)||Re({x:n,y:o},e))}function Lo(t,e,i){const{left:n,top:o,right:a,bottom:r}=i,{backdropColor:l}=e;if(!s(l)){const i=wi(e.borderRadius),s=ki(e.backdropPadding);t.fillStyle=l;const h=n-s.left,c=o-s.top,d=a-n+s.width,u=r-o+s.height;Object.values(i).some((t=>0!==t))?(t.beginPath(),He(t,{x:h,y:c,w:d,h:u,radius:i}),t.fill()):t.fillRect(h,c,d,u)}}function Eo(t,e,i,s){const{ctx:n}=t;if(i)n.arc(t.xCenter,t.yCenter,e,0,O);else{let i=t.getPointPosition(0,e);n.moveTo(i.x,i.y);for(let o=1;ot,padding:5,centerPointLabels:!1}};static defaultRoutes={"angleLines.color":"borderColor","pointLabels.color":"color","ticks.color":"color"};static descriptors={angleLines:{_fallback:"grid"}};constructor(t){super(t),this.xCenter=void 0,this.yCenter=void 0,this.drawingArea=void 0,this._pointLabels=[],this._pointLabelItems=[]}setDimensions(){const t=this._padding=ki(Po(this.options)/2),e=this.width=this.maxWidth-t.width,i=this.height=this.maxHeight-t.height;this.xCenter=Math.floor(this.left+e/2+t.left),this.yCenter=Math.floor(this.top+i/2+t.top),this.drawingArea=Math.floor(Math.min(e,i)/2)}determineDataLimits(){const{min:t,max:e}=this.getMinMax(!1);this.min=a(t)&&!isNaN(t)?t:0,this.max=a(e)&&!isNaN(e)?e:0,this.handleTickRangeOptions()}computeTickLimit(){return Math.ceil(this.drawingArea/Po(this.options))}generateTickLabels(t){bo.prototype.generateTickLabels.call(this,t),this._pointLabels=this.getLabels().map(((t,e)=>{const i=d(this.options.pointLabels.callback,[t,e],this);return i||0===i?i:""})).filter(((t,e)=>this.chart.getDataVisibility(e)))}fit(){const t=this.options;t.display&&t.pointLabels.display?Co(this):this.setCenterPoint(0,0,0,0)}setCenterPoint(t,e,i,s){this.xCenter+=Math.floor((t-e)/2),this.yCenter+=Math.floor((i-s)/2),this.drawingArea-=Math.min(this.drawingArea/2,Math.max(t,e,i,s))}getIndexAngle(t){return G(t*(O/(this._pointLabels.length||1))+$(this.options.startAngle||0))}getDistanceFromCenterForValue(t){if(s(t))return NaN;const e=this.drawingArea/(this.max-this.min);return this.options.reverse?(this.max-t)*e:(t-this.min)*e}getValueForDistanceFromCenter(t){if(s(t))return NaN;const e=t/(this.drawingArea/(this.max-this.min));return this.options.reverse?this.max-e:this.min+e}getPointLabelContext(t){const e=this._pointLabels||[];if(t>=0&&t=0;n--){const e=t._pointLabelItems[n];if(!e.visible)continue;const o=s.setContext(t.getPointLabelContext(n));Lo(i,o,e);const a=Si(o.font),{x:r,y:l,textAlign:h}=e;Ne(i,t._pointLabels[n],r,l+a.lineHeight/2,a,{color:o.color,textAlign:h,textBaseline:"middle"})}}(this,o),s.display&&this.ticks.forEach(((t,e)=>{if(0!==e||0===e&&this.min<0){r=this.getDistanceFromCenterForValue(t.value);const i=this.getContext(e),a=s.setContext(i),l=n.setContext(i);!function(t,e,i,s,n){const o=t.ctx,a=e.circular,{color:r,lineWidth:l}=e;!a&&!s||!r||!l||i<0||(o.save(),o.strokeStyle=r,o.lineWidth=l,o.setLineDash(n.dash||[]),o.lineDashOffset=n.dashOffset,o.beginPath(),Eo(t,i,a,s),o.closePath(),o.stroke(),o.restore())}(this,a,r,o,l)}})),i.display){for(t.save(),a=o-1;a>=0;a--){const s=i.setContext(this.getPointLabelContext(a)),{color:n,lineWidth:o}=s;o&&n&&(t.lineWidth=o,t.strokeStyle=n,t.setLineDash(s.borderDash),t.lineDashOffset=s.borderDashOffset,r=this.getDistanceFromCenterForValue(e.reverse?this.min:this.max),l=this.getPointPosition(a,r),t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(l.x,l.y),t.stroke())}t.restore()}}drawBorder(){}drawLabels(){const t=this.ctx,e=this.options,i=e.ticks;if(!i.display)return;const s=this.getIndexAngle(0);let n,o;t.save(),t.translate(this.xCenter,this.yCenter),t.rotate(s),t.textAlign="center",t.textBaseline="middle",this.ticks.forEach(((s,a)=>{if(0===a&&this.min>=0&&!e.reverse)return;const r=i.setContext(this.getContext(a)),l=Si(r.font);if(n=this.getDistanceFromCenterForValue(this.ticks[a].value),r.showLabelBackdrop){t.font=l.string,o=t.measureText(s.label).width,t.fillStyle=r.backdropColor;const e=ki(r.backdropPadding);t.fillRect(-o/2-e.left,-n-l.size/2-e.top,o+e.width,l.size+e.height)}Ne(t,s.label,0,-n,l,{color:r.color,strokeColor:r.textStrokeColor,strokeWidth:r.textStrokeWidth})})),t.restore()}drawTitle(){}}const Io={millisecond:{common:!0,size:1,steps:1e3},second:{common:!0,size:1e3,steps:60},minute:{common:!0,size:6e4,steps:60},hour:{common:!0,size:36e5,steps:24},day:{common:!0,size:864e5,steps:30},week:{common:!1,size:6048e5,steps:4},month:{common:!0,size:2628e6,steps:12},quarter:{common:!1,size:7884e6,steps:4},year:{common:!0,size:3154e7}},zo=Object.keys(Io);function Fo(t,e){return t-e}function Vo(t,e){if(s(e))return null;const i=t._adapter,{parser:n,round:o,isoWeekday:r}=t._parseOpts;let l=e;return"function"==typeof n&&(l=n(l)),a(l)||(l="string"==typeof n?i.parse(l,n):i.parse(l)),null===l?null:(o&&(l="week"!==o||!N(r)&&!0!==r?i.startOf(l,o):i.startOf(l,"isoWeek",r)),+l)}function Bo(t,e,i,s){const n=zo.length;for(let o=zo.indexOf(t);o=e?i[s]:i[n]]=!0}}else t[e]=!0}function No(t,e,i){const s=[],n={},o=e.length;let a,r;for(a=0;a=0&&(e[l].major=!0);return e}(t,s,n,i):s}class Ho extends tn{static id="time";static defaults={bounds:"data",adapters:{},time:{parser:!1,unit:!1,round:!1,isoWeekday:!1,minUnit:"millisecond",displayFormats:{}},ticks:{source:"auto",callback:!1,major:{enabled:!1}}};constructor(t){super(t),this._cache={data:[],labels:[],all:[]},this._unit="day",this._majorUnit=void 0,this._offsets={},this._normalized=!1,this._parseOpts=void 0}init(t,e={}){const i=t.time||(t.time={}),s=this._adapter=new In._date(t.adapters.date);s.init(e),b(i.displayFormats,s.formats()),this._parseOpts={parser:i.parser,round:i.round,isoWeekday:i.isoWeekday},super.init(t),this._normalized=e.normalized}parse(t,e){return void 0===t?null:Vo(this,t)}beforeLayout(){super.beforeLayout(),this._cache={data:[],labels:[],all:[]}}determineDataLimits(){const t=this.options,e=this._adapter,i=t.time.unit||"day";let{min:s,max:n,minDefined:o,maxDefined:r}=this.getUserBounds();function l(t){o||isNaN(t.min)||(s=Math.min(s,t.min)),r||isNaN(t.max)||(n=Math.max(n,t.max))}o&&r||(l(this._getLabelBounds()),"ticks"===t.bounds&&"labels"===t.ticks.source||l(this.getMinMax(!1))),s=a(s)&&!isNaN(s)?s:+e.startOf(Date.now(),i),n=a(n)&&!isNaN(n)?n:+e.endOf(Date.now(),i)+1,this.min=Math.min(s,n-1),this.max=Math.max(s+1,n)}_getLabelBounds(){const t=this.getLabelTimestamps();let e=Number.POSITIVE_INFINITY,i=Number.NEGATIVE_INFINITY;return t.length&&(e=t[0],i=t[t.length-1]),{min:e,max:i}}buildTicks(){const t=this.options,e=t.time,i=t.ticks,s="labels"===i.source?this.getLabelTimestamps():this._generate();"ticks"===t.bounds&&s.length&&(this.min=this._userMin||s[0],this.max=this._userMax||s[s.length-1]);const n=this.min,o=nt(s,n,this.max);return this._unit=e.unit||(i.autoSkip?Bo(e.minUnit,this.min,this.max,this._getLabelCapacity(n)):function(t,e,i,s,n){for(let o=zo.length-1;o>=zo.indexOf(i);o--){const i=zo[o];if(Io[i].common&&t._adapter.diff(n,s,i)>=e-1)return i}return zo[i?zo.indexOf(i):0]}(this,o.length,e.minUnit,this.min,this.max)),this._majorUnit=i.major.enabled&&"year"!==this._unit?function(t){for(let e=zo.indexOf(t)+1,i=zo.length;e+t.value)))}initOffsets(t=[]){let e,i,s=0,n=0;this.options.offset&&t.length&&(e=this.getDecimalForValue(t[0]),s=1===t.length?1-e:(this.getDecimalForValue(t[1])-e)/2,i=this.getDecimalForValue(t[t.length-1]),n=1===t.length?i:(i-this.getDecimalForValue(t[t.length-2]))/2);const o=t.length<3?.5:.25;s=J(s,0,o),n=J(n,0,o),this._offsets={start:s,end:n,factor:1/(s+1+n)}}_generate(){const t=this._adapter,e=this.min,i=this.max,s=this.options,n=s.time,o=n.unit||Bo(n.minUnit,e,i,this._getLabelCapacity(e)),a=l(s.ticks.stepSize,1),r="week"===o&&n.isoWeekday,h=N(r)||!0===r,c={};let d,u,f=e;if(h&&(f=+t.startOf(f,"isoWeek",r)),f=+t.startOf(f,h?"day":o),t.diff(i,e,o)>1e5*a)throw new Error(e+" and "+i+" are too far apart with stepSize of "+a+" "+o);const g="data"===s.ticks.source&&this.getDataTimestamps();for(d=f,u=0;d+t))}getLabelForValue(t){const e=this._adapter,i=this.options.time;return i.tooltipFormat?e.format(t,i.tooltipFormat):e.format(t,i.displayFormats.datetime)}format(t,e){const i=this.options.time.displayFormats,s=this._unit,n=e||i[s];return this._adapter.format(t,n)}_tickFormatFunction(t,e,i,s){const n=this.options,o=n.ticks.callback;if(o)return d(o,[t,e,i],this);const a=n.time.displayFormats,r=this._unit,l=this._majorUnit,h=r&&a[r],c=l&&a[l],u=i[e],f=l&&c&&u&&u.major;return this._adapter.format(t,s||(f?c:h))}generateTickLabels(t){let e,i,s;for(e=0,i=t.length;e0?a:1}getDataTimestamps(){let t,e,i=this._cache.data||[];if(i.length)return i;const s=this.getMatchingVisibleMetas();if(this._normalized&&s.length)return this._cache.data=s[0].controller.getAllParsedValues(this);for(t=0,e=s.length;t=t[r].pos&&e<=t[l].pos&&({lo:r,hi:l}=it(t,"pos",e)),({pos:s,time:o}=t[r]),({pos:n,time:a}=t[l])):(e>=t[r].time&&e<=t[l].time&&({lo:r,hi:l}=it(t,"time",e)),({time:s,pos:o}=t[r]),({time:n,pos:a}=t[l]));const h=n-s;return h?o+(a-o)*(e-s)/h:o}var $o=Object.freeze({__proto__:null,CategoryScale:class extends tn{static id="category";static defaults={ticks:{callback:mo}};constructor(t){super(t),this._startValue=void 0,this._valueRange=0,this._addedLabels=[]}init(t){const e=this._addedLabels;if(e.length){const t=this.getLabels();for(const{index:i,label:s}of e)t[i]===s&&t.splice(i,1);this._addedLabels=[]}super.init(t)}parse(t,e){if(s(t))return null;const i=this.getLabels();return((t,e)=>null===t?null:J(Math.round(t),0,e))(e=isFinite(e)&&i[e]===t?e:po(i,t,l(e,t),this._addedLabels),i.length-1)}determineDataLimits(){const{minDefined:t,maxDefined:e}=this.getUserBounds();let{min:i,max:s}=this.getMinMax(!0);"ticks"===this.options.bounds&&(t||(i=0),e||(s=this.getLabels().length-1)),this.min=i,this.max=s}buildTicks(){const t=this.min,e=this.max,i=this.options.offset,s=[];let n=this.getLabels();n=0===t&&e===n.length-1?n:n.slice(t,e+1),this._valueRange=Math.max(n.length-(i?0:1),1),this._startValue=this.min-(i?.5:0);for(let i=t;i<=e;i++)s.push({value:i});return s}getLabelForValue(t){return mo.call(this,t)}configure(){super.configure(),this.isHorizontal()||(this._reversePixels=!this._reversePixels)}getPixelForValue(t){return"number"!=typeof t&&(t=this.parse(t)),null===t?NaN:this.getPixelForDecimal((t-this._startValue)/this._valueRange)}getPixelForTick(t){const e=this.ticks;return t<0||t>e.length-1?null:this.getPixelForValue(e[t].value)}getValueForPixel(t){return Math.round(this._startValue+this.getDecimalForPixel(t)*this._valueRange)}getBasePixel(){return this.bottom}},LinearScale:_o,LogarithmicScale:So,RadialLinearScale:Ro,TimeScale:Ho,TimeSeriesScale:class extends Ho{static id="timeseries";static defaults=Ho.defaults;constructor(t){super(t),this._table=[],this._minPos=void 0,this._tableRange=void 0}initOffsets(){const t=this._getTimestampsForTable(),e=this._table=this.buildLookupTable(t);this._minPos=jo(e,this.min),this._tableRange=jo(e,this.max)-this._minPos,super.initOffsets(t)}buildLookupTable(t){const{min:e,max:i}=this,s=[],n=[];let o,a,r,l,h;for(o=0,a=t.length;o=e&&l<=i&&s.push(l);if(s.length<2)return[{time:e,pos:0},{time:i,pos:1}];for(o=0,a=s.length;ot-e))}_getTimestampsForTable(){let t=this._cache.all||[];if(t.length)return t;const e=this.getDataTimestamps(),i=this.getLabelTimestamps();return t=e.length&&i.length?this.normalize(e.concat(i)):e.length?e:i,t=this._cache.all=t,t}getDecimalForValue(t){return(jo(this._table,t)-this._minPos)/this._tableRange}getValueForPixel(t){const e=this._offsets,i=this.getDecimalForPixel(t)/e.factor-e.end;return jo(this._table,i*this._tableRange+this._minPos,!0)}}});const Yo=["rgb(54, 162, 235)","rgb(255, 99, 132)","rgb(255, 159, 64)","rgb(255, 205, 86)","rgb(75, 192, 192)","rgb(153, 102, 255)","rgb(201, 203, 207)"],Uo=Yo.map((t=>t.replace("rgb(","rgba(").replace(")",", 0.5)")));function Xo(t){return Yo[t%Yo.length]}function qo(t){return Uo[t%Uo.length]}function Ko(t){let e=0;return(i,s)=>{const n=t.getDatasetMeta(s).controller;n instanceof $n?e=function(t,e){return t.backgroundColor=t.data.map((()=>Xo(e++))),e}(i,e):n instanceof Yn?e=function(t,e){return t.backgroundColor=t.data.map((()=>qo(e++))),e}(i,e):n&&(e=function(t,e){return t.borderColor=Xo(e),t.backgroundColor=qo(e),++e}(i,e))}}function Go(t){let e;for(e in t)if(t[e].borderColor||t[e].backgroundColor)return!0;return!1}var Zo={id:"colors",defaults:{enabled:!0,forceOverride:!1},beforeLayout(t,e,i){if(!i.enabled)return;const{data:{datasets:s},options:n}=t.config,{elements:o}=n,a=Go(s)||(r=n)&&(r.borderColor||r.backgroundColor)||o&&Go(o)||"rgba(0,0,0,0.1)"!==ue.borderColor||"rgba(0,0,0,0.1)"!==ue.backgroundColor;var r;if(!i.forceOverride&&a)return;const l=Ko(t);s.forEach(l)}};function Jo(t){if(t._decimated){const e=t._data;delete t._decimated,delete t._data,Object.defineProperty(t,"data",{configurable:!0,enumerable:!0,writable:!0,value:e})}}function Qo(t){t.data.datasets.forEach((t=>{Jo(t)}))}var ta={id:"decimation",defaults:{algorithm:"min-max",enabled:!1},beforeElementsUpdate:(t,e,i)=>{if(!i.enabled)return void Qo(t);const n=t.width;t.data.datasets.forEach(((e,o)=>{const{_data:a,indexAxis:r}=e,l=t.getDatasetMeta(o),h=a||e.data;if("y"===Pi([r,t.options.indexAxis]))return;if(!l.controller.supportsDecimation)return;const c=t.scales[l.xAxisID];if("linear"!==c.type&&"time"!==c.type)return;if(t.options.parsing)return;let{start:d,count:u}=function(t,e){const i=e.length;let s,n=0;const{iScale:o}=t,{min:a,max:r,minDefined:l,maxDefined:h}=o.getUserBounds();return l&&(n=J(it(e,o.axis,a).lo,0,i-1)),s=h?J(it(e,o.axis,r).hi+1,n,i)-n:i-n,{start:n,count:s}}(l,h);if(u<=(i.threshold||4*n))return void Jo(e);let f;switch(s(a)&&(e._data=h,delete e.data,Object.defineProperty(e,"data",{configurable:!0,enumerable:!0,get:function(){return this._decimated},set:function(t){this._data=t}})),i.algorithm){case"lttb":f=function(t,e,i,s,n){const o=n.samples||s;if(o>=i)return t.slice(e,e+i);const a=[],r=(i-2)/(o-2);let l=0;const h=e+i-1;let c,d,u,f,g,p=e;for(a[l++]=t[p],c=0;cu&&(u=f,d=t[s],g=s);a[l++]=d,p=g}return a[l++]=t[h],a}(h,d,u,n,i);break;case"min-max":f=function(t,e,i,n){let o,a,r,l,h,c,d,u,f,g,p=0,m=0;const x=[],b=e+i-1,_=t[e].x,y=t[b].x-_;for(o=e;og&&(g=l,d=o),p=(m*p+a.x)/++m;else{const i=o-1;if(!s(c)&&!s(d)){const e=Math.min(c,d),s=Math.max(c,d);e!==u&&e!==i&&x.push({...t[e],x:p}),s!==u&&s!==i&&x.push({...t[s],x:p})}o>0&&i!==u&&x.push(t[i]),x.push(a),h=e,m=0,f=g=l,c=d=u=o}}return x}(h,d,u,n);break;default:throw new Error(`Unsupported decimation algorithm '${i.algorithm}'`)}e._decimated=f}))},destroy(t){Qo(t)}};function ea(t,e,i,s){if(s)return;let n=e[t],o=i[t];return"angle"===t&&(n=G(n),o=G(o)),{property:t,start:n,end:o}}function ia(t,e,i){for(;e>t;e--){const t=i[e];if(!isNaN(t.x)&&!isNaN(t.y))break}return e}function sa(t,e,i,s){return t&&e?s(t[i],e[i]):t?t[i]:e?e[i]:0}function na(t,e){let i=[],s=!1;return n(t)?(s=!0,i=t):i=function(t,e){const{x:i=null,y:s=null}=t||{},n=e.points,o=[];return e.segments.forEach((({start:t,end:e})=>{e=ia(t,e,n);const a=n[t],r=n[e];null!==s?(o.push({x:a.x,y:s}),o.push({x:r.x,y:s})):null!==i&&(o.push({x:i,y:a.y}),o.push({x:i,y:r.y}))})),o}(t,e),i.length?new oo({points:i,options:{tension:0},_loop:s,_fullLoop:s}):null}function oa(t){return t&&!1!==t.fill}function aa(t,e,i){let s=t[e].fill;const n=[e];let o;if(!i)return s;for(;!1!==s&&-1===n.indexOf(s);){if(!a(s))return s;if(o=t[s],!o)return!1;if(o.visible)return s;n.push(s),s=o.fill}return!1}function ra(t,e,i){const s=function(t){const e=t.options,i=e.fill;let s=l(i&&i.target,i);void 0===s&&(s=!!e.backgroundColor);if(!1===s||null===s)return!1;if(!0===s)return"origin";return s}(t);if(o(s))return!isNaN(s.value)&&s;let n=parseFloat(s);return a(n)&&Math.floor(n)===n?function(t,e,i,s){"-"!==t&&"+"!==t||(i=e+i);if(i===e||i<0||i>=s)return!1;return i}(s[0],e,n,i):["origin","start","end","stack","shape"].indexOf(s)>=0&&s}function la(t,e,i){const s=[];for(let n=0;n=0;--e){const i=n[e].$filler;i&&(i.line.updateControlPoints(o,i.axis),s&&i.fill&&ua(t.ctx,i,o))}},beforeDatasetsDraw(t,e,i){if("beforeDatasetsDraw"!==i.drawTime)return;const s=t.getSortedVisibleDatasetMetas();for(let e=s.length-1;e>=0;--e){const i=s[e].$filler;oa(i)&&ua(t.ctx,i,t.chartArea)}},beforeDatasetDraw(t,e,i){const s=e.meta.$filler;oa(s)&&"beforeDatasetDraw"===i.drawTime&&ua(t.ctx,s,t.chartArea)},defaults:{propagate:!0,drawTime:"beforeDatasetDraw"}};const ba=(t,e)=>{let{boxHeight:i=e,boxWidth:s=e}=t;return t.usePointStyle&&(i=Math.min(i,e),s=t.pointStyleWidth||Math.min(s,e)),{boxWidth:s,boxHeight:i,itemHeight:Math.max(e,i)}};class _a extends $s{constructor(t){super(),this._added=!1,this.legendHitBoxes=[],this._hoveredItem=null,this.doughnutMode=!1,this.chart=t.chart,this.options=t.options,this.ctx=t.ctx,this.legendItems=void 0,this.columnSizes=void 0,this.lineWidths=void 0,this.maxHeight=void 0,this.maxWidth=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.height=void 0,this.width=void 0,this._margins=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(t,e,i){this.maxWidth=t,this.maxHeight=e,this._margins=i,this.setDimensions(),this.buildLabels(),this.fit()}setDimensions(){this.isHorizontal()?(this.width=this.maxWidth,this.left=this._margins.left,this.right=this.width):(this.height=this.maxHeight,this.top=this._margins.top,this.bottom=this.height)}buildLabels(){const t=this.options.labels||{};let e=d(t.generateLabels,[this.chart],this)||[];t.filter&&(e=e.filter((e=>t.filter(e,this.chart.data)))),t.sort&&(e=e.sort(((e,i)=>t.sort(e,i,this.chart.data)))),this.options.reverse&&e.reverse(),this.legendItems=e}fit(){const{options:t,ctx:e}=this;if(!t.display)return void(this.width=this.height=0);const i=t.labels,s=Si(i.font),n=s.size,o=this._computeTitleHeight(),{boxWidth:a,itemHeight:r}=ba(i,n);let l,h;e.font=s.string,this.isHorizontal()?(l=this.maxWidth,h=this._fitRows(o,n,a,r)+10):(h=this.maxHeight,l=this._fitCols(o,s,a,r)+10),this.width=Math.min(l,t.maxWidth||this.maxWidth),this.height=Math.min(h,t.maxHeight||this.maxHeight)}_fitRows(t,e,i,s){const{ctx:n,maxWidth:o,options:{labels:{padding:a}}}=this,r=this.legendHitBoxes=[],l=this.lineWidths=[0],h=s+a;let c=t;n.textAlign="left",n.textBaseline="middle";let d=-1,u=-h;return this.legendItems.forEach(((t,f)=>{const g=i+e/2+n.measureText(t.text).width;(0===f||l[l.length-1]+g+2*a>o)&&(c+=h,l[l.length-(f>0?0:1)]=0,u+=h,d++),r[f]={left:0,top:u,row:d,width:g,height:s},l[l.length-1]+=g+a})),c}_fitCols(t,e,i,s){const{ctx:n,maxHeight:o,options:{labels:{padding:a}}}=this,r=this.legendHitBoxes=[],l=this.columnSizes=[],h=o-t;let c=a,d=0,u=0,f=0,g=0;return this.legendItems.forEach(((t,o)=>{const{itemWidth:p,itemHeight:m}=function(t,e,i,s,n){const o=function(t,e,i,s){let n=t.text;n&&"string"!=typeof n&&(n=n.reduce(((t,e)=>t.length>e.length?t:e)));return e+i.size/2+s.measureText(n).width}(s,t,e,i),a=function(t,e,i){let s=t;"string"!=typeof e.text&&(s=ya(e,i));return s}(n,s,e.lineHeight);return{itemWidth:o,itemHeight:a}}(i,e,n,t,s);o>0&&u+m+2*a>h&&(c+=d+a,l.push({width:d,height:u}),f+=d+a,g++,d=u=0),r[o]={left:f,top:u,col:g,width:p,height:m},d=Math.max(d,p),u+=m+a})),c+=d,l.push({width:d,height:u}),c}adjustHitBoxes(){if(!this.options.display)return;const t=this._computeTitleHeight(),{legendHitBoxes:e,options:{align:i,labels:{padding:s},rtl:n}}=this,o=Oi(n,this.left,this.width);if(this.isHorizontal()){let n=0,a=ft(i,this.left+s,this.right-this.lineWidths[n]);for(const r of e)n!==r.row&&(n=r.row,a=ft(i,this.left+s,this.right-this.lineWidths[n])),r.top+=this.top+t+s,r.left=o.leftForLtr(o.x(a),r.width),a+=r.width+s}else{let n=0,a=ft(i,this.top+t+s,this.bottom-this.columnSizes[n].height);for(const r of e)r.col!==n&&(n=r.col,a=ft(i,this.top+t+s,this.bottom-this.columnSizes[n].height)),r.top=a,r.left+=this.left+s,r.left=o.leftForLtr(o.x(r.left),r.width),a+=r.height+s}}isHorizontal(){return"top"===this.options.position||"bottom"===this.options.position}draw(){if(this.options.display){const t=this.ctx;Ie(t,this),this._draw(),ze(t)}}_draw(){const{options:t,columnSizes:e,lineWidths:i,ctx:s}=this,{align:n,labels:o}=t,a=ue.color,r=Oi(t.rtl,this.left,this.width),h=Si(o.font),{padding:c}=o,d=h.size,u=d/2;let f;this.drawTitle(),s.textAlign=r.textAlign("left"),s.textBaseline="middle",s.lineWidth=.5,s.font=h.string;const{boxWidth:g,boxHeight:p,itemHeight:m}=ba(o,d),x=this.isHorizontal(),b=this._computeTitleHeight();f=x?{x:ft(n,this.left+c,this.right-i[0]),y:this.top+c+b,line:0}:{x:this.left+c,y:ft(n,this.top+b+c,this.bottom-e[0].height),line:0},Ai(this.ctx,t.textDirection);const _=m+c;this.legendItems.forEach(((y,v)=>{s.strokeStyle=y.fontColor,s.fillStyle=y.fontColor;const M=s.measureText(y.text).width,w=r.textAlign(y.textAlign||(y.textAlign=o.textAlign)),k=g+u+M;let S=f.x,P=f.y;r.setWidth(this.width),x?v>0&&S+k+c>this.right&&(P=f.y+=_,f.line++,S=f.x=ft(n,this.left+c,this.right-i[f.line])):v>0&&P+_>this.bottom&&(S=f.x=S+e[f.line].width+c,f.line++,P=f.y=ft(n,this.top+b+c,this.bottom-e[f.line].height));if(function(t,e,i){if(isNaN(g)||g<=0||isNaN(p)||p<0)return;s.save();const n=l(i.lineWidth,1);if(s.fillStyle=l(i.fillStyle,a),s.lineCap=l(i.lineCap,"butt"),s.lineDashOffset=l(i.lineDashOffset,0),s.lineJoin=l(i.lineJoin,"miter"),s.lineWidth=n,s.strokeStyle=l(i.strokeStyle,a),s.setLineDash(l(i.lineDash,[])),o.usePointStyle){const a={radius:p*Math.SQRT2/2,pointStyle:i.pointStyle,rotation:i.rotation,borderWidth:n},l=r.xPlus(t,g/2);Ee(s,a,l,e+u,o.pointStyleWidth&&g)}else{const o=e+Math.max((d-p)/2,0),a=r.leftForLtr(t,g),l=wi(i.borderRadius);s.beginPath(),Object.values(l).some((t=>0!==t))?He(s,{x:a,y:o,w:g,h:p,radius:l}):s.rect(a,o,g,p),s.fill(),0!==n&&s.stroke()}s.restore()}(r.x(S),P,y),S=gt(w,S+g+u,x?S+k:this.right,t.rtl),function(t,e,i){Ne(s,i.text,t,e+m/2,h,{strikethrough:i.hidden,textAlign:r.textAlign(i.textAlign)})}(r.x(S),P,y),x)f.x+=k+c;else if("string"!=typeof y.text){const t=h.lineHeight;f.y+=ya(y,t)+c}else f.y+=_})),Ti(this.ctx,t.textDirection)}drawTitle(){const t=this.options,e=t.title,i=Si(e.font),s=ki(e.padding);if(!e.display)return;const n=Oi(t.rtl,this.left,this.width),o=this.ctx,a=e.position,r=i.size/2,l=s.top+r;let h,c=this.left,d=this.width;if(this.isHorizontal())d=Math.max(...this.lineWidths),h=this.top+l,c=ft(t.align,c,this.right-d);else{const e=this.columnSizes.reduce(((t,e)=>Math.max(t,e.height)),0);h=l+ft(t.align,this.top,this.bottom-e-t.labels.padding-this._computeTitleHeight())}const u=ft(a,c,c+d);o.textAlign=n.textAlign(ut(a)),o.textBaseline="middle",o.strokeStyle=e.color,o.fillStyle=e.color,o.font=i.string,Ne(o,e.text,u,h,i)}_computeTitleHeight(){const t=this.options.title,e=Si(t.font),i=ki(t.padding);return t.display?e.lineHeight+i.height:0}_getLegendItemAt(t,e){let i,s,n;if(tt(t,this.left,this.right)&&tt(e,this.top,this.bottom))for(n=this.legendHitBoxes,i=0;it.chart.options.color,boxWidth:40,padding:10,generateLabels(t){const e=t.data.datasets,{labels:{usePointStyle:i,pointStyle:s,textAlign:n,color:o,useBorderRadius:a,borderRadius:r}}=t.legend.options;return t._getSortedDatasetMetas().map((t=>{const l=t.controller.getStyle(i?0:void 0),h=ki(l.borderWidth);return{text:e[t.index].label,fillStyle:l.backgroundColor,fontColor:o,hidden:!t.visible,lineCap:l.borderCapStyle,lineDash:l.borderDash,lineDashOffset:l.borderDashOffset,lineJoin:l.borderJoinStyle,lineWidth:(h.width+h.height)/4,strokeStyle:l.borderColor,pointStyle:s||l.pointStyle,rotation:l.rotation,textAlign:n||l.textAlign,borderRadius:a&&(r||l.borderRadius),datasetIndex:t.index}}),this)}},title:{color:t=>t.chart.options.color,display:!1,position:"center",text:""}},descriptors:{_scriptable:t=>!t.startsWith("on"),labels:{_scriptable:t=>!["generateLabels","filter","sort"].includes(t)}}};class Ma extends $s{constructor(t){super(),this.chart=t.chart,this.options=t.options,this.ctx=t.ctx,this._padding=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(t,e){const i=this.options;if(this.left=0,this.top=0,!i.display)return void(this.width=this.height=this.right=this.bottom=0);this.width=this.right=t,this.height=this.bottom=e;const s=n(i.text)?i.text.length:1;this._padding=ki(i.padding);const o=s*Si(i.font).lineHeight+this._padding.height;this.isHorizontal()?this.height=o:this.width=o}isHorizontal(){const t=this.options.position;return"top"===t||"bottom"===t}_drawArgs(t){const{top:e,left:i,bottom:s,right:n,options:o}=this,a=o.align;let r,l,h,c=0;return this.isHorizontal()?(l=ft(a,i,n),h=e+t,r=n-i):("left"===o.position?(l=i+t,h=ft(a,s,e),c=-.5*C):(l=n-t,h=ft(a,e,s),c=.5*C),r=s-e),{titleX:l,titleY:h,maxWidth:r,rotation:c}}draw(){const t=this.ctx,e=this.options;if(!e.display)return;const i=Si(e.font),s=i.lineHeight/2+this._padding.top,{titleX:n,titleY:o,maxWidth:a,rotation:r}=this._drawArgs(s);Ne(t,e.text,0,0,i,{color:e.color,maxWidth:a,rotation:r,textAlign:ut(e.align),textBaseline:"middle",translation:[n,o]})}}var wa={id:"title",_element:Ma,start(t,e,i){!function(t,e){const i=new Ma({ctx:t.ctx,options:e,chart:t});ls.configure(t,i,e),ls.addBox(t,i),t.titleBlock=i}(t,i)},stop(t){const e=t.titleBlock;ls.removeBox(t,e),delete t.titleBlock},beforeUpdate(t,e,i){const s=t.titleBlock;ls.configure(t,s,i),s.options=i},defaults:{align:"center",display:!1,font:{weight:"bold"},fullSize:!0,padding:10,position:"top",text:"",weight:2e3},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const ka=new WeakMap;var Sa={id:"subtitle",start(t,e,i){const s=new Ma({ctx:t.ctx,options:i,chart:t});ls.configure(t,s,i),ls.addBox(t,s),ka.set(t,s)},stop(t){ls.removeBox(t,ka.get(t)),ka.delete(t)},beforeUpdate(t,e,i){const s=ka.get(t);ls.configure(t,s,i),s.options=i},defaults:{align:"center",display:!1,font:{weight:"normal"},fullSize:!0,padding:0,position:"top",text:"",weight:1500},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const Pa={average(t){if(!t.length)return!1;let e,i,s=new Set,n=0,o=0;for(e=0,i=t.length;et+e))/s.size,y:n/o}},nearest(t,e){if(!t.length)return!1;let i,s,n,o=e.x,a=e.y,r=Number.POSITIVE_INFINITY;for(i=0,s=t.length;i-1?t.split("\n"):t}function Oa(t,e){const{element:i,datasetIndex:s,index:n}=e,o=t.getDatasetMeta(s).controller,{label:a,value:r}=o.getLabelAndValue(n);return{chart:t,label:a,parsed:o.getParsed(n),raw:t.data.datasets[s].data[n],formattedValue:r,dataset:o.getDataset(),dataIndex:n,datasetIndex:s,element:i}}function Aa(t,e){const i=t.chart.ctx,{body:s,footer:n,title:o}=t,{boxWidth:a,boxHeight:r}=e,l=Si(e.bodyFont),h=Si(e.titleFont),c=Si(e.footerFont),d=o.length,f=n.length,g=s.length,p=ki(e.padding);let m=p.height,x=0,b=s.reduce(((t,e)=>t+e.before.length+e.lines.length+e.after.length),0);if(b+=t.beforeBody.length+t.afterBody.length,d&&(m+=d*h.lineHeight+(d-1)*e.titleSpacing+e.titleMarginBottom),b){m+=g*(e.displayColors?Math.max(r,l.lineHeight):l.lineHeight)+(b-g)*l.lineHeight+(b-1)*e.bodySpacing}f&&(m+=e.footerMarginTop+f*c.lineHeight+(f-1)*e.footerSpacing);let _=0;const y=function(t){x=Math.max(x,i.measureText(t).width+_)};return i.save(),i.font=h.string,u(t.title,y),i.font=l.string,u(t.beforeBody.concat(t.afterBody),y),_=e.displayColors?a+2+e.boxPadding:0,u(s,(t=>{u(t.before,y),u(t.lines,y),u(t.after,y)})),_=0,i.font=c.string,u(t.footer,y),i.restore(),x+=p.width,{width:x,height:m}}function Ta(t,e,i,s){const{x:n,width:o}=i,{width:a,chartArea:{left:r,right:l}}=t;let h="center";return"center"===s?h=n<=(r+l)/2?"left":"right":n<=o/2?h="left":n>=a-o/2&&(h="right"),function(t,e,i,s){const{x:n,width:o}=s,a=i.caretSize+i.caretPadding;return"left"===t&&n+o+a>e.width||"right"===t&&n-o-a<0||void 0}(h,t,e,i)&&(h="center"),h}function La(t,e,i){const s=i.yAlign||e.yAlign||function(t,e){const{y:i,height:s}=e;return it.height-s/2?"bottom":"center"}(t,i);return{xAlign:i.xAlign||e.xAlign||Ta(t,e,i,s),yAlign:s}}function Ea(t,e,i,s){const{caretSize:n,caretPadding:o,cornerRadius:a}=t,{xAlign:r,yAlign:l}=i,h=n+o,{topLeft:c,topRight:d,bottomLeft:u,bottomRight:f}=wi(a);let g=function(t,e){let{x:i,width:s}=t;return"right"===e?i-=s:"center"===e&&(i-=s/2),i}(e,r);const p=function(t,e,i){let{y:s,height:n}=t;return"top"===e?s+=i:s-="bottom"===e?n+i:n/2,s}(e,l,h);return"center"===l?"left"===r?g+=h:"right"===r&&(g-=h):"left"===r?g-=Math.max(c,u)+n:"right"===r&&(g+=Math.max(d,f)+n),{x:J(g,0,s.width-e.width),y:J(p,0,s.height-e.height)}}function Ra(t,e,i){const s=ki(i.padding);return"center"===e?t.x+t.width/2:"right"===e?t.x+t.width-s.right:t.x+s.left}function Ia(t){return Da([],Ca(t))}function za(t,e){const i=e&&e.dataset&&e.dataset.tooltip&&e.dataset.tooltip.callbacks;return i?t.override(i):t}const Fa={beforeTitle:e,title(t){if(t.length>0){const e=t[0],i=e.chart.data.labels,s=i?i.length:0;if(this&&this.options&&"dataset"===this.options.mode)return e.dataset.label||"";if(e.label)return e.label;if(s>0&&e.dataIndex{const e={before:[],lines:[],after:[]},n=za(i,t);Da(e.before,Ca(Va(n,"beforeLabel",this,t))),Da(e.lines,Va(n,"label",this,t)),Da(e.after,Ca(Va(n,"afterLabel",this,t))),s.push(e)})),s}getAfterBody(t,e){return Ia(Va(e.callbacks,"afterBody",this,t))}getFooter(t,e){const{callbacks:i}=e,s=Va(i,"beforeFooter",this,t),n=Va(i,"footer",this,t),o=Va(i,"afterFooter",this,t);let a=[];return a=Da(a,Ca(s)),a=Da(a,Ca(n)),a=Da(a,Ca(o)),a}_createItems(t){const e=this._active,i=this.chart.data,s=[],n=[],o=[];let a,r,l=[];for(a=0,r=e.length;at.filter(e,s,n,i)))),t.itemSort&&(l=l.sort(((e,s)=>t.itemSort(e,s,i)))),u(l,(e=>{const i=za(t.callbacks,e);s.push(Va(i,"labelColor",this,e)),n.push(Va(i,"labelPointStyle",this,e)),o.push(Va(i,"labelTextColor",this,e))})),this.labelColors=s,this.labelPointStyles=n,this.labelTextColors=o,this.dataPoints=l,l}update(t,e){const i=this.options.setContext(this.getContext()),s=this._active;let n,o=[];if(s.length){const t=Pa[i.position].call(this,s,this._eventPosition);o=this._createItems(i),this.title=this.getTitle(o,i),this.beforeBody=this.getBeforeBody(o,i),this.body=this.getBody(o,i),this.afterBody=this.getAfterBody(o,i),this.footer=this.getFooter(o,i);const e=this._size=Aa(this,i),a=Object.assign({},t,e),r=La(this.chart,i,a),l=Ea(i,a,r,this.chart);this.xAlign=r.xAlign,this.yAlign=r.yAlign,n={opacity:1,x:l.x,y:l.y,width:e.width,height:e.height,caretX:t.x,caretY:t.y}}else 0!==this.opacity&&(n={opacity:0});this._tooltipItems=o,this.$context=void 0,n&&this._resolveAnimations().update(this,n),t&&i.external&&i.external.call(this,{chart:this.chart,tooltip:this,replay:e})}drawCaret(t,e,i,s){const n=this.getCaretPosition(t,i,s);e.lineTo(n.x1,n.y1),e.lineTo(n.x2,n.y2),e.lineTo(n.x3,n.y3)}getCaretPosition(t,e,i){const{xAlign:s,yAlign:n}=this,{caretSize:o,cornerRadius:a}=i,{topLeft:r,topRight:l,bottomLeft:h,bottomRight:c}=wi(a),{x:d,y:u}=t,{width:f,height:g}=e;let p,m,x,b,_,y;return"center"===n?(_=u+g/2,"left"===s?(p=d,m=p-o,b=_+o,y=_-o):(p=d+f,m=p+o,b=_-o,y=_+o),x=p):(m="left"===s?d+Math.max(r,h)+o:"right"===s?d+f-Math.max(l,c)-o:this.caretX,"top"===n?(b=u,_=b-o,p=m-o,x=m+o):(b=u+g,_=b+o,p=m+o,x=m-o),y=b),{x1:p,x2:m,x3:x,y1:b,y2:_,y3:y}}drawTitle(t,e,i){const s=this.title,n=s.length;let o,a,r;if(n){const l=Oi(i.rtl,this.x,this.width);for(t.x=Ra(this,i.titleAlign,i),e.textAlign=l.textAlign(i.titleAlign),e.textBaseline="middle",o=Si(i.titleFont),a=i.titleSpacing,e.fillStyle=i.titleColor,e.font=o.string,r=0;r0!==t))?(t.beginPath(),t.fillStyle=n.multiKeyBackground,He(t,{x:e,y:g,w:h,h:l,radius:r}),t.fill(),t.stroke(),t.fillStyle=a.backgroundColor,t.beginPath(),He(t,{x:i,y:g+1,w:h-2,h:l-2,radius:r}),t.fill()):(t.fillStyle=n.multiKeyBackground,t.fillRect(e,g,h,l),t.strokeRect(e,g,h,l),t.fillStyle=a.backgroundColor,t.fillRect(i,g+1,h-2,l-2))}t.fillStyle=this.labelTextColors[i]}drawBody(t,e,i){const{body:s}=this,{bodySpacing:n,bodyAlign:o,displayColors:a,boxHeight:r,boxWidth:l,boxPadding:h}=i,c=Si(i.bodyFont);let d=c.lineHeight,f=0;const g=Oi(i.rtl,this.x,this.width),p=function(i){e.fillText(i,g.x(t.x+f),t.y+d/2),t.y+=d+n},m=g.textAlign(o);let x,b,_,y,v,M,w;for(e.textAlign=o,e.textBaseline="middle",e.font=c.string,t.x=Ra(this,m,i),e.fillStyle=i.bodyColor,u(this.beforeBody,p),f=a&&"right"!==m?"center"===o?l/2+h:l+2+h:0,y=0,M=s.length;y0&&e.stroke()}_updateAnimationTarget(t){const e=this.chart,i=this.$animations,s=i&&i.x,n=i&&i.y;if(s||n){const i=Pa[t.position].call(this,this._active,this._eventPosition);if(!i)return;const o=this._size=Aa(this,t),a=Object.assign({},i,this._size),r=La(e,t,a),l=Ea(t,a,r,e);s._to===l.x&&n._to===l.y||(this.xAlign=r.xAlign,this.yAlign=r.yAlign,this.width=o.width,this.height=o.height,this.caretX=i.x,this.caretY=i.y,this._resolveAnimations().update(this,l))}}_willRender(){return!!this.opacity}draw(t){const e=this.options.setContext(this.getContext());let i=this.opacity;if(!i)return;this._updateAnimationTarget(e);const s={width:this.width,height:this.height},n={x:this.x,y:this.y};i=Math.abs(i)<.001?0:i;const o=ki(e.padding),a=this.title.length||this.beforeBody.length||this.body.length||this.afterBody.length||this.footer.length;e.enabled&&a&&(t.save(),t.globalAlpha=i,this.drawBackground(n,t,s,e),Ai(t,e.textDirection),n.y+=o.top,this.drawTitle(n,t,e),this.drawBody(n,t,e),this.drawFooter(n,t,e),Ti(t,e.textDirection),t.restore())}getActiveElements(){return this._active||[]}setActiveElements(t,e){const i=this._active,s=t.map((({datasetIndex:t,index:e})=>{const i=this.chart.getDatasetMeta(t);if(!i)throw new Error("Cannot find a dataset at index "+t);return{datasetIndex:t,element:i.data[e],index:e}})),n=!f(i,s),o=this._positionChanged(s,e);(n||o)&&(this._active=s,this._eventPosition=e,this._ignoreReplayEvents=!0,this.update(!0))}handleEvent(t,e,i=!0){if(e&&this._ignoreReplayEvents)return!1;this._ignoreReplayEvents=!1;const s=this.options,n=this._active||[],o=this._getActiveElements(t,n,e,i),a=this._positionChanged(o,t),r=e||!f(o,n)||a;return r&&(this._active=o,(s.enabled||s.external)&&(this._eventPosition={x:t.x,y:t.y},this.update(!0,e))),r}_getActiveElements(t,e,i,s){const n=this.options;if("mouseout"===t.type)return[];if(!s)return e.filter((t=>this.chart.data.datasets[t.datasetIndex]&&void 0!==this.chart.getDatasetMeta(t.datasetIndex).controller.getParsed(t.index)));const o=this.chart.getElementsAtEventForMode(t,n.mode,n,i);return n.reverse&&o.reverse(),o}_positionChanged(t,e){const{caretX:i,caretY:s,options:n}=this,o=Pa[n.position].call(this,t,e);return!1!==o&&(i!==o.x||s!==o.y)}}var Wa={id:"tooltip",_element:Ba,positioners:Pa,afterInit(t,e,i){i&&(t.tooltip=new Ba({chart:t,options:i}))},beforeUpdate(t,e,i){t.tooltip&&t.tooltip.initialize(i)},reset(t,e,i){t.tooltip&&t.tooltip.initialize(i)},afterDraw(t){const e=t.tooltip;if(e&&e._willRender()){const i={tooltip:e};if(!1===t.notifyPlugins("beforeTooltipDraw",{...i,cancelable:!0}))return;e.draw(t.ctx),t.notifyPlugins("afterTooltipDraw",i)}},afterEvent(t,e){if(t.tooltip){const i=e.replay;t.tooltip.handleEvent(e.event,i,e.inChartArea)&&(e.changed=!0)}},defaults:{enabled:!0,external:null,position:"average",backgroundColor:"rgba(0,0,0,0.8)",titleColor:"#fff",titleFont:{weight:"bold"},titleSpacing:2,titleMarginBottom:6,titleAlign:"left",bodyColor:"#fff",bodySpacing:2,bodyFont:{},bodyAlign:"left",footerColor:"#fff",footerSpacing:2,footerMarginTop:6,footerFont:{weight:"bold"},footerAlign:"left",padding:6,caretPadding:2,caretSize:5,cornerRadius:6,boxHeight:(t,e)=>e.bodyFont.size,boxWidth:(t,e)=>e.bodyFont.size,multiKeyBackground:"#fff",displayColors:!0,boxPadding:0,borderColor:"rgba(0,0,0,0)",borderWidth:0,animation:{duration:400,easing:"easeOutQuart"},animations:{numbers:{type:"number",properties:["x","y","width","height","caretX","caretY"]},opacity:{easing:"linear",duration:200}},callbacks:Fa},defaultRoutes:{bodyFont:"font",footerFont:"font",titleFont:"font"},descriptors:{_scriptable:t=>"filter"!==t&&"itemSort"!==t&&"external"!==t,_indexable:!1,callbacks:{_scriptable:!1,_indexable:!1},animation:{_fallback:!1},animations:{_fallback:"animation"}},additionalOptionScopes:["interaction"]};return Tn.register(Un,$o,go,t),Tn.helpers={...Hi},Tn._adapters=In,Tn.Animation=As,Tn.Animations=Ts,Tn.animator=bt,Tn.controllers=nn.controllers.items,Tn.DatasetController=js,Tn.Element=$s,Tn.elements=go,Tn.Interaction=Ki,Tn.layouts=ls,Tn.platforms=Ds,Tn.Scale=tn,Tn.Ticks=ae,Object.assign(Tn,Un,$o,go,t,Ds),Tn.WPMailSMTPChart=Tn,"undefined"!=typeof window&&(window.WPMailSMTPChart=Tn),Tn})); diff --git a/wp-content/plugins/wp-mail-smtp/assets/js/vendor/chartjs-adapter-moment.min.js b/wp-content/plugins/wp-mail-smtp/assets/js/vendor/chartjs-adapter-moment.min.js new file mode 100755 index 00000000..1454812e --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/js/vendor/chartjs-adapter-moment.min.js @@ -0,0 +1,10 @@ +/*! + * chartjs-adapter-moment v1.0.1 + * https://www.chartjs.org + * (c) 2022 chartjs-adapter-moment Contributors + * Released under the MIT license + * + * NOTE: This file was modified. Chart object was renamed to WPMailSMTPChart, to prevent JS library conflicts with other plugins. + * "Chart" was replaced with "WPMailSMTPChart" 1 time in this file. + */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("moment"),require("chart.js")):"function"==typeof define&&define.amd?define(["moment","chart.js"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).moment,e.WPMailSMTPChart)}(this,(function(e,t){"use strict";function n(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var f=n(e);const a={datetime:"MMM D, YYYY, h:mm:ss a",millisecond:"h:mm:ss.SSS a",second:"h:mm:ss a",minute:"h:mm a",hour:"hA",day:"MMM D",week:"ll",month:"MMM YYYY",quarter:"[Q]Q - YYYY",year:"YYYY"};t._adapters._date.override("function"==typeof f.default?{_id:"moment",formats:function(){return a},parse:function(e,t){return"string"==typeof e&&"string"==typeof t?e=f.default(e,t):e instanceof f.default||(e=f.default(e)),e.isValid()?e.valueOf():null},format:function(e,t){return f.default(e).format(t)},add:function(e,t,n){return f.default(e).add(t,n).valueOf()},diff:function(e,t,n){return f.default(e).diff(f.default(t),n)},startOf:function(e,t,n){return e=f.default(e),"isoWeek"===t?(n=Math.trunc(Math.min(Math.max(0,n),6)),e.isoWeekday(n).startOf("day").valueOf()):e.startOf(t).valueOf()},endOf:function(e,t){return f.default(e).endOf(t).valueOf()}}:{})})); \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/js/vendor/flatpickr.min.js b/wp-content/plugins/wp-mail-smtp/assets/js/vendor/flatpickr.min.js new file mode 100755 index 00000000..357a860a --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/js/vendor/flatpickr.min.js @@ -0,0 +1,2 @@ +/* flatpickr v4.6.9,, @license MIT */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).flatpickr=t()}(this,(function(){"use strict";var e=function(){return(e=Object.assign||function(e){for(var t,n=1,a=arguments.length;n",noCalendar:!1,now:new Date,onChange:[],onClose:[],onDayCreate:[],onDestroy:[],onKeyDown:[],onMonthChange:[],onOpen:[],onParseConfig:[],onReady:[],onValueUpdate:[],onYearChange:[],onPreCalendarPosition:[],plugins:[],position:"auto",positionElement:void 0,prevArrow:"",shorthandCurrentMonth:!1,showMonths:1,static:!1,time_24hr:!1,weekNumbers:!1,wrap:!1},i={weekdays:{shorthand:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],longhand:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]},months:{shorthand:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],longhand:["January","February","March","April","May","June","July","August","September","October","November","December"]},daysInMonth:[31,28,31,30,31,30,31,31,30,31,30,31],firstDayOfWeek:0,ordinal:function(e){var t=e%100;if(t>3&&t<21)return"th";switch(t%10){case 1:return"st";case 2:return"nd";case 3:return"rd";default:return"th"}},rangeSeparator:" to ",weekAbbreviation:"Wk",scrollTitle:"Scroll to increment",toggleTitle:"Click to toggle",amPM:["AM","PM"],yearAriaLabel:"Year",monthAriaLabel:"Month",hourAriaLabel:"Hour",minuteAriaLabel:"Minute",time_24hr:!1},o=function(e,t){return void 0===t&&(t=2),("000"+e).slice(-1*t)},r=function(e){return!0===e?1:0};function l(e,t){var n;return function(){var a=this;clearTimeout(n),n=setTimeout((function(){return e.apply(a,arguments)}),t)}}var c=function(e){return e instanceof Array?e:[e]};function d(e,t,n){if(!0===n)return e.classList.add(t);e.classList.remove(t)}function s(e,t,n){var a=window.document.createElement(e);return t=t||"",n=n||"",a.className=t,void 0!==n&&(a.textContent=n),a}function u(e){for(;e.firstChild;)e.removeChild(e.firstChild)}function f(e,t){return t(e)?e:e.parentNode?f(e.parentNode,t):void 0}function m(e,t){var n=s("div","numInputWrapper"),a=s("input","numInput "+e),i=s("span","arrowUp"),o=s("span","arrowDown");if(-1===navigator.userAgent.indexOf("MSIE 9.0")?a.type="number":(a.type="text",a.pattern="\\d*"),void 0!==t)for(var r in t)a.setAttribute(r,t[r]);return n.appendChild(a),n.appendChild(i),n.appendChild(o),n}function g(e){try{return"function"==typeof e.composedPath?e.composedPath()[0]:e.target}catch(t){return e.target}}var p=function(){},h=function(e,t,n){return n.months[t?"shorthand":"longhand"][e]},v={D:p,F:function(e,t,n){e.setMonth(n.months.longhand.indexOf(t))},G:function(e,t){e.setHours(parseFloat(t))},H:function(e,t){e.setHours(parseFloat(t))},J:function(e,t){e.setDate(parseFloat(t))},K:function(e,t,n){e.setHours(e.getHours()%12+12*r(new RegExp(n.amPM[1],"i").test(t)))},M:function(e,t,n){e.setMonth(n.months.shorthand.indexOf(t))},S:function(e,t){e.setSeconds(parseFloat(t))},U:function(e,t){return new Date(1e3*parseFloat(t))},W:function(e,t,n){var a=parseInt(t),i=new Date(e.getFullYear(),0,2+7*(a-1),0,0,0,0);return i.setDate(i.getDate()-i.getDay()+n.firstDayOfWeek),i},Y:function(e,t){e.setFullYear(parseFloat(t))},Z:function(e,t){return new Date(t)},d:function(e,t){e.setDate(parseFloat(t))},h:function(e,t){e.setHours(parseFloat(t))},i:function(e,t){e.setMinutes(parseFloat(t))},j:function(e,t){e.setDate(parseFloat(t))},l:p,m:function(e,t){e.setMonth(parseFloat(t)-1)},n:function(e,t){e.setMonth(parseFloat(t)-1)},s:function(e,t){e.setSeconds(parseFloat(t))},u:function(e,t){return new Date(parseFloat(t))},w:p,y:function(e,t){e.setFullYear(2e3+parseFloat(t))}},D={D:"(\\w+)",F:"(\\w+)",G:"(\\d\\d|\\d)",H:"(\\d\\d|\\d)",J:"(\\d\\d|\\d)\\w+",K:"",M:"(\\w+)",S:"(\\d\\d|\\d)",U:"(.+)",W:"(\\d\\d|\\d)",Y:"(\\d{4})",Z:"(.+)",d:"(\\d\\d|\\d)",h:"(\\d\\d|\\d)",i:"(\\d\\d|\\d)",j:"(\\d\\d|\\d)",l:"(\\w+)",m:"(\\d\\d|\\d)",n:"(\\d\\d|\\d)",s:"(\\d\\d|\\d)",u:"(.+)",w:"(\\d\\d|\\d)",y:"(\\d{2})"},w={Z:function(e){return e.toISOString()},D:function(e,t,n){return t.weekdays.shorthand[w.w(e,t,n)]},F:function(e,t,n){return h(w.n(e,t,n)-1,!1,t)},G:function(e,t,n){return o(w.h(e,t,n))},H:function(e){return o(e.getHours())},J:function(e,t){return void 0!==t.ordinal?e.getDate()+t.ordinal(e.getDate()):e.getDate()},K:function(e,t){return t.amPM[r(e.getHours()>11)]},M:function(e,t){return h(e.getMonth(),!0,t)},S:function(e){return o(e.getSeconds())},U:function(e){return e.getTime()/1e3},W:function(e,t,n){return n.getWeek(e)},Y:function(e){return o(e.getFullYear(),4)},d:function(e){return o(e.getDate())},h:function(e){return e.getHours()%12?e.getHours()%12:12},i:function(e){return o(e.getMinutes())},j:function(e){return e.getDate()},l:function(e,t){return t.weekdays.longhand[e.getDay()]},m:function(e){return o(e.getMonth()+1)},n:function(e){return e.getMonth()+1},s:function(e){return e.getSeconds()},u:function(e){return e.getTime()},w:function(e){return e.getDay()},y:function(e){return String(e.getFullYear()).substring(2)}},b=function(e){var t=e.config,n=void 0===t?a:t,o=e.l10n,r=void 0===o?i:o,l=e.isMobile,c=void 0!==l&&l;return function(e,t,a){var i=a||r;return void 0===n.formatDate||c?t.split("").map((function(t,a,o){return w[t]&&"\\"!==o[a-1]?w[t](e,i,n):"\\"!==t?t:""})).join(""):n.formatDate(e,t,i)}},C=function(e){var t=e.config,n=void 0===t?a:t,o=e.l10n,r=void 0===o?i:o;return function(e,t,i,o){if(0===e||e){var l,c=o||r,d=e;if(e instanceof Date)l=new Date(e.getTime());else if("string"!=typeof e&&void 0!==e.toFixed)l=new Date(e);else if("string"==typeof e){var s=t||(n||a).dateFormat,u=String(e).trim();if("today"===u)l=new Date,i=!0;else if(/Z$/.test(u)||/GMT$/.test(u))l=new Date(e);else if(n&&n.parseDate)l=n.parseDate(e,s);else{l=n&&n.noCalendar?new Date((new Date).setHours(0,0,0,0)):new Date((new Date).getFullYear(),0,1,0,0,0,0);for(var f=void 0,m=[],g=0,p=0,h="";g=0?new Date:new Date(w.config.minDate.getTime()),n=x(w.config);t.setHours(n.hours,n.minutes,n.seconds,t.getMilliseconds()),w.selectedDates=[t],w.latestSelectedDateObj=t}void 0!==e&&"blur"!==e.type&&function(e){e.preventDefault();var t="keydown"===e.type,n=g(e),a=n;void 0!==w.amPM&&n===w.amPM&&(w.amPM.textContent=w.l10n.amPM[r(w.amPM.textContent===w.l10n.amPM[0])]);var i=parseFloat(a.getAttribute("min")),l=parseFloat(a.getAttribute("max")),c=parseFloat(a.getAttribute("step")),d=parseInt(a.value,10),s=e.delta||(t?38===e.which?1:-1:0),u=d+c*s;if(void 0!==a.value&&2===a.value.length){var f=a===w.hourElement,m=a===w.minuteElement;ul&&(u=a===w.hourElement?u-l-r(!w.amPM):i,m&&j(void 0,1,w.hourElement)),w.amPM&&f&&(1===c?u+d===23:Math.abs(u-d)>c)&&(w.amPM.textContent=w.l10n.amPM[r(w.amPM.textContent===w.l10n.amPM[0])]),a.value=o(u)}}(e);var a=w._input.value;S(),be(),w._input.value!==a&&w._debouncedChange()}function S(){if(void 0!==w.hourElement&&void 0!==w.minuteElement){var e,t,n=(parseInt(w.hourElement.value.slice(-2),10)||0)%24,a=(parseInt(w.minuteElement.value,10)||0)%60,i=void 0!==w.secondElement?(parseInt(w.secondElement.value,10)||0)%60:0;void 0!==w.amPM&&(e=n,t=w.amPM.textContent,n=e%12+12*r(t===w.l10n.amPM[1]));var o=void 0!==w.config.minTime||w.config.minDate&&w.minDateHasTime&&w.latestSelectedDateObj&&0===M(w.latestSelectedDateObj,w.config.minDate,!0);if(void 0!==w.config.maxTime||w.config.maxDate&&w.maxDateHasTime&&w.latestSelectedDateObj&&0===M(w.latestSelectedDateObj,w.config.maxDate,!0)){var l=void 0!==w.config.maxTime?w.config.maxTime:w.config.maxDate;(n=Math.min(n,l.getHours()))===l.getHours()&&(a=Math.min(a,l.getMinutes())),a===l.getMinutes()&&(i=Math.min(i,l.getSeconds()))}if(o){var c=void 0!==w.config.minTime?w.config.minTime:w.config.minDate;(n=Math.max(n,c.getHours()))===c.getHours()&&a=12)]),void 0!==w.secondElement&&(w.secondElement.value=o(n)))}function F(e){var t=g(e),n=parseInt(t.value)+(e.delta||0);(n/1e3>1||"Enter"===e.key&&!/[^\d]/.test(n.toString()))&&Q(n)}function A(e,t,n,a){return t instanceof Array?t.forEach((function(t){return A(e,t,n,a)})):e instanceof Array?e.forEach((function(e){return A(e,t,n,a)})):(e.addEventListener(t,n,a),void w._handlers.push({remove:function(){return e.removeEventListener(t,n)}}))}function N(){pe("onChange")}function P(e,t){var n=void 0!==e?w.parseDate(e):w.latestSelectedDateObj||(w.config.minDate&&w.config.minDate>w.now?w.config.minDate:w.config.maxDate&&w.config.maxDate=0&&M(e,w.selectedDates[1])<=0)}(t)&&!ve(t)&&o.classList.add("inRange"),w.weekNumbers&&1===w.config.showMonths&&"prevMonthDay"!==e&&n%7==1&&w.weekNumbers.insertAdjacentHTML("beforeend",""+w.config.getWeek(t)+""),pe("onDayCreate",o),o}function L(e){e.focus(),"range"===w.config.mode&&ae(e)}function W(e){for(var t=e>0?0:w.config.showMonths-1,n=e>0?w.config.showMonths:-1,a=t;a!=n;a+=e)for(var i=w.daysContainer.children[a],o=e>0?0:i.children.length-1,r=e>0?i.children.length:-1,l=o;l!=r;l+=e){var c=i.children[l];if(-1===c.className.indexOf("hidden")&&X(c.dateObj))return c}}function R(e,t){var n=ee(document.activeElement||document.body),a=void 0!==e?e:n?document.activeElement:void 0!==w.selectedDateElem&&ee(w.selectedDateElem)?w.selectedDateElem:void 0!==w.todayDateElem&&ee(w.todayDateElem)?w.todayDateElem:W(t>0?1:-1);void 0===a?w._input.focus():n?function(e,t){for(var n=-1===e.className.indexOf("Month")?e.dateObj.getMonth():w.currentMonth,a=t>0?w.config.showMonths:-1,i=t>0?1:-1,o=n-w.currentMonth;o!=a;o+=i)for(var r=w.daysContainer.children[o],l=n-w.currentMonth===o?e.$i+t:t<0?r.children.length-1:0,c=r.children.length,d=l;d>=0&&d0?c:-1);d+=i){var s=r.children[d];if(-1===s.className.indexOf("hidden")&&X(s.dateObj)&&Math.abs(e.$i-d)>=Math.abs(t))return L(s)}w.changeMonth(i),R(W(i),0)}(a,t):L(a)}function B(e,t){for(var n=(new Date(e,t,1).getDay()-w.l10n.firstDayOfWeek+7)%7,a=w.utils.getDaysInMonth((t-1+12)%12,e),i=w.utils.getDaysInMonth(t,e),o=window.document.createDocumentFragment(),r=w.config.showMonths>1,l=r?"prevMonthDay hidden":"prevMonthDay",c=r?"nextMonthDay hidden":"nextMonthDay",d=a+1-n,u=0;d<=a;d++,u++)o.appendChild(H(l,new Date(e,t-1,d),d,u));for(d=1;d<=i;d++,u++)o.appendChild(H("",new Date(e,t,d),d,u));for(var f=i+1;f<=42-n&&(1===w.config.showMonths||u%7!=0);f++,u++)o.appendChild(H(c,new Date(e,t+1,f%i),f,u));var m=s("div","dayContainer");return m.appendChild(o),m}function J(){if(void 0!==w.daysContainer){u(w.daysContainer),w.weekNumbers&&u(w.weekNumbers);for(var e=document.createDocumentFragment(),t=0;t1||"dropdown"!==w.config.monthSelectorType)){var e=function(e){return!(void 0!==w.config.minDate&&w.currentYear===w.config.minDate.getFullYear()&&ew.config.maxDate.getMonth())};w.monthsDropdownContainer.tabIndex=-1,w.monthsDropdownContainer.innerHTML="";for(var t=0;t<12;t++)if(e(t)){var n=s("option","flatpickr-monthDropdown-month");n.value=new Date(w.currentYear,t).getMonth().toString(),n.textContent=h(t,w.config.shorthandCurrentMonth,w.l10n),n.tabIndex=-1,w.currentMonth===t&&(n.selected=!0),w.monthsDropdownContainer.appendChild(n)}}}function U(){var e,t=s("div","flatpickr-month"),n=window.document.createDocumentFragment();w.config.showMonths>1||"static"===w.config.monthSelectorType?e=s("span","cur-month"):(w.monthsDropdownContainer=s("select","flatpickr-monthDropdown-months"),w.monthsDropdownContainer.setAttribute("aria-label",w.l10n.monthAriaLabel),A(w.monthsDropdownContainer,"change",(function(e){var t=g(e),n=parseInt(t.value,10);w.changeMonth(n-w.currentMonth),pe("onMonthChange")})),K(),e=w.monthsDropdownContainer);var a=m("cur-year",{tabindex:"-1"}),i=a.getElementsByTagName("input")[0];i.setAttribute("aria-label",w.l10n.yearAriaLabel),w.config.minDate&&i.setAttribute("min",w.config.minDate.getFullYear().toString()),w.config.maxDate&&(i.setAttribute("max",w.config.maxDate.getFullYear().toString()),i.disabled=!!w.config.minDate&&w.config.minDate.getFullYear()===w.config.maxDate.getFullYear());var o=s("div","flatpickr-current-month");return o.appendChild(e),o.appendChild(a),n.appendChild(o),t.appendChild(n),{container:t,yearElement:i,monthElement:e}}function q(){u(w.monthNav),w.monthNav.appendChild(w.prevMonthNav),w.config.showMonths&&(w.yearElements=[],w.monthElements=[]);for(var e=w.config.showMonths;e--;){var t=U();w.yearElements.push(t.yearElement),w.monthElements.push(t.monthElement),w.monthNav.appendChild(t.container)}w.monthNav.appendChild(w.nextMonthNav)}function $(){w.weekdayContainer?u(w.weekdayContainer):w.weekdayContainer=s("div","flatpickr-weekdays");for(var e=w.config.showMonths;e--;){var t=s("div","flatpickr-weekdaycontainer");w.weekdayContainer.appendChild(t)}return z(),w.weekdayContainer}function z(){if(w.weekdayContainer){var e=w.l10n.firstDayOfWeek,n=t(w.l10n.weekdays.shorthand);e>0&&e\n "+n.join("")+"\n \n "}}function G(e,t){void 0===t&&(t=!0);var n=t?e:e-w.currentMonth;n<0&&!0===w._hidePrevMonthArrow||n>0&&!0===w._hideNextMonthArrow||(w.currentMonth+=n,(w.currentMonth<0||w.currentMonth>11)&&(w.currentYear+=w.currentMonth>11?1:-1,w.currentMonth=(w.currentMonth+12)%12,pe("onYearChange"),K()),J(),pe("onMonthChange"),De())}function V(e){return!(!w.config.appendTo||!w.config.appendTo.contains(e))||w.calendarContainer.contains(e)}function Z(e){if(w.isOpen&&!w.config.inline){var t=g(e),n=V(t),a=t===w.input||t===w.altInput||w.element.contains(t)||e.path&&e.path.indexOf&&(~e.path.indexOf(w.input)||~e.path.indexOf(w.altInput)),i="blur"===e.type?a&&e.relatedTarget&&!V(e.relatedTarget):!a&&!n&&!V(e.relatedTarget),o=!w.config.ignoredFocusElements.some((function(e){return e.contains(t)}));i&&o&&(void 0!==w.timeContainer&&void 0!==w.minuteElement&&void 0!==w.hourElement&&""!==w.input.value&&void 0!==w.input.value&&I(),w.close(),w.config&&"range"===w.config.mode&&1===w.selectedDates.length&&(w.clear(!1),w.redraw()))}}function Q(e){if(!(!e||w.config.minDate&&ew.config.maxDate.getFullYear())){var t=e,n=w.currentYear!==t;w.currentYear=t||w.currentYear,w.config.maxDate&&w.currentYear===w.config.maxDate.getFullYear()?w.currentMonth=Math.min(w.config.maxDate.getMonth(),w.currentMonth):w.config.minDate&&w.currentYear===w.config.minDate.getFullYear()&&(w.currentMonth=Math.max(w.config.minDate.getMonth(),w.currentMonth)),n&&(w.redraw(),pe("onYearChange"),K())}}function X(e,t){var n;void 0===t&&(t=!0);var a=w.parseDate(e,void 0,t);if(w.config.minDate&&a&&M(a,w.config.minDate,void 0!==t?t:!w.minDateHasTime)<0||w.config.maxDate&&a&&M(a,w.config.maxDate,void 0!==t?t:!w.maxDateHasTime)>0)return!1;if(!w.config.enable&&0===w.config.disable.length)return!0;if(void 0===a)return!1;for(var i=!!w.config.enable,o=null!==(n=w.config.enable)&&void 0!==n?n:w.config.disable,r=0,l=void 0;r=l.from.getTime()&&a.getTime()<=l.to.getTime())return i}return!i}function ee(e){return void 0!==w.daysContainer&&(-1===e.className.indexOf("hidden")&&-1===e.className.indexOf("flatpickr-disabled")&&w.daysContainer.contains(e))}function te(e){!(e.target===w._input)||!(w.selectedDates.length>0||w._input.value.length>0)||e.relatedTarget&&V(e.relatedTarget)||w.setDate(w._input.value,!0,e.target===w.altInput?w.config.altFormat:w.config.dateFormat)}function ne(e){var t=g(e),n=w.config.wrap?p.contains(t):t===w._input,a=w.config.allowInput,i=w.isOpen&&(!a||!n),o=w.config.inline&&n&&!a;if(13===e.keyCode&&n){if(a)return w.setDate(w._input.value,!0,t===w.altInput?w.config.altFormat:w.config.dateFormat),t.blur();w.open()}else if(V(t)||i||o){var r=!!w.timeContainer&&w.timeContainer.contains(t);switch(e.keyCode){case 13:r?(e.preventDefault(),I(),se()):ue(e);break;case 27:e.preventDefault(),se();break;case 8:case 46:n&&!w.config.allowInput&&(e.preventDefault(),w.clear());break;case 37:case 39:if(r||n)w.hourElement&&w.hourElement.focus();else if(e.preventDefault(),void 0!==w.daysContainer&&(!1===a||document.activeElement&&ee(document.activeElement))){var l=39===e.keyCode?1:-1;e.ctrlKey?(e.stopPropagation(),G(l),R(W(1),0)):R(void 0,l)}break;case 38:case 40:e.preventDefault();var c=40===e.keyCode?1:-1;w.daysContainer&&void 0!==t.$i||t===w.input||t===w.altInput?e.ctrlKey?(e.stopPropagation(),Q(w.currentYear-c),R(W(1),0)):r||R(void 0,7*c):t===w.currentYearElement?Q(w.currentYear-c):w.config.enableTime&&(!r&&w.hourElement&&w.hourElement.focus(),I(e),w._debouncedChange());break;case 9:if(r){var d=[w.hourElement,w.minuteElement,w.secondElement,w.amPM].concat(w.pluginElements).filter((function(e){return e})),s=d.indexOf(t);if(-1!==s){var u=d[s+(e.shiftKey?-1:1)];e.preventDefault(),(u||w._input).focus()}}else!w.config.noCalendar&&w.daysContainer&&w.daysContainer.contains(t)&&e.shiftKey&&(e.preventDefault(),w._input.focus())}}if(void 0!==w.amPM&&t===w.amPM)switch(e.key){case w.l10n.amPM[0].charAt(0):case w.l10n.amPM[0].charAt(0).toLowerCase():w.amPM.textContent=w.l10n.amPM[0],S(),be();break;case w.l10n.amPM[1].charAt(0):case w.l10n.amPM[1].charAt(0).toLowerCase():w.amPM.textContent=w.l10n.amPM[1],S(),be()}(n||V(t))&&pe("onKeyDown",e)}function ae(e){if(1===w.selectedDates.length&&(!e||e.classList.contains("flatpickr-day")&&!e.classList.contains("flatpickr-disabled"))){for(var t=e?e.dateObj.getTime():w.days.firstElementChild.dateObj.getTime(),n=w.parseDate(w.selectedDates[0],void 0,!0).getTime(),a=Math.min(t,w.selectedDates[0].getTime()),i=Math.max(t,w.selectedDates[0].getTime()),o=!1,r=0,l=0,c=a;ca&&cr)?r=c:c>n&&(!l||c0&&m0&&m>l;return g?(f.classList.add("notAllowed"),["inRange","startRange","endRange"].forEach((function(e){f.classList.remove(e)})),"continue"):o&&!g?"continue":(["startRange","inRange","endRange","notAllowed"].forEach((function(e){f.classList.remove(e)})),void(void 0!==e&&(e.classList.add(t<=w.selectedDates[0].getTime()?"startRange":"endRange"),nt&&m===n&&f.classList.add("endRange"),m>=r&&(0===l||m<=l)&&(d=n,u=t,(c=m)>Math.min(d,u)&&c0||n.getMinutes()>0||n.getSeconds()>0),w.selectedDates&&(w.selectedDates=w.selectedDates.filter((function(e){return X(e)})),w.selectedDates.length||"min"!==e||_(n),be()),w.daysContainer&&(de(),void 0!==n?w.currentYearElement[e]=n.getFullYear().toString():w.currentYearElement.removeAttribute(e),w.currentYearElement.disabled=!!a&&void 0!==n&&a.getFullYear()===n.getFullYear())}}function re(){return w.config.wrap?p.querySelector("[data-input]"):p}function le(){"object"!=typeof w.config.locale&&void 0===T.l10ns[w.config.locale]&&w.config.errorHandler(new Error("flatpickr: invalid locale "+w.config.locale)),w.l10n=e(e({},T.l10ns.default),"object"==typeof w.config.locale?w.config.locale:"default"!==w.config.locale?T.l10ns[w.config.locale]:void 0),D.K="("+w.l10n.amPM[0]+"|"+w.l10n.amPM[1]+"|"+w.l10n.amPM[0].toLowerCase()+"|"+w.l10n.amPM[1].toLowerCase()+")",void 0===e(e({},v),JSON.parse(JSON.stringify(p.dataset||{}))).time_24hr&&void 0===T.defaultConfig.time_24hr&&(w.config.time_24hr=w.l10n.time_24hr),w.formatDate=b(w),w.parseDate=C({config:w.config,l10n:w.l10n})}function ce(e){if("function"!=typeof w.config.position){if(void 0!==w.calendarContainer){pe("onPreCalendarPosition");var t=e||w._positionElement,n=Array.prototype.reduce.call(w.calendarContainer.children,(function(e,t){return e+t.offsetHeight}),0),a=w.calendarContainer.offsetWidth,i=w.config.position.split(" "),o=i[0],r=i.length>1?i[1]:null,l=t.getBoundingClientRect(),c=window.innerHeight-l.bottom,s="above"===o||"below"!==o&&cn,u=window.pageYOffset+l.top+(s?-n-2:t.offsetHeight+2);if(d(w.calendarContainer,"arrowTop",!s),d(w.calendarContainer,"arrowBottom",s),!w.config.inline){var f=window.pageXOffset+l.left,m=!1,g=!1;"center"===r?(f-=(a-l.width)/2,m=!0):"right"===r&&(f-=a-l.width,g=!0),d(w.calendarContainer,"arrowLeft",!m&&!g),d(w.calendarContainer,"arrowCenter",m),d(w.calendarContainer,"arrowRight",g);var p=window.document.body.offsetWidth-(window.pageXOffset+l.right),h=f+a>window.document.body.offsetWidth,v=p+a>window.document.body.offsetWidth;if(d(w.calendarContainer,"rightMost",h),!w.config.static)if(w.calendarContainer.style.top=u+"px",h)if(v){var D=function(){for(var e=null,t=0;tw.currentMonth+w.config.showMonths-1)&&"range"!==w.config.mode;if(w.selectedDateElem=n,"single"===w.config.mode)w.selectedDates=[a];else if("multiple"===w.config.mode){var o=ve(a);o?w.selectedDates.splice(parseInt(o),1):w.selectedDates.push(a)}else"range"===w.config.mode&&(2===w.selectedDates.length&&w.clear(!1,!1),w.latestSelectedDateObj=a,w.selectedDates.push(a),0!==M(a,w.selectedDates[0],!0)&&w.selectedDates.sort((function(e,t){return e.getTime()-t.getTime()})));if(S(),i){var r=w.currentYear!==a.getFullYear();w.currentYear=a.getFullYear(),w.currentMonth=a.getMonth(),r&&(pe("onYearChange"),K()),pe("onMonthChange")}if(De(),J(),be(),i||"range"===w.config.mode||1!==w.config.showMonths?void 0!==w.selectedDateElem&&void 0===w.hourElement&&w.selectedDateElem&&w.selectedDateElem.focus():L(n),void 0!==w.hourElement&&void 0!==w.hourElement&&w.hourElement.focus(),w.config.closeOnSelect){var l="single"===w.config.mode&&!w.config.enableTime,c="range"===w.config.mode&&2===w.selectedDates.length&&!w.config.enableTime;(l||c)&&se()}N()}}w.parseDate=C({config:w.config,l10n:w.l10n}),w._handlers=[],w.pluginElements=[],w.loadedPlugins=[],w._bind=A,w._setHoursFromDate=_,w._positionCalendar=ce,w.changeMonth=G,w.changeYear=Q,w.clear=function(e,t){void 0===e&&(e=!0);void 0===t&&(t=!0);w.input.value="",void 0!==w.altInput&&(w.altInput.value="");void 0!==w.mobileInput&&(w.mobileInput.value="");w.selectedDates=[],w.latestSelectedDateObj=void 0,!0===t&&(w.currentYear=w._initialDate.getFullYear(),w.currentMonth=w._initialDate.getMonth());if(!0===w.config.enableTime){var n=x(w.config),a=n.hours,i=n.minutes,o=n.seconds;O(a,i,o)}w.redraw(),e&&pe("onChange")},w.close=function(){w.isOpen=!1,w.isMobile||(void 0!==w.calendarContainer&&w.calendarContainer.classList.remove("open"),void 0!==w._input&&w._input.classList.remove("active"));pe("onClose")},w._createElement=s,w.destroy=function(){void 0!==w.config&&pe("onDestroy");for(var e=w._handlers.length;e--;)w._handlers[e].remove();if(w._handlers=[],w.mobileInput)w.mobileInput.parentNode&&w.mobileInput.parentNode.removeChild(w.mobileInput),w.mobileInput=void 0;else if(w.calendarContainer&&w.calendarContainer.parentNode)if(w.config.static&&w.calendarContainer.parentNode){var t=w.calendarContainer.parentNode;if(t.lastChild&&t.removeChild(t.lastChild),t.parentNode){for(;t.firstChild;)t.parentNode.insertBefore(t.firstChild,t);t.parentNode.removeChild(t)}}else w.calendarContainer.parentNode.removeChild(w.calendarContainer);w.altInput&&(w.input.type="text",w.altInput.parentNode&&w.altInput.parentNode.removeChild(w.altInput),delete w.altInput);w.input&&(w.input.type=w.input._type,w.input.classList.remove("flatpickr-input"),w.input.removeAttribute("readonly"));["_showTimeInput","latestSelectedDateObj","_hideNextMonthArrow","_hidePrevMonthArrow","__hideNextMonthArrow","__hidePrevMonthArrow","isMobile","isOpen","selectedDateElem","minDateHasTime","maxDateHasTime","days","daysContainer","_input","_positionElement","innerContainer","rContainer","monthNav","todayDateElem","calendarContainer","weekdayContainer","prevMonthNav","nextMonthNav","monthsDropdownContainer","currentMonthElement","currentYearElement","navigationCurrentMonth","selectedDateElem","config"].forEach((function(e){try{delete w[e]}catch(e){}}))},w.isEnabled=X,w.jumpToDate=P,w.open=function(e,t){void 0===t&&(t=w._positionElement);if(!0===w.isMobile){if(e){e.preventDefault();var n=g(e);n&&n.blur()}return void 0!==w.mobileInput&&(w.mobileInput.focus(),w.mobileInput.click()),void pe("onOpen")}if(w._input.disabled||w.config.inline)return;var a=w.isOpen;w.isOpen=!0,a||(w.calendarContainer.classList.add("open"),w._input.classList.add("active"),pe("onOpen"),ce(t));!0===w.config.enableTime&&!0===w.config.noCalendar&&(!1!==w.config.allowInput||void 0!==e&&w.timeContainer.contains(e.relatedTarget)||setTimeout((function(){return w.hourElement.select()}),50))},w.redraw=de,w.set=function(e,t){if(null!==e&&"object"==typeof e)for(var a in Object.assign(w.config,e),e)void 0!==fe[a]&&fe[a].forEach((function(e){return e()}));else w.config[e]=t,void 0!==fe[e]?fe[e].forEach((function(e){return e()})):n.indexOf(e)>-1&&(w.config[e]=c(t));w.redraw(),be(!0)},w.setDate=function(e,t,n){void 0===t&&(t=!1);void 0===n&&(n=w.config.dateFormat);if(0!==e&&!e||e instanceof Array&&0===e.length)return w.clear(t);me(e,n),w.latestSelectedDateObj=w.selectedDates[w.selectedDates.length-1],w.redraw(),P(void 0,t),_(),0===w.selectedDates.length&&w.clear(!1);be(t),t&&pe("onChange")},w.toggle=function(e){if(!0===w.isOpen)return w.close();w.open(e)};var fe={locale:[le,z],showMonths:[q,k,$],minDate:[P],maxDate:[P],clickOpens:[function(){!0===w.config.clickOpens?(A(w._input,"focus",w.open),A(w._input,"click",w.open)):(w._input.removeEventListener("focus",w.open),w._input.removeEventListener("click",w.open))}]};function me(e,t){var n=[];if(e instanceof Array)n=e.map((function(e){return w.parseDate(e,t)}));else if(e instanceof Date||"number"==typeof e)n=[w.parseDate(e,t)];else if("string"==typeof e)switch(w.config.mode){case"single":case"time":n=[w.parseDate(e,t)];break;case"multiple":n=e.split(w.config.conjunction).map((function(e){return w.parseDate(e,t)}));break;case"range":n=e.split(w.l10n.rangeSeparator).map((function(e){return w.parseDate(e,t)}))}else w.config.errorHandler(new Error("Invalid date supplied: "+JSON.stringify(e)));w.selectedDates=w.config.allowInvalidPreload?n:n.filter((function(e){return e instanceof Date&&X(e,!1)})),"range"===w.config.mode&&w.selectedDates.sort((function(e,t){return e.getTime()-t.getTime()}))}function ge(e){return e.slice().map((function(e){return"string"==typeof e||"number"==typeof e||e instanceof Date?w.parseDate(e,void 0,!0):e&&"object"==typeof e&&e.from&&e.to?{from:w.parseDate(e.from,void 0),to:w.parseDate(e.to,void 0)}:e})).filter((function(e){return e}))}function pe(e,t){if(void 0!==w.config){var n=w.config[e];if(void 0!==n&&n.length>0)for(var a=0;n[a]&&a1||"static"===w.config.monthSelectorType?w.monthElements[t].textContent=h(n.getMonth(),w.config.shorthandCurrentMonth,w.l10n)+" ":w.monthsDropdownContainer.value=n.getMonth().toString(),e.value=n.getFullYear().toString()})),w._hidePrevMonthArrow=void 0!==w.config.minDate&&(w.currentYear===w.config.minDate.getFullYear()?w.currentMonth<=w.config.minDate.getMonth():w.currentYearw.config.maxDate.getMonth():w.currentYear>w.config.maxDate.getFullYear()))}function we(e){return w.selectedDates.map((function(t){return w.formatDate(t,e)})).filter((function(e,t,n){return"range"!==w.config.mode||w.config.enableTime||n.indexOf(e)===t})).join("range"!==w.config.mode?w.config.conjunction:w.l10n.rangeSeparator)}function be(e){void 0===e&&(e=!0),void 0!==w.mobileInput&&w.mobileFormatStr&&(w.mobileInput.value=void 0!==w.latestSelectedDateObj?w.formatDate(w.latestSelectedDateObj,w.mobileFormatStr):""),w.input.value=we(w.config.dateFormat),void 0!==w.altInput&&(w.altInput.value=we(w.config.altFormat)),!1!==e&&pe("onValueUpdate")}function Ce(e){var t=g(e),n=w.prevMonthNav.contains(t),a=w.nextMonthNav.contains(t);n||a?G(n?-1:1):w.yearElements.indexOf(t)>=0?t.select():t.classList.contains("arrowUp")?w.changeYear(w.currentYear+1):t.classList.contains("arrowDown")&&w.changeYear(w.currentYear-1)}return function(){w.element=w.input=p,w.isOpen=!1,function(){var t=["wrap","weekNumbers","allowInput","allowInvalidPreload","clickOpens","time_24hr","enableTime","noCalendar","altInput","shorthandCurrentMonth","inline","static","enableSeconds","disableMobile"],i=e(e({},JSON.parse(JSON.stringify(p.dataset||{}))),v),o={};w.config.parseDate=i.parseDate,w.config.formatDate=i.formatDate,Object.defineProperty(w.config,"enable",{get:function(){return w.config._enable},set:function(e){w.config._enable=ge(e)}}),Object.defineProperty(w.config,"disable",{get:function(){return w.config._disable},set:function(e){w.config._disable=ge(e)}});var r="time"===i.mode;if(!i.dateFormat&&(i.enableTime||r)){var l=T.defaultConfig.dateFormat||a.dateFormat;o.dateFormat=i.noCalendar||r?"H:i"+(i.enableSeconds?":S":""):l+" H:i"+(i.enableSeconds?":S":"")}if(i.altInput&&(i.enableTime||r)&&!i.altFormat){var d=T.defaultConfig.altFormat||a.altFormat;o.altFormat=i.noCalendar||r?"h:i"+(i.enableSeconds?":S K":" K"):d+" h:i"+(i.enableSeconds?":S":"")+" K"}Object.defineProperty(w.config,"minDate",{get:function(){return w.config._minDate},set:oe("min")}),Object.defineProperty(w.config,"maxDate",{get:function(){return w.config._maxDate},set:oe("max")});var s=function(e){return function(t){w.config["min"===e?"_minTime":"_maxTime"]=w.parseDate(t,"H:i:S")}};Object.defineProperty(w.config,"minTime",{get:function(){return w.config._minTime},set:s("min")}),Object.defineProperty(w.config,"maxTime",{get:function(){return w.config._maxTime},set:s("max")}),"time"===i.mode&&(w.config.noCalendar=!0,w.config.enableTime=!0);Object.assign(w.config,o,i);for(var u=0;u-1?w.config[m]=c(f[m]).map(E).concat(w.config[m]):void 0===i[m]&&(w.config[m]=f[m])}i.altInputClass||(w.config.altInputClass=re().className+" "+w.config.altInputClass);pe("onParseConfig")}(),le(),function(){if(w.input=re(),!w.input)return void w.config.errorHandler(new Error("Invalid input element specified"));w.input._type=w.input.type,w.input.type="text",w.input.classList.add("flatpickr-input"),w._input=w.input,w.config.altInput&&(w.altInput=s(w.input.nodeName,w.config.altInputClass),w._input=w.altInput,w.altInput.placeholder=w.input.placeholder,w.altInput.disabled=w.input.disabled,w.altInput.required=w.input.required,w.altInput.tabIndex=w.input.tabIndex,w.altInput.type="text",w.input.setAttribute("type","hidden"),!w.config.static&&w.input.parentNode&&w.input.parentNode.insertBefore(w.altInput,w.input.nextSibling));w.config.allowInput||w._input.setAttribute("readonly","readonly");w._positionElement=w.config.positionElement||w._input}(),function(){w.selectedDates=[],w.now=w.parseDate(w.config.now)||new Date;var e=w.config.defaultDate||("INPUT"!==w.input.nodeName&&"TEXTAREA"!==w.input.nodeName||!w.input.placeholder||w.input.value!==w.input.placeholder?w.input.value:null);e&&me(e,w.config.dateFormat);w._initialDate=w.selectedDates.length>0?w.selectedDates[0]:w.config.minDate&&w.config.minDate.getTime()>w.now.getTime()?w.config.minDate:w.config.maxDate&&w.config.maxDate.getTime()0&&(w.latestSelectedDateObj=w.selectedDates[0]);void 0!==w.config.minTime&&(w.config.minTime=w.parseDate(w.config.minTime,"H:i"));void 0!==w.config.maxTime&&(w.config.maxTime=w.parseDate(w.config.maxTime,"H:i"));w.minDateHasTime=!!w.config.minDate&&(w.config.minDate.getHours()>0||w.config.minDate.getMinutes()>0||w.config.minDate.getSeconds()>0),w.maxDateHasTime=!!w.config.maxDate&&(w.config.maxDate.getHours()>0||w.config.maxDate.getMinutes()>0||w.config.maxDate.getSeconds()>0)}(),w.utils={getDaysInMonth:function(e,t){return void 0===e&&(e=w.currentMonth),void 0===t&&(t=w.currentYear),1===e&&(t%4==0&&t%100!=0||t%400==0)?29:w.l10n.daysInMonth[e]}},w.isMobile||function(){var e=window.document.createDocumentFragment();if(w.calendarContainer=s("div","flatpickr-calendar"),w.calendarContainer.tabIndex=-1,!w.config.noCalendar){if(e.appendChild((w.monthNav=s("div","flatpickr-months"),w.yearElements=[],w.monthElements=[],w.prevMonthNav=s("span","flatpickr-prev-month"),w.prevMonthNav.innerHTML=w.config.prevArrow,w.nextMonthNav=s("span","flatpickr-next-month"),w.nextMonthNav.innerHTML=w.config.nextArrow,q(),Object.defineProperty(w,"_hidePrevMonthArrow",{get:function(){return w.__hidePrevMonthArrow},set:function(e){w.__hidePrevMonthArrow!==e&&(d(w.prevMonthNav,"flatpickr-disabled",e),w.__hidePrevMonthArrow=e)}}),Object.defineProperty(w,"_hideNextMonthArrow",{get:function(){return w.__hideNextMonthArrow},set:function(e){w.__hideNextMonthArrow!==e&&(d(w.nextMonthNav,"flatpickr-disabled",e),w.__hideNextMonthArrow=e)}}),w.currentYearElement=w.yearElements[0],De(),w.monthNav)),w.innerContainer=s("div","flatpickr-innerContainer"),w.config.weekNumbers){var t=function(){w.calendarContainer.classList.add("hasWeeks");var e=s("div","flatpickr-weekwrapper");e.appendChild(s("span","flatpickr-weekday",w.l10n.weekAbbreviation));var t=s("div","flatpickr-weeks");return e.appendChild(t),{weekWrapper:e,weekNumbers:t}}(),n=t.weekWrapper,a=t.weekNumbers;w.innerContainer.appendChild(n),w.weekNumbers=a,w.weekWrapper=n}w.rContainer=s("div","flatpickr-rContainer"),w.rContainer.appendChild($()),w.daysContainer||(w.daysContainer=s("div","flatpickr-days"),w.daysContainer.tabIndex=-1),J(),w.rContainer.appendChild(w.daysContainer),w.innerContainer.appendChild(w.rContainer),e.appendChild(w.innerContainer)}w.config.enableTime&&e.appendChild(function(){w.calendarContainer.classList.add("hasTime"),w.config.noCalendar&&w.calendarContainer.classList.add("noCalendar");var e=x(w.config);w.timeContainer=s("div","flatpickr-time"),w.timeContainer.tabIndex=-1;var t=s("span","flatpickr-time-separator",":"),n=m("flatpickr-hour",{"aria-label":w.l10n.hourAriaLabel});w.hourElement=n.getElementsByTagName("input")[0];var a=m("flatpickr-minute",{"aria-label":w.l10n.minuteAriaLabel});w.minuteElement=a.getElementsByTagName("input")[0],w.hourElement.tabIndex=w.minuteElement.tabIndex=-1,w.hourElement.value=o(w.latestSelectedDateObj?w.latestSelectedDateObj.getHours():w.config.time_24hr?e.hours:function(e){switch(e%24){case 0:case 12:return 12;default:return e%12}}(e.hours)),w.minuteElement.value=o(w.latestSelectedDateObj?w.latestSelectedDateObj.getMinutes():e.minutes),w.hourElement.setAttribute("step",w.config.hourIncrement.toString()),w.minuteElement.setAttribute("step",w.config.minuteIncrement.toString()),w.hourElement.setAttribute("min",w.config.time_24hr?"0":"1"),w.hourElement.setAttribute("max",w.config.time_24hr?"23":"12"),w.hourElement.setAttribute("maxlength","2"),w.minuteElement.setAttribute("min","0"),w.minuteElement.setAttribute("max","59"),w.minuteElement.setAttribute("maxlength","2"),w.timeContainer.appendChild(n),w.timeContainer.appendChild(t),w.timeContainer.appendChild(a),w.config.time_24hr&&w.timeContainer.classList.add("time24hr");if(w.config.enableSeconds){w.timeContainer.classList.add("hasSeconds");var i=m("flatpickr-second");w.secondElement=i.getElementsByTagName("input")[0],w.secondElement.value=o(w.latestSelectedDateObj?w.latestSelectedDateObj.getSeconds():e.seconds),w.secondElement.setAttribute("step",w.minuteElement.getAttribute("step")),w.secondElement.setAttribute("min","0"),w.secondElement.setAttribute("max","59"),w.secondElement.setAttribute("maxlength","2"),w.timeContainer.appendChild(s("span","flatpickr-time-separator",":")),w.timeContainer.appendChild(i)}w.config.time_24hr||(w.amPM=s("span","flatpickr-am-pm",w.l10n.amPM[r((w.latestSelectedDateObj?w.hourElement.value:w.config.defaultHour)>11)]),w.amPM.title=w.l10n.toggleTitle,w.amPM.tabIndex=-1,w.timeContainer.appendChild(w.amPM));return w.timeContainer}());d(w.calendarContainer,"rangeMode","range"===w.config.mode),d(w.calendarContainer,"animate",!0===w.config.animate),d(w.calendarContainer,"multiMonth",w.config.showMonths>1),w.calendarContainer.appendChild(e);var i=void 0!==w.config.appendTo&&void 0!==w.config.appendTo.nodeType;if((w.config.inline||w.config.static)&&(w.calendarContainer.classList.add(w.config.inline?"inline":"static"),w.config.inline&&(!i&&w.element.parentNode?w.element.parentNode.insertBefore(w.calendarContainer,w._input.nextSibling):void 0!==w.config.appendTo&&w.config.appendTo.appendChild(w.calendarContainer)),w.config.static)){var l=s("div","flatpickr-wrapper");w.element.parentNode&&w.element.parentNode.insertBefore(l,w.element),l.appendChild(w.element),w.altInput&&l.appendChild(w.altInput),l.appendChild(w.calendarContainer)}w.config.static||w.config.inline||(void 0!==w.config.appendTo?w.config.appendTo:window.document.body).appendChild(w.calendarContainer)}(),function(){w.config.wrap&&["open","close","toggle","clear"].forEach((function(e){Array.prototype.forEach.call(w.element.querySelectorAll("[data-"+e+"]"),(function(t){return A(t,"click",w[e])}))}));if(w.isMobile)return void function(){var e=w.config.enableTime?w.config.noCalendar?"time":"datetime-local":"date";w.mobileInput=s("input",w.input.className+" flatpickr-mobile"),w.mobileInput.tabIndex=1,w.mobileInput.type=e,w.mobileInput.disabled=w.input.disabled,w.mobileInput.required=w.input.required,w.mobileInput.placeholder=w.input.placeholder,w.mobileFormatStr="datetime-local"===e?"Y-m-d\\TH:i:S":"date"===e?"Y-m-d":"H:i:S",w.selectedDates.length>0&&(w.mobileInput.defaultValue=w.mobileInput.value=w.formatDate(w.selectedDates[0],w.mobileFormatStr));w.config.minDate&&(w.mobileInput.min=w.formatDate(w.config.minDate,"Y-m-d"));w.config.maxDate&&(w.mobileInput.max=w.formatDate(w.config.maxDate,"Y-m-d"));w.input.getAttribute("step")&&(w.mobileInput.step=String(w.input.getAttribute("step")));w.input.type="hidden",void 0!==w.altInput&&(w.altInput.type="hidden");try{w.input.parentNode&&w.input.parentNode.insertBefore(w.mobileInput,w.input.nextSibling)}catch(e){}A(w.mobileInput,"change",(function(e){w.setDate(g(e).value,!1,w.mobileFormatStr),pe("onChange"),pe("onClose")}))}();var e=l(ie,50);w._debouncedChange=l(N,300),w.daysContainer&&!/iPhone|iPad|iPod/i.test(navigator.userAgent)&&A(w.daysContainer,"mouseover",(function(e){"range"===w.config.mode&&ae(g(e))}));A(window.document.body,"keydown",ne),w.config.inline||w.config.static||A(window,"resize",e);void 0!==window.ontouchstart?A(window.document,"touchstart",Z):A(window.document,"mousedown",Z);A(window.document,"focus",Z,{capture:!0}),!0===w.config.clickOpens&&(A(w._input,"focus",w.open),A(w._input,"click",w.open));void 0!==w.daysContainer&&(A(w.monthNav,"click",Ce),A(w.monthNav,["keyup","increment"],F),A(w.daysContainer,"click",ue));if(void 0!==w.timeContainer&&void 0!==w.minuteElement&&void 0!==w.hourElement){var t=function(e){return g(e).select()};A(w.timeContainer,["increment"],I),A(w.timeContainer,"blur",I,{capture:!0}),A(w.timeContainer,"click",Y),A([w.hourElement,w.minuteElement],["focus","click"],t),void 0!==w.secondElement&&A(w.secondElement,"focus",(function(){return w.secondElement&&w.secondElement.select()})),void 0!==w.amPM&&A(w.amPM,"click",(function(e){I(e),N()}))}w.config.allowInput&&A(w._input,"blur",te)}(),(w.selectedDates.length||w.config.noCalendar)&&(w.config.enableTime&&_(w.config.noCalendar?w.latestSelectedDateObj:void 0),be(!1)),k();var t=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);!w.isMobile&&t&&ce(),pe("onReady")}(),w}function k(e,t){for(var n=Array.prototype.slice.call(e).filter((function(e){return e instanceof HTMLElement})),a=[],i=0;i').html(that.buttons[key].text).addClass(that.buttons[key].btnClass).prop("disabled",that.buttons[key].isDisabled).css("display",that.buttons[key].isHidden?"none":"").click(function(e){e.preventDefault();var res=that.buttons[key].action.apply(that,[that.buttons[key]]);that.onAction.apply(that,[key,that.buttons[key]]);that._stopCountDown();if(typeof res==="undefined"||res){that.close();}});that.buttons[key].el=button_element;that.buttons[key].setText=function(text){button_element.html(text);};that.buttons[key].addClass=function(className){button_element.addClass(className);};that.buttons[key].removeClass=function(className){button_element.removeClass(className);};that.buttons[key].disable=function(){that.buttons[key].isDisabled=true;button_element.prop("disabled",true);};that.buttons[key].enable=function(){that.buttons[key].isDisabled=false;button_element.prop("disabled",false);};that.buttons[key].show=function(){that.buttons[key].isHidden=false;button_element.css("display","");};that.buttons[key].hide=function(){that.buttons[key].isHidden=true;button_element.css("display","none");};that["$_"+key]=that["$$"+key]=button_element;that.$btnc.append(button_element);});if(total_buttons===0){this.$btnc.hide();}if(this.closeIcon===null&&total_buttons===0){this.closeIcon=true;}if(this.closeIcon){if(this.closeIconClass){var closeHtml='';this.$closeIcon.html(closeHtml);}this.$closeIcon.click(function(e){e.preventDefault();var buttonName=false;var shouldClose=false;var str;if(typeof that.closeIcon==="function"){str=that.closeIcon();}else{str=that.closeIcon;}if(typeof str==="string"&&typeof that.buttons[str]!=="undefined"){buttonName=str;shouldClose=false;}else{if(typeof str==="undefined"||!!(str)===true){shouldClose=true;}else{shouldClose=false;}}if(buttonName){var btnResponse=that.buttons[buttonName].action.apply(that);shouldClose=(typeof btnResponse==="undefined")||!!(btnResponse);}if(shouldClose){that.close();}});this.$closeIcon.show();}else{this.$closeIcon.hide();}},setTitle:function(string,force){force=force||false;if(typeof string!=="undefined"){if(typeof string==="string"){this.title=string;}else{if(typeof string==="function"){if(typeof string.promise==="function"){console.error("Promise was returned from title function, this is not supported.");}var response=string();if(typeof response==="string"){this.title=response;}else{this.title=false;}}else{this.title=false;}}}if(this.isAjaxLoading&&!force){return;}this.$title.html(this.title||"");this.updateTitleContainer();},setIcon:function(iconClass,force){force=force||false;if(typeof iconClass!=="undefined"){if(typeof iconClass==="string"){this.icon=iconClass;}else{if(typeof iconClass==="function"){var response=iconClass();if(typeof response==="string"){this.icon=response;}else{this.icon=false;}}else{this.icon=false;}}}if(this.isAjaxLoading&&!force){return;}this.$icon.html(this.icon?'':"");this.updateTitleContainer();},updateTitleContainer:function(){if(!this.title&&!this.icon){this.$titleContainer.hide();}else{this.$titleContainer.show();}},setContentPrepend:function(content,force){if(!content){return;}this.contentParsed.prepend(content);},setContentAppend:function(content){if(!content){return;}this.contentParsed.append(content);},setContent:function(content,force){force=!!force;var that=this;if(content){this.contentParsed.html("").append(content);}if(this.isAjaxLoading&&!force){return;}this.$content.html("");this.$content.append(this.contentParsed);setTimeout(function(){that.$body.find("input[autofocus]:visible:first").focus();},100);},loadingSpinner:false,showLoading:function(disableButtons){this.loadingSpinner=true;this.$jconfirmBox.addClass("loading");if(disableButtons){this.$btnc.find("button").prop("disabled",true);}},hideLoading:function(enableButtons){this.loadingSpinner=false;this.$jconfirmBox.removeClass("loading");if(enableButtons){this.$btnc.find("button").prop("disabled",false);}},ajaxResponse:false,contentParsed:"",isAjax:false,isAjaxLoading:false,_parseContent:function(){var that=this;var e=" ";if(typeof this.content==="function"){var res=this.content.apply(this);if(typeof res==="string"){this.content=res;}else{if(typeof res==="object"&&typeof res.always==="function"){this.isAjax=true;this.isAjaxLoading=true;res.always(function(data,status,xhr){that.ajaxResponse={data:data,status:status,xhr:xhr};that._contentReady.resolve(data,status,xhr);if(typeof that.contentLoaded==="function"){that.contentLoaded(data,status,xhr);}});this.content=e;}else{this.content=e;}}}if(typeof this.content==="string"&&this.content.substr(0,4).toLowerCase()==="url:"){this.isAjax=true;this.isAjaxLoading=true;var u=this.content.substring(4,this.content.length);$.get(u).done(function(html){that.contentParsed.html(html);}).always(function(data,status,xhr){that.ajaxResponse={data:data,status:status,xhr:xhr};that._contentReady.resolve(data,status,xhr);if(typeof that.contentLoaded==="function"){that.contentLoaded(data,status,xhr);}});}if(!this.content){this.content=e;}if(!this.isAjax){this.contentParsed.html(this.content);this.setContent();that._contentReady.resolve();}},_stopCountDown:function(){clearInterval(this.autoCloseInterval);if(this.$cd){this.$cd.remove();}},_startCountDown:function(){var that=this;var opt=this.autoClose.split("|");if(opt.length!==2){console.error("Invalid option for autoClose. example 'close|10000'");return false;}var button_key=opt[0];var time=parseInt(opt[1]);if(typeof this.buttons[button_key]==="undefined"){console.error("Invalid button key '"+button_key+"' for autoClose");return false;}var seconds=Math.ceil(time/1000);this.$cd=$(' ('+seconds+")").appendTo(this["$_"+button_key]);this.autoCloseInterval=setInterval(function(){that.$cd.html(" ("+(seconds-=1)+") ");if(seconds<=0){that["$$"+button_key].trigger("click");that._stopCountDown();}},1000);},_getKey:function(key){switch(key){case 192:return"tilde";case 13:return"enter";case 16:return"shift";case 9:return"tab";case 20:return"capslock";case 17:return"ctrl";case 91:return"win";case 18:return"alt";case 27:return"esc";case 32:return"space";}var initial=String.fromCharCode(key);if(/^[A-z0-9]+$/.test(initial)){return initial.toLowerCase();}else{return false;}},reactOnKey:function(e){var that=this;var a=$(".jconfirm");if(a.eq(a.length-1)[0]!==this.$el[0]){return false;}var key=e.which;if(this.$content.find(":input").is(":focus")&&/13|32/.test(key)){return false;}var keyChar=this._getKey(key);if(keyChar==="esc"&&this.escapeKey){if(this.escapeKey===true){this.$scrollPane.trigger("click");}else{if(typeof this.escapeKey==="string"||typeof this.escapeKey==="function"){var buttonKey;if(typeof this.escapeKey==="function"){buttonKey=this.escapeKey();}else{buttonKey=this.escapeKey;}if(buttonKey){if(typeof this.buttons[buttonKey]==="undefined"){console.warn("Invalid escapeKey, no buttons found with key "+buttonKey);}else{this["$_"+buttonKey].trigger("click");}}}}}$.each(this.buttons,function(key,button){if(button.keys.indexOf(keyChar)!==-1){that["$_"+key].trigger("click");}});},setDialogCenter:function(){console.info("setDialogCenter is deprecated, dialogs are centered with CSS3 tables");},_unwatchContent:function(){clearInterval(this._timer);},close:function(onClosePayload){var that=this;if(typeof this.onClose==="function"){this.onClose(onClosePayload);}this._unwatchContent();$(window).unbind("resize."+this._id);$(window).unbind("keyup."+this._id);$(window).unbind("jcKeyDown."+this._id);if(this.draggable){$(window).unbind("mousemove."+this._id);$(window).unbind("mouseup."+this._id);this.$titleContainer.unbind("mousedown");}that.$el.removeClass(that.loadedClass);$("body").removeClass("jconfirm-no-scroll-"+that._id);that.$jconfirmBoxContainer.removeClass("jconfirm-no-transition");setTimeout(function(){that.$body.addClass(that.closeAnimationParsed);that.$jconfirmBg.addClass("jconfirm-bg-h");var closeTimer=(that.closeAnimation==="none")?1:that.animationSpeed;setTimeout(function(){that.$el.remove();var l=w.jconfirm.instances;var i=w.jconfirm.instances.length-1;for(i;i>=0;i--){if(w.jconfirm.instances[i]._id===that._id){w.jconfirm.instances.splice(i,1);}}if(!w.jconfirm.instances.length){if(that.scrollToPreviousElement&&w.jconfirm.lastFocused&&w.jconfirm.lastFocused.length&&$.contains(document,w.jconfirm.lastFocused[0])){var $lf=w.jconfirm.lastFocused;if(that.scrollToPreviousElementAnimate){var st=$(window).scrollTop();var ot=w.jconfirm.lastFocused.offset().top;var wh=$(window).height();if(!(ot>st&&ot<(st+wh))){var scrollTo=(ot-Math.round((wh/3)));$("html, body").animate({scrollTop:scrollTo},that.animationSpeed,"swing",function(){$lf.focus();});}else{$lf.focus();}}else{$lf.focus();}w.jconfirm.lastFocused=false;}}if(typeof that.onDestroy==="function"){that.onDestroy();}},closeTimer*0.4);},50);return true;},open:function(){if(this.isOpen()){return false;}this._buildHTML();this._bindEvents();this._open();return true;},setStartingPoint:function(){var el=false;if(this.animateFromElement!==true&&this.animateFromElement){el=this.animateFromElement;w.jconfirm.lastClicked=false;}else{if(w.jconfirm.lastClicked&&this.animateFromElement===true){el=w.jconfirm.lastClicked;w.jconfirm.lastClicked=false;}else{return false;}}if(!el){return false;}var offset=el.offset();var iTop=el.outerHeight()/2;var iLeft=el.outerWidth()/2;iTop-=this.$jconfirmBox.outerHeight()/2;iLeft-=this.$jconfirmBox.outerWidth()/2;var sourceTop=offset.top+iTop;sourceTop=sourceTop-this._scrollTop();var sourceLeft=offset.left+iLeft;var wh=$(window).height()/2;var ww=$(window).width()/2;var targetH=wh-this.$jconfirmBox.outerHeight()/2;var targetW=ww-this.$jconfirmBox.outerWidth()/2;sourceTop-=targetH;sourceLeft-=targetW;if(Math.abs(sourceTop)>wh||Math.abs(sourceLeft)>ww){return false;}this.$jconfirmBoxContainer.css("transform","translate("+sourceLeft+"px, "+sourceTop+"px)");},_open:function(){var that=this;if(typeof that.onOpenBefore==="function"){that.onOpenBefore();}this.$body.removeClass(this.animationParsed);this.$jconfirmBg.removeClass("jconfirm-bg-h");this.$body.focus();that.$jconfirmBoxContainer.css("transform","translate("+0+"px, "+0+"px)");setTimeout(function(){that.$body.css(that._getCSS(that.animationSpeed,1));that.$body.css({"transition-property":that.$body.css("transition-property")+", margin"});that.$jconfirmBoxContainer.addClass("jconfirm-no-transition");that._modalReady.resolve();if(typeof that.onOpen==="function"){that.onOpen();}that.$el.addClass(that.loadedClass);},this.animationSpeed);},loadedClass:"jconfirm-open",isClosed:function(){return !this.$el||this.$el.parent().length===0;},isOpen:function(){return !this.isClosed();},toggle:function(){if(!this.isOpen()){this.open();}else{this.close();}}};w.jconfirm.instances=[];w.jconfirm.lastFocused=false;w.jconfirm.pluginDefaults={template:'
',title:"Hello",titleClass:"",type:"default",typeAnimated:true,draggable:true,dragWindowGap:15,dragWindowBorder:true,animateFromElement:true,alignMiddle:true,smoothContent:true,content:"Are you sure to continue?",buttons:{},defaultButtons:{ok:{action:function(){}},close:{action:function(){}}},contentLoaded:function(){},icon:"",lazyOpen:false,bgOpacity:null,theme:"light",animation:"scale",closeAnimation:"scale",animationSpeed:400,animationBounce:1,escapeKey:true,rtl:false,container:"body",containerFluid:false,backgroundDismiss:false,backgroundDismissAnimation:"shake",autoClose:false,closeIcon:null,closeIconClass:false,watchInterval:100,columnClass:"col-md-4 col-md-offset-4 col-sm-6 col-sm-offset-3 col-xs-10 col-xs-offset-1",boxWidth:"50%",scrollToPreviousElement:true,scrollToPreviousElementAnimate:true,useBootstrap:true,offsetTop:40,offsetBottom:40,bootstrapClasses:{container:"container",containerFluid:"container-fluid",row:"row"},onContentReady:function(){},onOpenBefore:function(){},onOpen:function(){},onClose:function(){},onDestroy:function(){},onAction:function(){}};var keyDown=false;$(window).on("keydown",function(e){if(!keyDown){var $target=$(e.target);var pass=false;if($target.closest(".jconfirm-box").length){pass=true;}if(pass){$(window).trigger("jcKeyDown");}keyDown=true;}});$(window).on("keyup",function(){keyDown=false;});w.jconfirm.lastClicked=false;$(document).on("mousedown","button, a, [jc-source]",function(){w.jconfirm.lastClicked=$(this);});})); \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/js/vendor/jquery.matchHeight.js b/wp-content/plugins/wp-mail-smtp/assets/js/vendor/jquery.matchHeight.js new file mode 100755 index 00000000..48925b5f --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/js/vendor/jquery.matchHeight.js @@ -0,0 +1,388 @@ +/** +* jquery-match-height 0.7.2 by @liabru +* http://brm.io/jquery-match-height/ +* License: MIT +*/ + +;(function(factory) { // eslint-disable-line no-extra-semi + 'use strict'; + if (typeof define === 'function' && define.amd) { + // AMD + define(['jquery'], factory); + } else if (typeof module !== 'undefined' && module.exports) { + // CommonJS + module.exports = factory(require('jquery')); + } else { + // Global + factory(jQuery); + } +})(function($) { + /* + * internal + */ + + var _previousResizeWidth = -1, + _updateTimeout = -1; + + /* + * _parse + * value parse utility function + */ + + var _parse = function(value) { + // parse value and convert NaN to 0 + return parseFloat(value) || 0; + }; + + /* + * _rows + * utility function returns array of jQuery selections representing each row + * (as displayed after float wrapping applied by browser) + */ + + var _rows = function(elements) { + var tolerance = 1, + $elements = $(elements), + lastTop = null, + rows = []; + + // group elements by their top position + $elements.each(function(){ + var $that = $(this), + top = $that.offset().top - _parse($that.css('margin-top')), + lastRow = rows.length > 0 ? rows[rows.length - 1] : null; + + if (lastRow === null) { + // first item on the row, so just push it + rows.push($that); + } else { + // if the row top is the same, add to the row group + if (Math.floor(Math.abs(lastTop - top)) <= tolerance) { + rows[rows.length - 1] = lastRow.add($that); + } else { + // otherwise start a new row group + rows.push($that); + } + } + + // keep track of the last row top + lastTop = top; + }); + + return rows; + }; + + /* + * _parseOptions + * handle plugin options + */ + + var _parseOptions = function(options) { + var opts = { + byRow: true, + property: 'height', + target: null, + remove: false + }; + + if (typeof options === 'object') { + return $.extend(opts, options); + } + + if (typeof options === 'boolean') { + opts.byRow = options; + } else if (options === 'remove') { + opts.remove = true; + } + + return opts; + }; + + /* + * matchHeight + * plugin definition + */ + + var matchHeight = $.fn.matchHeight = function(options) { + var opts = _parseOptions(options); + + // handle remove + if (opts.remove) { + var that = this; + + // remove fixed height from all selected elements + this.css(opts.property, ''); + + // remove selected elements from all groups + $.each(matchHeight._groups, function(key, group) { + group.elements = group.elements.not(that); + }); + + // TODO: cleanup empty groups + + return this; + } + + if (this.length <= 1 && !opts.target) { + return this; + } + + // keep track of this group so we can re-apply later on load and resize events + matchHeight._groups.push({ + elements: this, + options: opts + }); + + // match each element's height to the tallest element in the selection + matchHeight._apply(this, opts); + + return this; + }; + + /* + * plugin global options + */ + + matchHeight.version = '0.7.2'; + matchHeight._groups = []; + matchHeight._throttle = 80; + matchHeight._maintainScroll = false; + matchHeight._beforeUpdate = null; + matchHeight._afterUpdate = null; + matchHeight._rows = _rows; + matchHeight._parse = _parse; + matchHeight._parseOptions = _parseOptions; + + /* + * matchHeight._apply + * apply matchHeight to given elements + */ + + matchHeight._apply = function(elements, options) { + var opts = _parseOptions(options), + $elements = $(elements), + rows = [$elements]; + + // take note of scroll position + var scrollTop = $(window).scrollTop(), + htmlHeight = $('html').outerHeight(true); + + // get hidden parents + var $hiddenParents = $elements.parents().filter(':hidden'); + + // cache the original inline style + $hiddenParents.each(function() { + var $that = $(this); + $that.data('style-cache', $that.attr('style')); + }); + + // temporarily must force hidden parents visible + $hiddenParents.css('display', 'block'); + + // get rows if using byRow, otherwise assume one row + if (opts.byRow && !opts.target) { + + // must first force an arbitrary equal height so floating elements break evenly + $elements.each(function() { + var $that = $(this), + display = $that.css('display'); + + // temporarily force a usable display value + if (display !== 'inline-block' && display !== 'flex' && display !== 'inline-flex') { + display = 'block'; + } + + // cache the original inline style + $that.data('style-cache', $that.attr('style')); + + $that.css({ + 'display': display, + 'padding-top': '0', + 'padding-bottom': '0', + 'margin-top': '0', + 'margin-bottom': '0', + 'border-top-width': '0', + 'border-bottom-width': '0', + 'height': '100px', + 'overflow': 'hidden' + }); + }); + + // get the array of rows (based on element top position) + rows = _rows($elements); + + // revert original inline styles + $elements.each(function() { + var $that = $(this); + $that.attr('style', $that.data('style-cache') || ''); + }); + } + + $.each(rows, function(key, row) { + var $row = $(row), + targetHeight = 0; + + if (!opts.target) { + // skip apply to rows with only one item + if (opts.byRow && $row.length <= 1) { + $row.css(opts.property, ''); + return; + } + + // iterate the row and find the max height + $row.each(function(){ + var $that = $(this), + style = $that.attr('style'), + display = $that.css('display'); + + // temporarily force a usable display value + if (display !== 'inline-block' && display !== 'flex' && display !== 'inline-flex') { + display = 'block'; + } + + // ensure we get the correct actual height (and not a previously set height value) + var css = { 'display': display }; + css[opts.property] = ''; + $that.css(css); + + // find the max height (including padding, but not margin) + if ($that.outerHeight(false) > targetHeight) { + targetHeight = $that.outerHeight(false); + } + + // revert styles + if (style) { + $that.attr('style', style); + } else { + $that.css('display', ''); + } + }); + } else { + // if target set, use the height of the target element + targetHeight = opts.target.outerHeight(false); + } + + // iterate the row and apply the height to all elements + $row.each(function(){ + var $that = $(this), + verticalPadding = 0; + + // don't apply to a target + if (opts.target && $that.is(opts.target)) { + return; + } + + // handle padding and border correctly (required when not using border-box) + if ($that.css('box-sizing') !== 'border-box') { + verticalPadding += _parse($that.css('border-top-width')) + _parse($that.css('border-bottom-width')); + verticalPadding += _parse($that.css('padding-top')) + _parse($that.css('padding-bottom')); + } + + // set the height (accounting for padding and border) + $that.css(opts.property, (targetHeight - verticalPadding) + 'px'); + }); + }); + + // revert hidden parents + $hiddenParents.each(function() { + var $that = $(this); + $that.attr('style', $that.data('style-cache') || null); + }); + + // restore scroll position if enabled + if (matchHeight._maintainScroll) { + $(window).scrollTop((scrollTop / htmlHeight) * $('html').outerHeight(true)); + } + + return this; + }; + + /* + * matchHeight._applyDataApi + * applies matchHeight to all elements with a data-match-height attribute + */ + + matchHeight._applyDataApi = function() { + var groups = {}; + + // generate groups by their groupId set by elements using data-match-height + $('[data-match-height], [data-mh]').each(function() { + var $this = $(this), + groupId = $this.attr('data-mh') || $this.attr('data-match-height'); + + if (groupId in groups) { + groups[groupId] = groups[groupId].add($this); + } else { + groups[groupId] = $this; + } + }); + + // apply matchHeight to each group + $.each(groups, function() { + this.matchHeight(true); + }); + }; + + /* + * matchHeight._update + * updates matchHeight on all current groups with their correct options + */ + + var _update = function(event) { + if (matchHeight._beforeUpdate) { + matchHeight._beforeUpdate(event, matchHeight._groups); + } + + $.each(matchHeight._groups, function() { + matchHeight._apply(this.elements, this.options); + }); + + if (matchHeight._afterUpdate) { + matchHeight._afterUpdate(event, matchHeight._groups); + } + }; + + matchHeight._update = function(throttle, event) { + // prevent update if fired from a resize event + // where the viewport width hasn't actually changed + // fixes an event looping bug in IE8 + if (event && event.type === 'resize') { + var windowWidth = $(window).width(); + if (windowWidth === _previousResizeWidth) { + return; + } + _previousResizeWidth = windowWidth; + } + + // throttle updates + if (!throttle) { + _update(event); + } else if (_updateTimeout === -1) { + _updateTimeout = setTimeout(function() { + _update(event); + _updateTimeout = -1; + }, matchHeight._throttle); + } + }; + + /* + * bind events + */ + + // apply on DOM ready event + $(matchHeight._applyDataApi); + + // use on or bind where supported + var on = $.fn.on ? 'on' : 'bind'; + + // update heights on load and resize events + $(window)[on]('load', function(event) { + matchHeight._update(false, event); + }); + + // throttled update heights on resize events + $(window)[on]('resize orientationchange', function(event) { + matchHeight._update(true, event); + }); + +}); diff --git a/wp-content/plugins/wp-mail-smtp/assets/js/vendor/jquery.matchHeight.min.js b/wp-content/plugins/wp-mail-smtp/assets/js/vendor/jquery.matchHeight.min.js new file mode 100755 index 00000000..fc942dd4 --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/js/vendor/jquery.matchHeight.min.js @@ -0,0 +1 @@ +!function(t){"use strict";"function"==typeof define&&define.amd?define(["jquery"],t):"undefined"!=typeof module&&module.exports?module.exports=t(require("jquery")):t(jQuery)}(function(l){function c(t){return parseFloat(t)||0}function h(t){var e=l(t),n=null,a=[];return e.each(function(){var t=l(this),e=t.offset().top-c(t.css("margin-top")),o=0a&&(a=t.outerHeight(!1)),e?t.attr("style",e):t.css("display","")})}o.each(function(){var t=l(this),e=0;i.target&&t.is(i.target)||("border-box"!==t.css("box-sizing")&&(e+=c(t.css("border-top-width"))+c(t.css("border-bottom-width")),e+=c(t.css("padding-top"))+c(t.css("padding-bottom"))),t.css(i.property,a-e+"px"))})}),s.each(function(){var t=l(this);t.attr("style",t.data("style-cache")||null)}),d._maintainScroll&&l(window).scrollTop(a/r*l("html").outerHeight(!0)),this},d._applyDataApi=function(){var o={};l("[data-match-height], [data-mh]").each(function(){var t=l(this),e=t.attr("data-mh")||t.attr("data-match-height");o[e]=e in o?o[e].add(t):t}),l.each(o,function(){this.matchHeight(!0)})};function i(t){d._beforeUpdate&&d._beforeUpdate(t,d._groups),l.each(d._groups,function(){d._apply(this.elements,this.options)}),d._afterUpdate&&d._afterUpdate(t,d._groups)}d._update=function(t,e){if(e&&"resize"===e.type){var o=l(window).width();if(o===n)return;n=o}t?-1===a&&(a=setTimeout(function(){i(e),a=-1},d._throttle)):i(e)},l(d._applyDataApi);var t=l.fn.on?"on":"bind";l(window)[t]("load",function(t){d._update(!1,t)}),l(window)[t]("resize orientationchange",function(t){d._update(!0,t)})}); \ No newline at end of file diff --git a/wp-content/plugins/wp-mail-smtp/assets/js/vendor/lity.min.js b/wp-content/plugins/wp-mail-smtp/assets/js/vendor/lity.min.js new file mode 100755 index 00000000..40d0f34a --- /dev/null +++ b/wp-content/plugins/wp-mail-smtp/assets/js/vendor/lity.min.js @@ -0,0 +1,5 @@ +/*! Lity - v2.4.1 - 2020-04-26 +* http://sorgalla.com/lity/ +* Copyright (c) 2015-2020 Jan Sorgalla; Licensed MIT */ + +!function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(c){return b(a,c)}):"object"==typeof module&&"object"==typeof module.exports?module.exports=b(a,require("jquery")):a.lity=b(a,a.jQuery||a.Zepto)}("undefined"!=typeof window?window:this,function(a,b){"use strict";function c(a){var b=B();return N&&a.length?(a.one(N,b.resolve),setTimeout(b.resolve,500)):b.resolve(),b.promise()}function d(a,c,d){if(1===arguments.length)return b.extend({},a);if("string"==typeof c){if(void 0===d)return void 0===a[c]?null:a[c];a[c]=d}else b.extend(a,c);return this}function e(a){for(var b,c=decodeURI(a.split("#")[0]).split("&"),d={},e=0,f=c.length;e-1?"&":"?")+b.param(c)}function g(a,b){var c=a.indexOf("#");return-1===c?b:(c>0&&(a=a.substr(c)),b+a)}function h(a){return b('').append(a)}function i(a,c){var d=c.opener()&&c.opener().data("lity-desc")||"Image with no description",e=b(''+d+''),f=B(),g=function(){f.reject(h("Failed loading image"))};return e.on("load",function(){if(0===this.naturalWidth)return g();f.resolve(e)}).on("error",g),f.promise()}function j(a,c){var d,e,f;try{d=b(a)}catch(a){return!1}return!!d.length&&(e=b(''),f=d.hasClass("lity-hide"),c.element().one("lity:remove",function(){e.before(d).remove(),f&&!d.closest(".lity-content").length&&d.addClass("lity-hide")}),d.removeClass("lity-hide").after(e))}function k(a){var c=J.exec(a);return!!c&&o(g(a,f("https://www.youtube"+(c[2]||"")+".com/embed/"+c[4],b.extend({autoplay:1},e(c[5]||"")))))}function l(a){var c=K.exec(a);return!!c&&o(g(a,f("https://player.vimeo.com/video/"+c[3],b.extend({autoplay:1},e(c[4]||"")))))}function m(a){var c=M.exec(a);return!!c&&(0!==a.indexOf("http")&&(a="https:"+a),o(g(a,f("https://www.facebook.com/plugins/video.php?href="+a,b.extend({autoplay:1},e(c[4]||""))))))}function n(a){var b=L.exec(a);return!!b&&o(g(a,f("https://www.google."+b[3]+"/maps?"+b[6],{output:b[6].indexOf("layer=c")>0?"svembed":"embed"})))}function o(a){return'
'; + + $.dialog( { + title: false, + content: video, + closeIcon: true, + boxWidth: '70%', + } ); + } ); + }, + + //--------------------------------------------------------------------// + // Addons List. + //--------------------------------------------------------------------// + + /** + * Element bindings for the Addons List page. + * + * @since 1.3.9 + */ + initAddons() { // eslint-disable-line max-lines-per-function + // Only run on the addons page. + if ( ! $( '#wpforms-admin-addons' ).length ) { + return; + } + + // Addons searching. + const $sectionAll = $( '#wpforms-addons-list-section-all' ); + const $sectionInstalled = $( '#wpforms-addons-list-section-installed' ); + + if ( $sectionAll.length || $sectionInstalled.length ) { + let addonSearchInstalled; + let addonSearchAll; + + if ( $sectionInstalled.length ) { + addonSearchInstalled = new List( + 'wpforms-addons-list-section-installed', + { + valueNames: [ 'addon-link' ], + } + ); + } + + if ( $sectionAll.length ) { + addonSearchAll = new List( + 'wpforms-addons-list-section-all', + { + valueNames: [ 'addon-link' ], + } + ); + } + + $( '#wpforms-addons-search' ).on( + 'keyup search', + function() { + WPFormsAdmin.updateAddonSearchResult( this, addonSearchAll, addonSearchInstalled ); + } + ); + } + + // Toggle an addon state. + $( document ).on( 'change', '.wpforms-addons-list-item .wpforms-toggle-control input', function( event ) { + event.preventDefault(); + + if ( $( this ).hasClass( 'disabled' ) ) { + return false; + } + + WPFormsAdmin.addonToggleNew( $( this ) ); + } ); + + $( document ).on( 'click', '.wpforms-addons-list-item button', function( event ) { + event.preventDefault(); + + if ( $( this ).hasClass( 'disabled' ) ) { + return false; + } + + WPFormsAdmin.addonToggleNew( $( this ) ); + } ); + + $( document ).on( 'click', '#wpforms-admin-addons .addon-item button', function( event ) { + event.preventDefault(); + + if ( $( this ).hasClass( 'disabled' ) ) { + return false; + } + + WPFormsAdmin.addonToggle( $( this ) ); + } ); + }, + + /** + * Handle addons search field operations. + * + * @since 1.7.4 + * + * @param {Object} searchField The search field HTML element. + * @param {Object} addonSearchAll Addons all list (uses List.js). + * @param {Object} addonSearchInstalled Addons installed list (uses List.js). + */ + updateAddonSearchResult( searchField, addonSearchAll, addonSearchInstalled ) { + let searchTerm = $( searchField ).val(); + + /* + * Replace dot and comma with space + * it is a workaround for a bug in the list.js library. + * + * Note: remove when the issue below is fixed: + * @see https://github.com/javve/list.js/issues/699 + */ + searchTerm = searchTerm.replace( /[.,]/g, ' ' ); + + const $noResultsMessage = $( '#wpforms-addons-no-results' ); + const $sectionAll = $( '#wpforms-addons-list-section-all' ); + const $sectionInstalled = $( '#wpforms-addons-list-section-installed' ); + const searchResultsAll = addonSearchAll ? addonSearchAll.search( searchTerm ) : []; + const searchResultsInstalled = addonSearchInstalled ? addonSearchInstalled.search( searchTerm ) : []; + + $noResultsMessage.toggle( searchResultsAll.length === 0 && searchResultsInstalled.length === 0 ); + $sectionAll.toggle( searchResultsAll.length > 0 ); + $sectionInstalled.toggle( searchResultsInstalled.length > 0 ); + }, + + /** + * Change plugin/addon state. + * + * @since 1.6.3 + * + * @param {string} plugin Plugin slug or URL for download. + * @param {string} state State status activate|deactivate|install. + * @param {string} pluginType Plugin type addon or plugin. + * @param {Function} callback Callback for get a result from AJAX. + * @param {Function} errorCallback Callback for get error from AJAX. + */ + setAddonState( plugin, state, pluginType, callback, errorCallback ) { + const actions = { + activate: 'wpforms_activate_addon', + install: 'wpforms_install_addon', + deactivate: 'wpforms_deactivate_addon', + incompatible: 'wpforms_activate_addon', + }; + const action = actions[ state ]; + + if ( ! action ) { + return; + } + + const data = { + action, + nonce: wpforms_admin.nonce, + plugin, + type: pluginType, + }; + + $.post( wpforms_admin.ajax_url, data, function( res ) { + callback( res ); + } ).fail( function( xhr ) { + errorCallback( xhr ); + } ); + }, + + /** + * Toggle addon state. + * + * @since 1.8.6 + * + * @param {Object} $btn Button element. + */ + // eslint-disable-next-line max-lines-per-function + addonToggleNew( $btn ) { + const $footer = $btn.parents( '.wpforms-addons-list-item-footer' ); + const classes = { + active: 'wpforms-addons-list-item-footer-active', + activating: 'wpforms-addons-list-item-footer-activating', + incompatible: 'wpforms-addons-list-item-footer-incompatible', + installed: 'wpforms-addons-list-item-footer-installed', + missing: 'wpforms-addons-list-item-footer-missing', + goToUrl: 'wpforms-addons-list-item-footer-go-to-url', + withError: 'wpforms-addons-list-item-footer-with-error', + }; + + // Open url in new tab. + if ( $footer.hasClass( classes.goToUrl ) ) { + window.open( $btn.attr( 'data-plugin' ), '_blank' ); + return; + } + + $btn.prop( 'disabled', true ); + + let checked = $btn.is( ':checked' ); + let cssClass; + const plugin = $footer.attr( 'data-plugin' ); + const pluginType = $footer.attr( 'data-type' ); + const $addon = $btn.parents( '.wpforms-addons-list-item' ); + const state = WPFormsAdmin.getAddonState( $footer, classes, $btn ); + + /** + * Handle error. + * + * @param {Object} res Response object. + */ + function handleError( res ) { + $footer.addClass( classes.withError ); + + if ( typeof res.data === 'object' ) { + $footer.append( `` ); + } else { + $footer.append( `` ); + } + + if ( state === 'install' ) { + checked = false; + WPFormsAdmin.removeSpinnerFromButton( $btn ); + } else if ( state === 'deactivate' ) { + checked = true; + } else if ( state === 'activate' ) { + checked = false; + } + } + + /** + * Handle success. + * + * @param {Object} res Response object. + */ + function handleSuccess( res ) { + if ( state === 'install' ) { + cssClass = classes.active; + checked = true; + + $footer.attr( 'data-plugin', res.data.basename ); + + if ( ! res.data.is_activated ) { + cssClass = classes.installed; + checked = false; + } + + $btn.hide(); + $btn = $btn.closest( '.wpforms-addons-list-item' ).find( '.wpforms-toggle-control input' ); + } else if ( state === 'activate' ) { + $footer.find( '.wpforms-addons-list-item-footer-settings-link' ).fadeIn( 150 ); + cssClass = classes.active; + checked = true; + } else if ( state === 'deactivate' ) { + $footer.find( '.wpforms-addons-list-item-footer-settings-link' ).fadeOut( 150 ); + cssClass = classes.installed; + checked = false; + } + + $footer.removeClass( classes.active + ' ' + classes.incompatible + ' ' + classes.installed + ' ' + classes.missing ).addClass( cssClass ); + } + + WPFormsAdmin.setAddonState( plugin, state, pluginType, function( res ) { + if ( res.success ) { + handleSuccess( res ); + } else { + handleError( res ); + } + + WPFormsAdmin.updateAddonButtonPropertiesAndUI( $btn, $addon, $footer, classes, checked ); + }, function() { + handleError( { + data: wpforms_admin.server_error, + } ); + + WPFormsAdmin.updateAddonButtonPropertiesAndUI( $btn, $addon, $footer, classes, checked ); + } ); + }, + + /** + * Add spinner to button. + * + * @since 1.8.6 + * + * @param {Object} $button Button element. + */ + addSpinnerToButton( $button ) { + const spinnerBlue = ''; + const originalWidth = $button.width(); + + $button.data( 'original-text', $button.html() ); + $button.width( originalWidth ).html( spinnerBlue ); + }, + + /** + * Remove spinner from button. + * + * @since 1.8.6 + * + * @param {Object} $button Button element. + */ + removeSpinnerFromButton( $button ) { + $button.html( $button.data( 'original-text' ) ); + }, + + /** + * Get addon state. + * + * @since 1.8.6 + * + * @param {Object} $footer Footer element. + * @param {Object} classes Classes object. + * @param {Object} $button Button element. + * + * @return {string} State. + */ + getAddonState( $footer, classes, $button ) { + if ( $footer.hasClass( classes.active ) || $footer.hasClass( classes.incompatible ) ) { + return 'deactivate'; + } + + if ( $footer.hasClass( classes.installed ) ) { + return 'activate'; + } + + if ( $footer.hasClass( classes.missing ) ) { + WPFormsAdmin.addSpinnerToButton( $button ); + return 'install'; + } + + return ''; + }, + + /** + * Update button properties and UI. + * + * @since 1.8.6 + * + * @param {Object} $btn Button element. + * @param {Object} $addon Addon element. + * @param {Object} $footer Footer element. + * @param {Object} classes Classes object. + * @param {boolean} checked Checked state. + */ + updateAddonButtonPropertiesAndUI( $btn, $addon, $footer, classes, checked ) { + $btn.prop( 'checked', checked ); + $btn.prop( 'disabled', false ); + $btn.siblings( '.wpforms-toggle-control-status' ).html( $btn.siblings( '.wpforms-toggle-control-status' ).data( checked ? 'on' : 'off' ) ); + + if ( $addon.find( '.wpforms-addons-list-item-footer-error' ).length > 0 ) { + setTimeout( function() { + $footer.removeClass( classes.withError ); + $addon.find( '.wpforms-addons-list-item-footer-error' ).remove(); + }, 6000 ); + } + }, + + /** + * Scroll to integration. + * + * @since 1.8.6 + */ + scrollToIntegration() { + const currentURL = window.location.href; + // eslint-disable-next-line compat/compat + const urlObject = new URL( currentURL ); + const searchParams = urlObject.searchParams; + const addon = searchParams.get( 'addon' ); + + if ( addon ) { + const $elementToScrollTo = $( '.wpforms-settings-provider[id*="' + addon + '"]' ); + + if ( $elementToScrollTo.length ) { + $( window ).scrollTop( $elementToScrollTo.offset().top ); + searchParams.delete( 'addon' ); + + window.history.pushState( {}, document.title, urlObject.toString() ); + } + } + }, + + /** + * Toggle addon state. + * + * @since 1.3.9 + * + * @param {Object} $btn Button element. + */ + // eslint-disable-next-line max-lines-per-function,complexity + addonToggle( $btn ) { + let state, + cssClass, + stateText, + buttonText, + errorText, + successText; + + if ( $btn.hasClass( 'status-go-to-url' ) ) { + // Open url in new tab. + window.open( $btn.attr( 'data-plugin' ), '_blank' ); + return; + } + + $btn.prop( 'disabled', true ).addClass( 'loading' ); + $btn.html( s.iconSpinner ); + + const pluginType = $btn.attr( 'data-type' ); + + if ( $btn.hasClass( 'status-active' ) ) { + // Deactivate. + state = 'deactivate'; + cssClass = 'status-installed'; + if ( pluginType === 'plugin' ) { + cssClass += ' button button-secondary'; + } + stateText = wpforms_admin.addon_inactive; + buttonText = wpforms_admin.addon_activate; + errorText = wpforms_admin.addon_deactivate; + if ( pluginType === 'addon' ) { + buttonText = s.iconActivate + buttonText; + errorText = s.iconDeactivate + errorText; + } + } else if ( $btn.hasClass( 'status-installed' ) ) { + // Activate. + state = 'activate'; + cssClass = 'status-active'; + if ( pluginType === 'plugin' ) { + cssClass += ' button button-secondary disabled'; + } + stateText = wpforms_admin.addon_active; + buttonText = wpforms_admin.addon_deactivate; + if ( pluginType === 'addon' ) { + buttonText = s.iconDeactivate + buttonText; + errorText = s.iconActivate + wpforms_admin.addon_activate; + } else if ( pluginType === 'plugin' ) { + buttonText = wpforms_admin.addon_activated; + errorText = wpforms_admin.addon_activate; + } + } else if ( $btn.hasClass( 'status-missing' ) ) { + // Install & Activate. + state = 'install'; + cssClass = 'status-active'; + if ( pluginType === 'plugin' ) { + cssClass += ' button disabled'; + } + stateText = wpforms_admin.addon_active; + buttonText = wpforms_admin.addon_activated; + errorText = s.iconInstall; + if ( pluginType === 'addon' ) { + buttonText = s.iconActivate + wpforms_admin.addon_deactivate; + errorText += wpforms_admin.addon_install; + } + } else { + return; + } + + const plugin = $btn.attr( 'data-plugin' ); + + // eslint-disable-next-line complexity + WPFormsAdmin.setAddonState( plugin, state, pluginType, function( res ) { + const $addon = $btn.closest( '.addon-item' ); + + if ( res.success ) { + if ( 'install' === state ) { + $btn.attr( 'data-plugin', res.data.basename ); + successText = res.data.msg; + if ( ! res.data.is_activated ) { + stateText = wpforms_admin.addon_inactive; + buttonText = 'plugin' === pluginType ? wpforms_admin.addon_activate : s.iconActivate + wpforms_admin.addon_activate; + cssClass = 'plugin' === pluginType ? 'status-installed button button-secondary' : 'status-installed'; + } + } else { + successText = res.data; + } + $addon.find( '.actions' ).append( '
' + successText + '
' ); + $addon.find( 'span.status-label' ) + .removeClass( 'status-active status-installed status-missing' ) + .addClass( cssClass ) + .removeClass( 'button button-primary button-secondary disabled' ) + .text( stateText ); + $btn + .removeClass( 'status-active status-installed status-missing' ) + .removeClass( 'button button-primary button-secondary disabled' ) + .addClass( cssClass ).html( buttonText ); + } else { + if ( 'object' === typeof res.data ) { + if ( pluginType === 'addon' ) { + $addon.find( '.actions' ).append( '

' + wpforms_admin.addon_error + '

' ); + } else { + $addon.find( '.actions' ).append( '

' + wpforms_admin.plugin_error + '

' ); + } + } else { + $addon.find( '.actions' ).append( '

' + res.data + '

' ); + } + if ( 'install' === state && 'plugin' === pluginType ) { + $btn.addClass( 'status-go-to-url' ).removeClass( 'status-missing' ); + } + $btn.html( errorText ); + } + + $btn.prop( 'disabled', false ).removeClass( 'loading' ); + + if ( ! $addon.find( '.actions' ).find( '.msg.error' ).length ) { + setTimeout( function() { + $( '.addon-item .msg' ).remove(); + }, 3000 ); + } + }, + function( error ) { + // eslint-disable-next-line no-console + console.log( error.responseText ); + } ); + }, + + //--------------------------------------------------------------------// + // Settings. + //--------------------------------------------------------------------// + /** + * Element bindings for Settings page. + * + * @since 1.3.9 + */ + initSettings() { // eslint-disable-line max-lines-per-function + // On ready events. + $( document ).on( 'wpformsReady', function() { // eslint-disable-line max-lines-per-function + // Only proceed if we're on the settings page. + if ( ! $( '#wpforms-settings' ).length ) { + return; + } + + // Watch for hashes and scroll to if found. + // Display all addon boxes as the same height. + const integrationFocus = WPFormsAdmin.getQueryString( 'wpforms-integration' ), + jumpTo = WPFormsAdmin.getQueryString( 'jump' ); + + if ( integrationFocus ) { + $( 'body' ).animate( + { scrollTop: $( '#wpforms-integration-' + integrationFocus ).offset().top }, + 1000 + ); + } else if ( jumpTo ) { + $( 'body' ).animate( + { scrollTop: $( '#' + jumpTo ).offset().top }, + 1000 + ); + } + + // Settings conditional logic. + $( '.wpforms-admin-settings-form' ).conditions( [ + + // Misc > Disable User Cookies visibility. + { + conditions: { + element: '#wpforms-setting-gdpr', + type: 'checked', + operator: 'is', + }, + actions: { + if: { + element: '#wpforms-setting-row-gdpr-disable-uuid,#wpforms-setting-row-gdpr-disable-details', + action: 'show', + }, + else : { + element: '#wpforms-setting-row-gdpr-disable-uuid,#wpforms-setting-row-gdpr-disable-details', + action: 'hide', + }, + }, + effect: 'appear', + }, + + // CAPTCHA > Type. + { + conditions: { + element: 'input[name=captcha-provider]:checked', + type: 'value', + operator: '=', + condition: 'hcaptcha', + }, + actions: { + if: [ + { + element: '.wpforms-setting-row', + action: 'show', + }, + { + element: '.wpforms-setting-recaptcha, #wpforms-setting-row-recaptcha-site-key, #wpforms-setting-row-recaptcha-secret-key, #wpforms-setting-row-recaptcha-fail-msg, .wpforms-setting-turnstile, #wpforms-setting-row-turnstile-heading, #wpforms-setting-row-turnstile-site-key, #wpforms-setting-row-turnstile-secret-key, #wpforms-setting-row-turnstile-theme, #wpforms-setting-row-turnstile-fail-msg', + action: 'hide', + }, + ], + }, + effect: 'appear', + }, + { + conditions: { + element: 'input[name=captcha-provider]:checked', + type: 'value', + operator: '=', + condition: 'recaptcha', + }, + actions: { + if: [ + { + element: '.wpforms-setting-row', + action: 'show', + }, + { + element: '#wpforms-setting-row-hcaptcha-heading, #wpforms-setting-row-hcaptcha-site-key, #wpforms-setting-row-hcaptcha-secret-key, #wpforms-setting-row-hcaptcha-fail-msg, #wpforms-setting-row-turnstile-heading, #wpforms-setting-row-turnstile-site-key, #wpforms-setting-row-turnstile-secret-key, #wpforms-setting-row-turnstile-theme, #wpforms-setting-row-turnstile-fail-msg', + action: 'hide', + }, + ], + }, + effect: 'appear', + }, + { + conditions: { + element: 'input[name=captcha-provider]:checked', + type: 'value', + operator: '=', + condition: 'turnstile', + }, + actions: { + if: [ + { + element: '.wpforms-setting-row', + action: 'show', + }, + { + element: '#wpforms-setting-row-hcaptcha-heading, #wpforms-setting-row-hcaptcha-site-key, #wpforms-setting-row-hcaptcha-secret-key, #wpforms-setting-row-hcaptcha-fail-msg, .wpforms-setting-recaptcha, #wpforms-setting-row-recaptcha-site-key, #wpforms-setting-row-recaptcha-secret-key, #wpforms-setting-row-recaptcha-fail-msg', + action: 'hide', + }, + ], + }, + effect: 'appear', + }, + { + conditions: { + element: 'input[name=captcha-provider]:checked', + type: 'value', + operator: '=', + condition: 'none', + }, + actions: { + if: [ + { + element: '.wpforms-setting-row', + action: 'hide', + }, + { + element: '.wpforms-setting-captcha-heading, #wpforms-setting-row-captcha-provider', + action: 'show', + }, + ], + }, + effect: 'appear', + }, + ] ); + } ); + + // Render engine setting. + $( document ).on( 'change', '#wpforms-setting-row-render-engine input', WPFormsAdmin.settingsRenderEngineChange ); + + // Form styles plugin setting. + $( document ).on( 'change', '#wpforms-setting-disable-css', function() { + WPFormsAdmin.settingsFormStylesAlert( $( this ).val() ); + } ); + + // Image upload fields. + $( document ).on( 'click', '.wpforms-setting-row-image button', function( event ) { + event.preventDefault(); + + // If the remove button was clicked, clear the value and remove the image. + if ( $( this ).hasClass( 'wpforms-setting-remove-image' ) ) { + const $wrapper = $( this ).closest( '.wpforms-setting-row-image' ); + $wrapper.find( 'input' ).val( '' ).attr( 'value', '' ).trigger( 'change' ).end().find( 'img' ).remove(); + + return; + } + + WPFormsAdmin.imageUploadModal( $( this ) ); + } ); + + // Verify license key. + $( document ).on( 'click', '#wpforms-setting-license-key-verify', function( event ) { + event.preventDefault(); + + WPFormsAdmin.licenseVerify( $( this ) ); + } ); + + // Show a message for license field. + $( document ).on( 'click', '.wpforms-setting-license-wrapper', function( event ) { + event.preventDefault(); + + const $keyField = $( '#wpforms-setting-license-key' ); + + if ( ! $keyField.length ) { + return; + } + + if ( ! $keyField.prop( 'disabled' ) ) { + return; + } + + WPFormsAdmin.licenseEditMessage(); + } ); + + // Deactivate a license key. + $( document ).on( 'click', '#wpforms-setting-license-key-deactivate', function( event ) { + event.preventDefault(); + + WPFormsAdmin.licenseDeactivate( $( this ) ); + } ); + + // Refresh license key. + $( document ).on( 'click', '#wpforms-setting-license-key-refresh', function( event ) { + event.preventDefault(); + + WPFormsAdmin.licenseRefresh( $( this ) ); + } ); + + /** + * @todo Refactor providers settings tab. Code below is legacy. + */ + + // Integration connect. + $( document ).on( 'click', '.wpforms-settings-provider-connect', function( event ) { + event.preventDefault(); + + const button = $( this ); + + WPFormsAdmin.integrationConnect( button ); + } ); + + // Integration account disconnect. + $( document ).on( 'click', '.wpforms-settings-provider-accounts-list .remove a', function( event ) { + event.preventDefault(); + + WPFormsAdmin.integrationDisconnect( $( this ) ); + } ); + + // Integration individual display toggling. + $( document ).on( 'click', '.wpforms-settings-provider:not(.focus-out) .wpforms-settings-provider-header', function( event ) { + event.preventDefault(); + + const $this = $( this ); + + $this + .parent() + .find( '.wpforms-settings-provider-accounts' ) + .stop( false, true ) + .slideToggle( '', function() { + $this.parent().find( '.wpforms-settings-provider-logo i' ).toggleClass( 'fa-chevron-right fa-chevron-down' ); + } ); + } ); + + // Integration accounts display toggling. + $( document ).on( 'click', '.wpforms-settings-provider-accounts-toggle a', function( event ) { + event.preventDefault(); + + const $connectFields = $( this ).parent().next( '.wpforms-settings-provider-accounts-connect' ); + $connectFields.find( 'input[type=text], input[type=password]' ).val( '' ); + $connectFields.stop().slideToggle(); + } ); + + // CAPTCHA settings page: type toggling. + $( document ).on( 'change', '#wpforms-setting-row-captcha-provider input', function() { + const $preview = $( '#wpforms-setting-row-captcha-preview' ); + + if ( this.value === 'hcaptcha' || this.value === 'turnstile' ) { + $preview.removeClass( 'wpforms-hidden' ); + } else if ( this.value === 'none' ) { + $preview.addClass( 'wpforms-hidden' ); + } else { + $( '#wpforms-setting-row-recaptcha-type input:checked' ).trigger( 'change' ); + } + + if ( $preview.find( '.wpforms-captcha-preview' ).length ) { + $preview.find( '.wpforms-captcha-preview' ).empty(); + $preview.find( '.wpforms-captcha-placeholder' ).removeClass( 'wpforms-hidden' ); + } + } ); + + // CAPTCHA settings page: reCAPTCHA type toggling. + $( document ).on( 'change', '#wpforms-setting-row-recaptcha-type input', function() { + $( '#wpforms-setting-row-captcha-preview' ).toggleClass( 'wpforms-hidden', 'v2' !== this.value ); + $( '#wpforms-setting-row-recaptcha-v3-threshold' ).toggleClass( 'wpforms-hidden', 'v3' !== this.value ); + } ); + + // Toggle control switch description. + $( document ).on( 'change', '.wpforms-toggle-control input', function() { + const $input = $( this ), + checked = $input.is( ':checked' ), + state = checked ? 'on' : 'off', + $field = $input.closest( '.wpforms-setting-field' ), + $control = $input.closest( '.wpforms-toggle-control' ), + $status = $control.find( '.wpforms-toggle-control-status' ), + $descOn = $field.find( '.wpforms-toggle-desc.desc-on' ), + $descOff = $field.find( '.wpforms-toggle-desc.desc-off' ), + isDoubleDesc = $descOn.length > 0 && $descOff.length > 0; + + $descOn.toggleClass( 'wpforms-hidden', ! checked && isDoubleDesc ); + $descOff.toggleClass( 'wpforms-hidden', checked && isDoubleDesc ); + $status.html( $status.data( state ) ); + } ); + }, + + /** + * Render engine setting change event handler. + * + * @since 1.8.1 + */ + settingsRenderEngineChange() { + // noinspection JSUnusedLocalSymbols + const renderEngine = $( this ).val(); // eslint-disable-line + + // TODO: Add corresponding code that need to be executed on change render engine setting. + }, + + /** + * Alert users if they change form styles to something that may give unexpected results. + * + * @since 1.5.0 + * + * @param {string} value Form Styles value. + */ + settingsFormStylesAlert( value ) { + let msg; + + if ( '2' === value ) { + msg = wpforms_admin.settings_form_style_base; + } else if ( '3' === value ) { + msg = wpforms_admin.settings_form_style_none; + } else { + return; + } + + $.alert( { + title: wpforms_admin.heads_up, + content: msg, + icon: 'fa fa-exclamation-circle', + type: 'orange', + buttons: { + confirm: { + text: wpforms_admin.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + }, + }, + } ); + }, + + /** + * Image upload modal window. + * + * @since 1.3.0 + * + * @param {jQuery} $el Image upload button element. + */ + imageUploadModal( $el ) { + // To prevent caching of the media frame object and + // avoid confusion between multiple instances, + // this method no longer relies on the shared s.mediaFrame object. + // Instead, it creates a new mediaFrame object for each instance. + + const $setting = $el.closest( '.wpforms-setting-field' ); + + s.mediaFrame = wpf.initMediaLibrary( { + title: wpforms_admin.upload_image_title, + extensions: wpforms_admin.upload_image_extensions, + extensionsError: wpforms_admin.upload_image_extensions_error, + buttonText: wpforms_admin.upload_image_button, + } ); + + s.mediaFrame.on( 'select', function() { + // Grab our attachment selection and construct a JSON representation of the model. + const mediaAttachment = s.mediaFrame.state().get( 'selection' ).first().toJSON(); + const $input = $setting.find( 'input[type=text]' ); + + // Send the attachment URL to our custom input field via jQuery. + $input.val( mediaAttachment.url ); + $setting.find( 'img' ).remove(); + $setting.prepend( '' ); + $input.trigger( 'change' ); + } ).on( 'close', function() { + s.mediaFrame.off( 'library:selection:add' ); + } ); + + // Now that everything has been set, let's open up the frame. + s.mediaFrame.open(); + }, + + /** + * Verify a license key. + * + * @since 1.3.9 + * + * @param {jQuery} $el Verify button element. + */ + licenseVerify( $el ) { // eslint-disable-line max-lines-per-function + const $row = $el.closest( '.wpforms-setting-row' ), + $keyField = $( '#wpforms-setting-license-key' ), + buttonWidth = $el.outerWidth(), + buttonLabel = $el.text(), + data = { + action: 'wpforms_verify_license', + nonce: wpforms_admin.nonce, + license: $keyField.val(), + }; + + $el.html( s.iconSpinner ).css( 'width', buttonWidth ).prop( 'disabled', true ); + + $.post( wpforms_admin.ajax_url, data, function( res ) { + let icon = 'fa fa-check-circle', + color = 'green', + msg; + + if ( res.success ) { + msg = res.data.msg; + $el.hide(); + $row.find( '#wpforms-setting-license-key-info-message' ).empty().hide(); + $row.find( '.type, .desc, #wpforms-setting-license-key-deactivate' ).show(); + $row.find( '.type strong' ).text( res.data.type ); + $( '.wpforms-license-notice' ).remove(); + $keyField + .prop( 'disabled', true ) + .addClass( 'wpforms-setting-license-is-valid' ) + .attr( 'value', $keyField.val().replace( /./g, '*' ) ); + } else { + icon = 'fa fa-exclamation-circle'; + color = 'orange'; + msg = res.data; + $row.find( '.type, .desc, #wpforms-setting-license-key-deactivate' ).hide(); + $keyField.prop( 'disabled', false ); + } + + $.alert( { + title: msg.header ?? false, + content: msg.msg ?? msg, + icon, + type: color, + buttons: { + confirm: { + text: wpforms_admin.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + }, + }, + } ); + + $el.html( buttonLabel ).css( 'width', 'auto' ).prop( 'disabled', false ); + } ).fail( function( xhr ) { + $keyField.prop( 'disabled', false ); + + // eslint-disable-next-line no-console + console.log( xhr.responseText ); + } ); + }, + + /** + * Show a message that license key editing is disabled. + * + * @since 1.6.5 + */ + licenseEditMessage() { + $.alert( { + title: wpforms_admin.heads_up, + content: wpforms_admin.edit_license, + icon: 'fa fa-exclamation-circle', + type: 'orange', + buttons: { + confirm: { + text: wpforms_admin.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + }, + }, + } ); + }, + + /** + * Deactivate a license key. + * + * @since 1.3.9 + * + * @param {Element} el Button element. + */ + licenseDeactivate( el ) { + const $this = $( el ); + const $row = $this.closest( '.wpforms-setting-row' ); + + const buttonWidth = $this.outerWidth(); + const buttonLabel = $this.text(); + + const data = { + action: 'wpforms_deactivate_license', + nonce: wpforms_admin.nonce, + }; + + $this.html( s.iconSpinner ).css( 'width', buttonWidth ).prop( 'disabled', true ); + + $.post( wpforms_admin.ajax_url, data, function( res ) { + let icon = 'fa fa-info-circle'; + let color = 'blue'; + let title = wpforms_admin.success; + + const resData = res.data; + const msg = ! resData.msg || typeof resData.msg !== 'string' ? wpforms_admin.something_went_wrong : resData.msg; + + if ( res.success ) { + $row.find( '#wpforms-setting-license-key' ) + .val( '' ) + .attr( 'value', '' ) + .prop( { readonly: false, disabled: false } ) + .removeClass(); + $row.find( '.wpforms-license-key-deactivate-remove' ).remove(); + $row.find( '#wpforms-setting-license-key-info-message' ).html( resData.info ).show(); + $row.find( '#wpforms-setting-license-key-verify' ).prop( 'disabled', false ).show(); + $row.find( '.type, .desc, #wpforms-setting-license-key-deactivate' ).hide(); + } else { + icon = 'fa fa-exclamation-circle'; + color = 'orange'; + title = wpforms_admin.oops; + } + + $.alert( { + title, + content: msg, + icon, + type: color, + buttons: { + confirm: { + text: wpforms_admin.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + }, + }, + } ); + + $this.html( buttonLabel ).css( 'width', 'auto' ).prop( 'disabled', false ); + } ).fail( function( xhr ) { + // eslint-disable-next-line no-console + console.log( xhr.responseText ); + } ); + }, + + /** + * Refresh a license key. + * + * @since 1.3.9 + * + * @param {jQuery} el Element. + */ + licenseRefresh( el ) { + const $this = $( el ), + $row = $this.closest( '.wpforms-setting-row' ), + $input = $( '#wpforms-setting-license-key' ), + data = { + action: 'wpforms_refresh_license', + nonce: wpforms_admin.nonce, + }; + + $.post( wpforms_admin.ajax_url, data, function( res ) { + let icon = 'fa fa-check-circle', + color = 'green', + msg; + + if ( res.success ) { + msg = res.data.msg; + $row.find( '.type strong' ).text( res.data.type ); + } else { + icon = 'fa fa-exclamation-circle'; + color = 'orange'; + msg = res.data; + $row.find( '.type, .desc' ).hide(); + $input.removeClass( 'wpforms-setting-license-is-valid' ).addClass( 'wpforms-setting-license-is-invalid' ); + } + + $.alert( { + title: msg.header ?? false, + content: msg.msg ?? msg, + icon, + type: color, + buttons: { + confirm: { + text: wpforms_admin.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + }, + }, + } ); + } ).fail( function( xhr ) { + // eslint-disable-next-line no-console + console.log( xhr.responseText ); + } ); + }, + + /** + * Connect integration provider account. + * + * @since 1.3.9 + * + * @param {jQuery} $btn Button (.wpforms-settings-provider-connect) that was clicked to establish connection. + */ + integrationConnect( $btn ) { + const buttonWidth = $btn.outerWidth(), + buttonLabel = $btn.text(), + $provider = $btn.closest( '.wpforms-settings-provider' ), + data = { + action : 'wpforms_settings_provider_add_' + $btn.data( 'provider' ), + data : $btn.closest( 'form' ).serialize(), + provider: $btn.data( 'provider' ), + nonce : wpforms_admin.nonce, + }; + let errorMessage = wpforms_admin.provider_auth_error; + + $btn.html( wpforms_admin.connecting ).css( 'width', buttonWidth ).prop( 'disabled', true ); + + $.post( wpforms_admin.ajax_url, data, function( response ) { + if ( response.success ) { + $provider.find( '.wpforms-settings-provider-accounts-list ul' ).append( response.data.html ); + $provider.addClass( 'connected' ); + $btn.closest( '.wpforms-settings-provider-accounts-connect' ).stop().slideToggle(); + } else { + if ( + Object.prototype.hasOwnProperty.call( response, 'data' ) && + Object.prototype.hasOwnProperty.call( response.data, 'error_msg' ) + ) { + errorMessage += '
' + response.data.error_msg; + } + + WPFormsAdmin.integrationError( errorMessage ); + } + } ).fail( function() { + WPFormsAdmin.integrationError( errorMessage ); + } ).always( function() { + $btn.html( buttonLabel ).css( 'width', 'auto' ).prop( 'disabled', false ); + } ); + }, + + /** + * Remove an integration provider account. + * + * @since 1.3.9 + * + * @param {Object} el Disconnect link that was clicked to establish removing account. + */ + integrationDisconnect( el ) { + const $this = $( el ), + $provider = $this.parents( '.wpforms-settings-provider' ), + data = { + action : 'wpforms_settings_provider_disconnect_' + $this.data( 'provider' ), + provider: $this.data( 'provider' ), + key : $this.data( 'key' ), + nonce : wpforms_admin.nonce, + }; + let errorMessage = wpforms_admin.provider_delete_error; + + $.confirm( { + title: wpforms_admin.heads_up, + content: wpforms_admin.provider_delete_confirm, + icon: 'fa fa-exclamation-circle', + type: 'orange', + buttons: { + confirm: { + text: wpforms_admin.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + action() { + $.post( wpforms_admin.ajax_url, data, function( response ) { + if ( response.success ) { + $this.parent().parent().remove(); + + // Hide the Connected status label if no more integrations are linked. + const numberOfIntegrations = $provider.find( '.wpforms-settings-provider-accounts-list li' ).length; + + if ( typeof numberOfIntegrations === 'undefined' || numberOfIntegrations === 0 ) { + $provider.removeClass( 'connected' ); + } + + /** + * Provider account has been removed. + * + * @since 1.7.7 + */ + $( document ).trigger( 'wpformsProviderRemoved', [ $provider, response ] ); + } else { + if ( + Object.prototype.hasOwnProperty.call( response, 'data' ) && + Object.prototype.hasOwnProperty.call( response.data, 'error_msg' ) + ) { + errorMessage += '
' + response.data.error_msg; + } + + WPFormsAdmin.integrationError( errorMessage ); + } + } ).fail( function() { + WPFormsAdmin.integrationError( errorMessage ); + } ); + }, + }, + cancel: { + text: wpforms_admin.cancel, + keys: [ 'esc' ], + }, + }, + } ); + }, + + /** + * Error handling. + * + * @since 1.6.4 + * + * @param {string} error Error message. + */ + integrationError( error ) { + $.alert( { + title: wpforms_admin.something_went_wrong, + content: error, + icon: 'fa fa-exclamation-circle', + type: 'orange', + buttons: { + confirm: { + text: wpforms_admin.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + }, + }, + } ); + }, + + //--------------------------------------------------------------------// + // Tools. + //--------------------------------------------------------------------// + + /** + * Element bindings for Tools page. + * + * @since 1.4.2 + */ + initTools() { // eslint-disable-line max-lines-per-function + // Enable import/export buttons when a value is selected. + $( document ).on( 'change', '#wpforms-tools-form-import, #wpforms-tools-form-other-import, #wpforms-tools-form-export, #wpforms-tools-form-template', function() { + const $field = $( this ); + const $button = $field.parents( 'form' ).find( 'button' ); + + $button.attr( 'aria-disabled', $field.val().length === 0 ); + } ); + + // Copy system information to the clipboard. + $( document ).on( 'click', '#wpforms-system-information-copy', function( event ) { + event.preventDefault(); + WPFormsAdmin.copySystemInformation(); + } ); + + // Run SSL test. + $( document ).on( 'click', '#wpforms-ssl-verify', function( event ) { + event.preventDefault(); + WPFormsAdmin.verifySSLConnection(); + } ); + + // Recreate database tables. + $( document ).on( 'click', '#wpforms-recreate-tables', function( event ) { + event.preventDefault(); + WPFormsAdmin.recreateTables(); + } ); + + // Run import for a specific provider. + $( document ).on( 'click', '#wpforms-importer-forms-submit', function( event ) { + event.preventDefault(); + + // Check to confirm the user as selected a form. + const $checked = $( '#wpforms-importer-forms input:checked' ); + + if ( $checked.length ) { + const ids = []; + + $checked.each( function( i ) { + ids[ i ] = $( this ).val(); + } ); + + if ( ! wpforms_admin.isPro ) { + // We need to analyze the forms before starting the actual import. + WPFormsAdmin.analyzeForms( ids ); + } else { + // Begin the import process. + WPFormsAdmin.importForms( ids ); + } + } else { + // User didn't select a form so alert them. + $.alert( { + title: wpforms_admin.heads_up, + content: wpforms_admin.importer_forms_required, + icon: 'fa fa-info-circle', + type: 'blue', + buttons: { + confirm: { + text: wpforms_admin.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + }, + }, + } ); + } + } ); + + // Continue import after analyzing. + $( document ).on( 'click', '#wpforms-importer-continue-submit', function( event ) { + event.preventDefault(); + WPFormsAdmin.importForms( s.formIDs ); + } ); + }, + + /** + * Copy system information to the clipboard. + * + * @since 1.8.4 + */ + copySystemInformation() { + $( '#wpforms-system-information' ).select(); + document.execCommand( 'copy' ); + }, + + /** + * Perform a test connection to verify that the current web host + * can successfully make outbound SSL connections. + * + * @since 1.4.5 + */ + verifySSLConnection() { + const $btn = $( '#wpforms-ssl-verify' ); + const btnLabel = $btn.text(); + const btnWidth = $btn.outerWidth(); + const $settings = $btn.parent(); + + $btn.css( 'width', btnWidth ).prop( 'disabled', true ).text( wpforms_admin.testing ); + + const data = { + action: 'wpforms_verify_ssl', + nonce: wpforms_admin.nonce, + }; + + // Trigger AJAX to test connection + $.post( wpforms_admin.ajax_url, data, function( res ) { + WPFormsAdmin.debug( res ); + + // Remove any previous alerts. + $settings.find( '.wpforms-notice' ).remove(); + + if ( res.success ) { + $btn.before( '
' + res.data.msg + '
' ); + } + + if ( ! res.success && res.data.msg ) { + $btn.before( '
' + res.data.msg + '
' ); + } + + if ( ! res.success && res.data.debug ) { + $btn.before( '
' + res.data.debug + '
' ); + } + + $btn.css( 'width', btnWidth ).prop( 'disabled', false ).text( btnLabel ); + } ); + }, + + /** + * Recreate custom tables. + * + * @since 1.9.0 + */ + recreateTables() { + const $btn = $( '#wpforms-recreate-tables' ); + const btnLabel = $btn.text(); + const btnWidth = $btn.outerWidth(); + const $settings = $btn.parent(); + + $btn.css( 'width', btnWidth ).prop( 'disabled', true ).text( wpforms_admin.recreating ); + + const data = { + action: 'wpforms_recreate_tables', + nonce: wpforms_admin.nonce, + }; + + // Trigger AJAX to recreate tables. + $.post( wpforms_admin.ajax_url, data, function( res ) { + WPFormsAdmin.debug( res ); + + // Remove any previous alerts. + $settings.find( '.wpforms-notice' ).remove(); + + if ( res.success ) { + $btn.before( '
' + res.data.msg + '
' ); + $btn.hide(); + } + + if ( ! res.success && res.data.msg ) { + $btn.before( '
' + res.data.msg + '
' ); + } + + if ( ! res.success && res.data.debug ) { + $btn.before( '
' + res.data.debug + '
' ); + } + } ).always( function() { + $btn.css( 'width', btnWidth ).prop( 'disabled', false ).text( btnLabel ); + } ); + }, + + /** + * Begins the process of analyzing the forms. + * + * This runs for non-Pro installs to check if any of the forms to be imported + * contain fields not currently available. + * + * @since 1.4.2 + * + * @param {Array} forms Forms. + */ + analyzeForms( forms ) { + const $processAnalyze = $( '#wpforms-importer-analyze' ); + + // Display the total number of forms we have to import. + $processAnalyze.find( '.form-total' ).text( forms.length ); + $processAnalyze.find( '.form-current' ).text( '1' ); + + // Hide the form select section. + $( '#wpforms-importer-forms' ).hide(); + + // Show Analyze status. + $processAnalyze.show(); + + // Create global analyze queue. + s.analyzeQueue = forms; + s.analyzed = 0; + s.analyzeUpgrade = []; + s.formIDs = forms; + + // Analyze the first form in the queue. + WPFormsAdmin.analyzeForm(); + }, + + /** + * Analyze a single form from the queue. + * + * @since 1.4.2 + */ + analyzeForm() { + const $analyzeSettings = $( '#wpforms-importer-analyze' ), + formID = _.first( s.analyzeQueue ), + provider = WPFormsAdmin.getQueryString( 'provider' ), + data = { + action: 'wpforms_import_form_' + provider, + analyze: 1, + form_id: formID, + nonce: wpforms_admin.nonce, + }; + + // Trigger AJAX analyze for this form. + $.post( wpforms_admin.ajax_url, data, function( res ) { + if ( res.success ) { + if ( ! _.isEmpty( res.data.upgrade_plain ) || ! _.isEmpty( res.data.upgrade_omit ) ) { + s.analyzeUpgrade.push( { + name: res.data.name, + fields: _.union( res.data.upgrade_omit, res.data.upgrade_plain ), + } ); + } + + // Remove this form ID from the queue. + s.analyzeQueue = _.without( s.analyzeQueue, formID ); + s.analyzed++; + + if ( _.isEmpty( s.analyzeQueue ) ) { + if ( _.isEmpty( s.analyzeUpgrade ) ) { + // Continue to import forms as no Pro fields were found. + WPFormsAdmin.importForms( s.formIDs ); + } else { + // We found Pro fields, so alert the user. + const upgradeDetails = wp.template( 'wpforms-importer-upgrade' ); + $analyzeSettings.find( '.upgrade' ).append( upgradeDetails( s.analyzeUpgrade ) ); + $analyzeSettings.find( '.upgrade' ).show(); + $analyzeSettings.find( '.process-analyze' ).hide(); + } + } else { + // Analyze the next form in the queue. + $analyzeSettings.find( '.form-current' ).text( s.analyzed + 1 ); + WPFormsAdmin.analyzeForm(); + } + } + } ); + }, + + /** + * Begins the process of importing the forms. + * + * @since 1.4.2 + * + * @param {Array} forms Forms. + */ + importForms( forms ) { + const $processSettings = $( '#wpforms-importer-process' ); + + // Display the total number of forms we have to import. + $processSettings.find( '.form-total' ).text( forms.length ); + $processSettings.find( '.form-current' ).text( '1' ); + + // Hide the form select and form analyze sections. + $( '#wpforms-importer-forms, #wpforms-importer-analyze' ).hide(); + + // Show processing status. + $processSettings.show(); + + // Create global import queue. + s.importQueue = forms; + s.imported = 0; + + // Import the first form in the queue. + WPFormsAdmin.importForm(); + }, + + /** + * Imports a single form from the import queue. + * + * @since 1.4.2 + */ + importForm() { + const $processSettings = $( '#wpforms-importer-process' ), + formID = _.first( s.importQueue ), + provider = WPFormsAdmin.getQueryString( 'provider' ), + data = { + action: 'wpforms_import_form_' + provider, + form_id: formID, + nonce: wpforms_admin.nonce, + }; + + // Trigger AJAX import for this form. + $.post( wpforms_admin.ajax_url, data, function( res ) { + if ( res.success ) { + let statusUpdate; + + if ( res.data.error ) { + statusUpdate = wp.template( 'wpforms-importer-status-error' ); + } else { + statusUpdate = wp.template( 'wpforms-importer-status-update' ); + } + + $processSettings.find( '.status' ).prepend( statusUpdate( res.data ) ); + $processSettings.find( '.status' ).show(); + + // Remove this form ID from the queue. + s.importQueue = _.without( s.importQueue, formID ); + s.imported++; + + if ( _.isEmpty( s.importQueue ) ) { + $processSettings.find( '.process-count' ).hide(); + $processSettings.find( '.forms-completed' ).text( s.imported ); + $processSettings.find( '.process-completed' ).show(); + } else { + // Import the next form in the queue. + $processSettings.find( '.form-current' ).text( s.imported + 1 ); + WPFormsAdmin.importForm(); + } + } + } ); + }, + + //--------------------------------------------------------------------// + // Upgrades (Tabs view). + //--------------------------------------------------------------------// + + /** + * Element bindings for Tools page. + * + * @since 1.4.3 + */ + initUpgrades() { + // Prepare to run the v1.4.3 upgrade routine. + $( document ).on( 'click', '#wpforms-upgrade-143 button', function( event ) { + event.preventDefault(); + + const $this = $( this ), + buttonWidth = $this.outerWidth(), + $status = $( '#wpforms-upgrade-143 .status' ), + data = { + action: 'wpforms_upgrade_143', + nonce: wpforms_admin.nonce, + init: true, + incomplete: $this.data( 'incomplete' ), + }; + + // Change the button to indicate we are doing initial processing. + $this.html( s.iconSpinner ).css( 'width', buttonWidth ).prop( 'disabled', true ); + + // Get the total number of entries, then kick off the routine. + $.post( wpforms_admin.ajax_url, data, function( res ) { + if ( res.success ) { + // Set initial values. + s.upgraded = Number( res.data.upgraded ); + s.upgradeTotal = Number( res.data.total ); + const percent = Math.round( ( Number( s.upgraded ) / Number( s.upgradeTotal ) ) * 100 ); + + // Show the status area. + $this.remove(); + $status.find( '.bar' ).css( 'width', percent + '%' ); + $status.show().find( '.total' ).text( s.upgradeTotal ); + $status.find( '.current' ).text( s.upgraded ); + $status.find( '.percent' ).text( percent + '%' ); + + // Begin the actual upgrade routine. + WPFormsAdmin.upgrade143(); + } + } ); + } ); + }, + + /** + * The v1.4.3 entry fields upgrade routine. + * + * @since 1.4.3 + */ + upgrade143() { + const $status = $( '#wpforms-upgrade-143 .status' ), + data = { + action: 'wpforms_upgrade_143', + nonce: wpforms_admin.nonce, + upgraded: s.upgraded, + }; + + // Get the total number of entries, then kick off the routine. + $.post( wpforms_admin.ajax_url, data, function( res ) { + if ( res.success ) { + s.upgraded = Number( s.upgraded ) + Number( res.data.count ); + const percent = Math.round( ( Number( s.upgraded ) / Number( s.upgradeTotal ) ) * 100 ); + + // Update progress bar. + $status.find( '.bar' ).css( 'width', percent + '%' ); + + if ( Number( res.data.count ) < 10 ) { + // This batch completed the upgrade routine. + $status.find( '.progress-bar' ).addClass( 'complete' ); + $status.find( '.msg' ).text( wpforms_admin.upgrade_completed ); + } else { + $status.find( '.current' ).text( s.upgraded ); + $status.find( '.percent' ).text( percent + '%' ); + + // Batch the next round of entries. + WPFormsAdmin.upgrade143(); + } + } + } ); + }, + + /** + * Element bindings for Flyout Menu. + * + * @since 1.5.7 + */ + initFlyoutMenu() { + // Flyout Menu Elements. + const $flyoutMenu = $( '#wpforms-flyout' ); + + if ( $flyoutMenu.length === 0 ) { + return; + } + + const $head = $flyoutMenu.find( '.wpforms-flyout-head' ), + $sullie = $head.find( 'img' ), + menu = { + state: 'inactive', + srcInactive: $sullie.attr( 'src' ), + srcActive: $sullie.data( 'active' ), + }; + + // Click on the menu head icon. + $head.on( 'click', function( e ) { + e.preventDefault(); + + if ( menu.state === 'active' ) { + $flyoutMenu.removeClass( 'opened' ); + $sullie.attr( 'src', menu.srcInactive ); + menu.state = 'inactive'; + } else { + $flyoutMenu.addClass( 'opened' ); + $sullie.attr( 'src', menu.srcActive ); + menu.state = 'active'; + } + } ); + + // Page elements and other values. + const $wpfooter = $( '#wpfooter' ); + + if ( $wpfooter.length === 0 ) { + return; + } + + const $overlap = $( + '#wpforms-overview, ' + + '#wpforms-entries-list, ' + + '#wpforms-tools.wpforms-tools-tab-action-scheduler, ' + + '#wpforms-tools.wpforms-tools-tab-logs' + ); + + // Hide the menu if scrolled down to the bottom of the page. + $( window ).on( 'resize scroll', _.debounce( function() { + const wpfooterTop = $wpfooter.offset().top, + wpfooterBottom = wpfooterTop + $wpfooter.height(), + overlapBottom = $overlap.length > 0 ? $overlap.offset().top + $overlap.height() + 85 : 0, + viewTop = $( window ).scrollTop(), + viewBottom = viewTop + $( window ).height(); + + if ( wpfooterBottom <= viewBottom && wpfooterTop >= viewTop && overlapBottom > viewBottom ) { + $flyoutMenu.addClass( 'out' ); + } else { + $flyoutMenu.removeClass( 'out' ); + } + }, 50 ) ); + + $( window ).trigger( 'scroll' ); + }, + + /** + * Lity improvements. + * + * @since 1.5.8 + */ + initLity() { + // Use `data-lity-srcset` opener's attribute for add srcset to full image in opened lightbox. + $( document ).on( 'lity:ready', function( event, instance ) { + const $el = instance.element(), + $opener = instance.opener(), + srcset = typeof $opener !== 'undefined' ? $opener.data( 'lity-srcset' ) : ''; + + if ( typeof srcset !== 'undefined' && srcset !== '' ) { + $el.find( '.lity-content img' ).attr( 'srcset', srcset ); + } + } ); + }, + + //--------------------------------------------------------------------// + // Helper functions. + //--------------------------------------------------------------------// + + /** + * Return if the target nodeName is a form element. + * + * @since 1.4.0 + * + * @param {string} name Node name. + * @return {boolean} Target node is a form element. + */ + isFormTypeNode( name ) { + name = name || false; + + return 'TEXTAREA' === name || 'INPUT' === name || 'SELECT' === name; + }, + + /** + * Get a query string in a URL. + * + * @since 1.3.9 + * + * @param {string} name Query string to find in a URL. + * @return {string|null} Query string or null. + */ + getQueryString( name ) { + const match = new RegExp( '[?&]' + name + '=([^&]*)' ).exec( window.location.search ); + + return match && decodeURIComponent( match[ 1 ].replace( /\+/g, ' ' ) ); + }, + + /** + * Debug output helper. + * + * @param {string} msg Message. + * + * @since 1.4.4 + */ + debug( msg ) { + if ( WPFormsAdmin.isDebug() ) { + if ( typeof msg === 'object' || msg.constructor === Array ) { + console.log( 'WPForms Debug:' ); // eslint-disable-line no-console + console.log( msg ); // eslint-disable-line no-console + } else { + console.log( 'WPForms Debug: ' + msg ); // eslint-disable-line no-console + } + } + }, + + /** + * Is debug mode. + * + * @since 1.4.4 + * + * @return {boolean} Debug mode. + */ + isDebug() { + return ( window.location.hash && '#wpformsdebug' === window.location.hash ); + }, + + /** + * Get Delete / Trash all notice message. + * + * @since 1.8.5 + * + * @param {string} type Type of screen. + * + * @return {Object} The `Notice Data` object. + */ + getDeleteAllNoticeData: ( type = '' ) => { + // Define delete data for spam or trash. + if ( [ 'spam', 'trash' ].includes( type ) ) { + return { + contentAll : wpforms_admin.entry_delete_all_confirm, + content : wpforms_admin.entry_delete_n_confirm, + action : 'delete', + }; + } + + // Otherwise define trash data. + return { + contentAll : wpforms_admin.entry_trash_all_confirm, + content : wpforms_admin.entry_trash_n_confirm, + action : 'trash', + }; + }, + + /** + * Show/hide the right arrow for the scrollable menu on mobile devices. + * + * @since 1.8.8 + */ + initScrollableMenu() { + $( document ).on( 'wpformsReady', function() { + const $menu = $( '.wpforms-admin-tabs' ); + + if ( ! $menu.length ) { + return; + } + + const $lastMenuItem = $menu.find( 'li:last-child' ); + + // The last item of the menu is not visible - show the right arrow as an indicator of a scrollable menu. + if ( ! wpf.isInViewport( $lastMenuItem ) ) { + $menu.addClass( 'wpforms-admin-tabs--scrollable' ); + } + + // Listen to the ` scroll ` event to hide the right arrow when the last item is visible. + $menu.on( 'scroll', function() { + $menu.toggleClass( 'wpforms-admin-tabs--scrollable', ! wpf.isInViewport( $lastMenuItem ) ); + } ); + } ); + }, + }; + + WPFormsAdmin.init(); + + window.WPFormsAdmin = WPFormsAdmin; +}( jQuery ) ); diff --git a/wp-content/plugins/wpforms-lite/assets/js/admin/admin.min.js b/wp-content/plugins/wpforms-lite/assets/js/admin/admin.min.js new file mode 100755 index 00000000..3976e170 --- /dev/null +++ b/wp-content/plugins/wpforms-lite/assets/js/admin/admin.min.js @@ -0,0 +1 @@ +(l=>{let m;var p={settings:{iconActivate:'',iconDeactivate:'',iconInstall:'',iconSpinner:'',mediaFrame:!1},init(){m=this.settings,l(p.ready),p.initEntriesSingle(),p.initEntriesList(),p.initWelcome(),l(document).on("wpformsReady",p.initAddons),p.initSettings(),p.initTools(),p.initUpgrades(),p.initScrollableMenu()},ready(){l.ajaxSetup({data:{_wp_http_referer:wpf.updateQueryString("_wp_http_referer",null)}}),p.scrollToIntegration(),l(".notice").show(),l("#screen-meta-links, #screen-meta").prependTo("#wpforms-header-temp").show(),p.initChoicesJS(),l(document).on("htmx:afterSwap",p.initChoicesJS),p.initCheckboxMultiselectColumns(),l(".wpforms-color-picker").each(function(){var e=l(this);e.minicolors({defaultValue:e.data("fallback-color")||""})}),l(".wpforms-file-upload").each(function(){let e=l(this).find("input[type=file]"),n=l(this).find("label"),o=n.html();e.on("change",function(e){let t="";this.files&&1'+t+"")):(e.parent().removeClass("checked"),n.find("#"+o).remove())}),l(document).on("click",".checkbox-multiselect-columns .all",function(e){e.preventDefault(),l(this).closest(".checkbox-multiselect-columns").find("input[type=checkbox]").prop("checked",!0).trigger("change"),l(this).remove()})},initFormOverview(){console.warn('WARNING! Function "WPFormsAdmin.initFormOverview()" has been deprecated, please use the new "WPFormsForms.Overview.init()" function instead!'),window.WPFormsForms.Overview.init()},initEntriesList(){l(document).on("click","#wpforms-entries-list .form-selector .toggle",function(e){e.preventDefault(),l(this).toggleClass("active").next(".form-list").toggle()}),l(document).on("click","#wpforms-entries-table #doaction",function(e){let t=l(this),n=t.closest("form"),o=n.find("table"),s=n.find("select[name=action]"),i=o.find("input[name^=entry_id]:checked");var a;"delete"!==s.val()&&"trash"!==s.val()||!i.length||(a="delete"===s.val()?wpforms_admin.entry_delete_n_confirm:wpforms_admin.entry_trash_n_confirm,e.preventDefault(),l.confirm({title:wpforms_admin.heads_up,content:a.replace("{entry_count}",i.length),icon:"fa fa-exclamation-circle",type:"orange",buttons:{confirm:{text:wpforms_admin.ok,btnClass:"btn-confirm",keys:["enter"],action(){n.trigger("submit")}},cancel:{text:wpforms_admin.cancel,keys:["esc"]}}}))}),l(document).on("click","#wpforms-entries-list .wp-list-table .delete",function(e){e.preventDefault();let t=l(this).attr("href");l.confirm({title:wpforms_admin.heads_up,content:wpforms_admin.entry_delete_confirm,icon:"fa fa-exclamation-circle",type:"orange",buttons:{confirm:{text:wpforms_admin.ok,btnClass:"btn-confirm",keys:["enter"],action(){window.location=t}},cancel:{text:wpforms_admin.cancel,keys:["esc"]}}})}),l(document).on("click","#wpforms-entries-list .wp-list-table .trash",function(e){e.preventDefault();let t=l(this).attr("href");l.confirm({title:wpforms_admin.heads_up,content:wpforms_admin.entry_trash_confirm,icon:"fa fa-exclamation-circle",type:"orange",buttons:{confirm:{text:wpforms_admin.ok,btnClass:"btn-confirm",keys:["enter"],action:()=>{window.location=t}},cancel:{text:wpforms_admin.cancel,keys:["esc"]}}})}),l(document).on("click","#wpforms-entries-list .wp-list-table .indicator-star",function(e){e.preventDefault();var e=l(this),t=l("#wpforms-entries-list .starred-num"),n=e.parents("table");let o,s=Number(t.text());e.hasClass("star")?(o="star",s++,e.attr("title",wpforms_admin.entry_unstar)):(o="unstar",s--,e.attr("title",wpforms_admin.entry_star)),e.toggleClass("star unstar"),n.hasClass("wpforms-entries-table-spam")||n.hasClass("wpforms-entries-table-trash")||t.text(s);n={task:o,action:"wpforms_entry_list_star",nonce:wpforms_admin.nonce,entryId:e.data("id"),formId:e.data("form-id")};l.post(wpforms_admin.ajax_url,n)}),l(document).on("click","#wpforms-entries-list .wp-list-table .indicator-read",function(e){e.preventDefault();var e=l(this),t=l("#wpforms-entries-list .unread-num"),n=e.parents("table");let o,s=Number(t.text());e.hasClass("read")?(o="read",s--,e.attr("title",wpforms_admin.entry_unread)):(o="unread",s++,e.attr("title",wpforms_admin.entry_read)),e.toggleClass("read unread"),n.hasClass("wpforms-entries-table-spam")||n.hasClass("wpforms-entries-table-trash")||t.text(s);n={task:o,action:"wpforms_entry_list_read",nonce:wpforms_admin.nonce,entryId:e.data("id"),formId:e.data("form-id")};l.post(wpforms_admin.ajax_url,n)}),l(document).on("click","#wpforms-entries-list .form-details-actions-removeall",function(e){e.preventDefault();let t=l(this).data("page"),n=p.getDeleteAllNoticeData(t),o=l(this).attr("href"),s=l("#wpforms-entries-table"),i=s.data("filtered-count-trash")&&"trash"===n.action?parseInt(s.data("filtered-count-trash"),10):0,a={action:"wpforms_entry_list_process_"+n.action+"_all",form_id:s.find('input[name="form_id"]').val(),date:s.find('input[name="date"]').val(),page:t,search:{field:s.find('select[name="search[field]"]').val(),comparison:s.find('select[name="search[comparison]"]').val(),term:s.find('input[name="search[term]"]').val()},nonce:wpforms_admin.nonce,url:o};l.confirm({title:wpforms_admin.heads_up,content:i&&l("#wpforms-reset-filter").length?n.content.replace("{entry_count}",i):n.contentAll,icon:"fa fa-exclamation-circle",type:"orange",buttons:{confirm:{text:wpforms_admin.ok,btnClass:"btn-confirm",keys:["enter"],action:()=>{l.get(wpforms_admin.ajax_url,a).done(function(e){e.success&&(window.location=_.isEmpty(e.data)?o:e.data)})}},cancel:{text:wpforms_admin.cancel,keys:["esc"]}}})}),l(document).on("heartbeat-send",function(e,t){var n,o=l("#wpforms-entries-list");o.length&&!o.find(".wpforms-dash-widget").length&&void 0!==(n=o.find("#wpforms-entries-table").data("last-entry-id"))&&(t.wpforms_new_entries_entry_id=n,t.wpforms_new_entries_form_id=o.find("input[name=form_id]").val())}),l(document).on("heartbeat-tick",function(e,t){var n=l("#wpforms-entries-list");if(n.length&&t.wpforms_new_entries_notification){var o=n.find(".wp-list-table thead tr").first().children().length;n.find(".new-entries-notification").length||n.find(".wp-list-table thead").append('');let e=n.find(".new-entries-notification a");e.text(t.wpforms_new_entries_notification).slideDown({start(){e.css("display","block")},always(){e.css("display","block")}})}})},initEntriesSingle(){"wpforms-entries"===p.getQueryString("page")&&"details"===p.getQueryString("view")&&p.entryHotkeys(),l(document).on("click","#wpforms-entries-single .wpforms-entry-delete a",function(e){e.preventDefault();let t=l(this).attr("href");l.confirm({title:wpforms_admin.heads_up,content:wpforms_admin.entry_delete_confirm,icon:"fa fa-exclamation-circle",type:"orange",buttons:{confirm:{text:wpforms_admin.ok,btnClass:"btn-confirm",keys:["enter"],action(){window.location=t}},cancel:{text:wpforms_admin.cancel,keys:["esc"]}}})}),l(document).on("click","#wpforms-entries-single .trash",function(e){e.preventDefault();let t=l(this).attr("href");l.confirm({title:wpforms_admin.heads_up,content:wpforms_admin.entry_trash_confirm,icon:"fa fa-exclamation-circle",type:"orange",buttons:{confirm:{text:wpforms_admin.ok,btnClass:"btn-confirm",keys:["enter"],action:()=>{window.location=t}},cancel:{text:wpforms_admin.cancel,keys:["esc"]}}})}),l(document).on("click","#wpforms-entries-single .wpforms-entry-print a",function(e){e.preventDefault(),window.open(l(this).attr("href"))}),l(document).on("click","#wpforms-entries-single .wpforms-empty-field-toggle",function(e){e.preventDefault(),"true"===wpCookies.get("wpforms_entry_hide_empty")?(wpCookies.remove("wpforms_entry_hide_empty"),l(this).text(wpforms_admin.entry_empty_fields_hide)):(wpCookies.set("wpforms_entry_hide_empty","true",2592e3),l(this).text(wpforms_admin.entry_empty_fields_show)),l(".wpforms-entry-field.empty, .wpforms-edit-entry-field.empty").toggle()}),l(document).on("click","#wpforms-entries-single .wpforms-entry-notes-new .add",function(e){e.preventDefault(),l(this).hide().next("form").stop().slideToggle()}),l(document).on("click","#wpforms-entries-single .wpforms-entry-notes-new .cancel",function(e){e.preventDefault(),l(this).closest("form").stop().slideToggle(),l(".wpforms-entry-notes-new .add").show()}),l(document).on("click","#wpforms-entries-single .wpforms-entry-notes-byline .note-delete",function(e){e.preventDefault();let t=l(this).attr("href");l.confirm({title:wpforms_admin.heads_up,content:wpforms_admin.entry_note_delete_confirm,icon:"fa fa-exclamation-circle",type:"orange",buttons:{confirm:{text:wpforms_admin.ok,btnClass:"btn-confirm",keys:["enter"],action(){window.location=t}},cancel:{text:wpforms_admin.cancel,keys:["esc"]}}})})},entryHotkeys(){l(document).on("keydown",function(e){74!==e.keyCode||e.metaKey||p.isFormTypeNode(e.target.nodeName)?75!==e.keyCode||e.metaKey||p.isFormTypeNode(e.target.nodeName)||"#"!==(e=l("#wpforms-admin-single-navigation-next-link").attr("href"))&&(window.location.href=e):"#"!==(e=l("#wpforms-admin-single-navigation-prev-link").attr("href"))&&(window.location.href=e)})},initWelcome(){l(document).on("click","#wpforms-welcome .play-video",function(e){e.preventDefault();l.dialog({title:!1,content:'
',closeIcon:!0,boxWidth:"70%"})})},initAddons(){if(l("#wpforms-admin-addons").length){var n=l("#wpforms-addons-list-section-all"),o=l("#wpforms-addons-list-section-installed");if(n.length||o.length){let e,t;o.length&&(e=new List("wpforms-addons-list-section-installed",{valueNames:["addon-link"]})),n.length&&(t=new List("wpforms-addons-list-section-all",{valueNames:["addon-link"]})),l("#wpforms-addons-search").on("keyup search",function(){p.updateAddonSearchResult(this,t,e)})}l(document).on("change",".wpforms-addons-list-item .wpforms-toggle-control input",function(e){if(e.preventDefault(),l(this).hasClass("disabled"))return!1;p.addonToggleNew(l(this))}),l(document).on("click",".wpforms-addons-list-item button",function(e){if(e.preventDefault(),l(this).hasClass("disabled"))return!1;p.addonToggleNew(l(this))}),l(document).on("click","#wpforms-admin-addons .addon-item button",function(e){if(e.preventDefault(),l(this).hasClass("disabled"))return!1;p.addonToggle(l(this))})}},updateAddonSearchResult(e,t,n){let o=l(e).val();o=o.replace(/[.,]/g," ");var e=l("#wpforms-addons-no-results"),s=l("#wpforms-addons-list-section-all"),i=l("#wpforms-addons-list-section-installed"),t=t?t.search(o):[],n=n?n.search(o):[];e.toggle(0===t.length&&0===n.length),s.toggle(0

${"addon"===t?wpforms_admin.addon_error:wpforms_admin.plugin_error}

`):r.append(``),"install"===i?(n=!1,p.removeSpinnerFromButton(a)):"deactivate"===i?n=!0:"activate"===i&&(n=!1)}p.setAddonState(e,i,t,function(e){var t;e.success?(t=e,"install"===i?(o=c.active,n=!0,r.attr("data-plugin",t.data.basename),t.data.is_activated||(o=c.installed,n=!1),a.hide(),a=a.closest(".wpforms-addons-list-item").find(".wpforms-toggle-control input")):"activate"===i?(r.find(".wpforms-addons-list-item-footer-settings-link").fadeIn(150),o=c.active,n=!0):"deactivate"===i&&(r.find(".wpforms-addons-list-item-footer-settings-link").fadeOut(150),o=c.installed,n=!1),r.removeClass(c.active+" "+c.incompatible+" "+c.installed+" "+c.missing).addClass(o)):d(e),p.updateAddonButtonPropertiesAndUI(a,s,r,c,n)},function(){d({data:wpforms_admin.server_error}),p.updateAddonButtonPropertiesAndUI(a,s,r,c,n)})}},addSpinnerToButton(e){var t=e.width();e.data("original-text",e.html()),e.width(t).html('')},removeSpinnerFromButton(e){e.html(e.data("original-text"))},getAddonState(e,t,n){return e.hasClass(t.active)||e.hasClass(t.incompatible)?"deactivate":e.hasClass(t.installed)?"activate":e.hasClass(t.missing)?(p.addSpinnerToButton(n),"install"):""},updateAddonButtonPropertiesAndUI(e,t,n,o,s){e.prop("checked",s),e.prop("disabled",!1),e.siblings(".wpforms-toggle-control-status").html(e.siblings(".wpforms-toggle-control-status").data(s?"on":"off")),0'+d+""),t.find("span.status-label").removeClass("status-active status-installed status-missing").addClass(i).removeClass("button button-primary button-secondary disabled").text(a),o.removeClass("status-active status-installed status-missing").removeClass("button button-primary button-secondary disabled").addClass(i).html(r)):("object"==typeof e.data?"addon"===n?t.find(".actions").append('

'+wpforms_admin.addon_error+"

"):t.find(".actions").append('

'+wpforms_admin.plugin_error+"

"):t.find(".actions").append('

'+e.data+"

"),"install"===s&&"plugin"===n&&o.addClass("status-go-to-url").removeClass("status-missing"),o.html(c)),o.prop("disabled",!1).removeClass("loading"),t.find(".actions").find(".msg.error").length||setTimeout(function(){l(".addon-item .msg").remove()},3e3)},function(e){console.log(e.responseText)})}},initSettings(){l(document).on("wpformsReady",function(){var e,t;l("#wpforms-settings").length&&(e=p.getQueryString("wpforms-integration"),t=p.getQueryString("jump"),e?l("body").animate({scrollTop:l("#wpforms-integration-"+e).offset().top},1e3):t&&l("body").animate({scrollTop:l("#"+t).offset().top},1e3),l(".wpforms-admin-settings-form").conditions([{conditions:{element:"#wpforms-setting-gdpr",type:"checked",operator:"is"},actions:{if:{element:"#wpforms-setting-row-gdpr-disable-uuid,#wpforms-setting-row-gdpr-disable-details",action:"show"},else:{element:"#wpforms-setting-row-gdpr-disable-uuid,#wpforms-setting-row-gdpr-disable-details",action:"hide"}},effect:"appear"},{conditions:{element:"input[name=captcha-provider]:checked",type:"value",operator:"=",condition:"hcaptcha"},actions:{if:[{element:".wpforms-setting-row",action:"show"},{element:".wpforms-setting-recaptcha, #wpforms-setting-row-recaptcha-site-key, #wpforms-setting-row-recaptcha-secret-key, #wpforms-setting-row-recaptcha-fail-msg, .wpforms-setting-turnstile, #wpforms-setting-row-turnstile-heading, #wpforms-setting-row-turnstile-site-key, #wpforms-setting-row-turnstile-secret-key, #wpforms-setting-row-turnstile-theme, #wpforms-setting-row-turnstile-fail-msg",action:"hide"}]},effect:"appear"},{conditions:{element:"input[name=captcha-provider]:checked",type:"value",operator:"=",condition:"recaptcha"},actions:{if:[{element:".wpforms-setting-row",action:"show"},{element:"#wpforms-setting-row-hcaptcha-heading, #wpforms-setting-row-hcaptcha-site-key, #wpforms-setting-row-hcaptcha-secret-key, #wpforms-setting-row-hcaptcha-fail-msg, #wpforms-setting-row-turnstile-heading, #wpforms-setting-row-turnstile-site-key, #wpforms-setting-row-turnstile-secret-key, #wpforms-setting-row-turnstile-theme, #wpforms-setting-row-turnstile-fail-msg",action:"hide"}]},effect:"appear"},{conditions:{element:"input[name=captcha-provider]:checked",type:"value",operator:"=",condition:"turnstile"},actions:{if:[{element:".wpforms-setting-row",action:"show"},{element:"#wpforms-setting-row-hcaptcha-heading, #wpforms-setting-row-hcaptcha-site-key, #wpforms-setting-row-hcaptcha-secret-key, #wpforms-setting-row-hcaptcha-fail-msg, .wpforms-setting-recaptcha, #wpforms-setting-row-recaptcha-site-key, #wpforms-setting-row-recaptcha-secret-key, #wpforms-setting-row-recaptcha-fail-msg",action:"hide"}]},effect:"appear"},{conditions:{element:"input[name=captcha-provider]:checked",type:"value",operator:"=",condition:"none"},actions:{if:[{element:".wpforms-setting-row",action:"hide"},{element:".wpforms-setting-captcha-heading, #wpforms-setting-row-captcha-provider",action:"show"}]},effect:"appear"}]))}),l(document).on("change","#wpforms-setting-row-render-engine input",p.settingsRenderEngineChange),l(document).on("change","#wpforms-setting-disable-css",function(){p.settingsFormStylesAlert(l(this).val())}),l(document).on("click",".wpforms-setting-row-image button",function(e){e.preventDefault(),l(this).hasClass("wpforms-setting-remove-image")?l(this).closest(".wpforms-setting-row-image").find("input").val("").attr("value","").trigger("change").end().find("img").remove():p.imageUploadModal(l(this))}),l(document).on("click","#wpforms-setting-license-key-verify",function(e){e.preventDefault(),p.licenseVerify(l(this))}),l(document).on("click",".wpforms-setting-license-wrapper",function(e){e.preventDefault();e=l("#wpforms-setting-license-key");e.length&&e.prop("disabled")&&p.licenseEditMessage()}),l(document).on("click","#wpforms-setting-license-key-deactivate",function(e){e.preventDefault(),p.licenseDeactivate(l(this))}),l(document).on("click","#wpforms-setting-license-key-refresh",function(e){e.preventDefault(),p.licenseRefresh(l(this))}),l(document).on("click",".wpforms-settings-provider-connect",function(e){e.preventDefault();e=l(this);p.integrationConnect(e)}),l(document).on("click",".wpforms-settings-provider-accounts-list .remove a",function(e){e.preventDefault(),p.integrationDisconnect(l(this))}),l(document).on("click",".wpforms-settings-provider:not(.focus-out) .wpforms-settings-provider-header",function(e){e.preventDefault();let t=l(this);t.parent().find(".wpforms-settings-provider-accounts").stop(!1,!0).slideToggle("",function(){t.parent().find(".wpforms-settings-provider-logo i").toggleClass("fa-chevron-right fa-chevron-down")})}),l(document).on("click",".wpforms-settings-provider-accounts-toggle a",function(e){e.preventDefault();e=l(this).parent().next(".wpforms-settings-provider-accounts-connect");e.find("input[type=text], input[type=password]").val(""),e.stop().slideToggle()}),l(document).on("change","#wpforms-setting-row-captcha-provider input",function(){var e=l("#wpforms-setting-row-captcha-preview");"hcaptcha"===this.value||"turnstile"===this.value?e.removeClass("wpforms-hidden"):"none"===this.value?e.addClass("wpforms-hidden"):l("#wpforms-setting-row-recaptcha-type input:checked").trigger("change"),e.find(".wpforms-captcha-preview").length&&(e.find(".wpforms-captcha-preview").empty(),e.find(".wpforms-captcha-placeholder").removeClass("wpforms-hidden"))}),l(document).on("change","#wpforms-setting-row-recaptcha-type input",function(){l("#wpforms-setting-row-captcha-preview").toggleClass("wpforms-hidden","v2"!==this.value),l("#wpforms-setting-row-recaptcha-v3-threshold").toggleClass("wpforms-hidden","v3"!==this.value)}),l(document).on("change",".wpforms-toggle-control input",function(){var e=l(this),t=e.is(":checked"),n=t?"on":"off",o=e.closest(".wpforms-setting-field"),e=e.closest(".wpforms-toggle-control").find(".wpforms-toggle-control-status"),s=o.find(".wpforms-toggle-desc.desc-on"),o=o.find(".wpforms-toggle-desc.desc-off"),i=0'),t.trigger("change")}).on("close",function(){m.mediaFrame.off("library:selection:add")}),m.mediaFrame.open()},licenseVerify(s){let i=s.closest(".wpforms-setting-row"),a=l("#wpforms-setting-license-key"),e=s.outerWidth(),r=s.text(),t={action:"wpforms_verify_license",nonce:wpforms_admin.nonce,license:a.val()};s.html(m.iconSpinner).css("width",e).prop("disabled",!0),l.post(wpforms_admin.ajax_url,t,function(e){let t="fa fa-check-circle",n="green",o;e.success?(o=e.data.msg,s.hide(),i.find("#wpforms-setting-license-key-info-message").empty().hide(),i.find(".type, .desc, #wpforms-setting-license-key-deactivate").show(),i.find(".type strong").text(e.data.type),l(".wpforms-license-notice").remove(),a.prop("disabled",!0).addClass("wpforms-setting-license-is-valid").attr("value",a.val().replace(/./g,"*"))):(t="fa fa-exclamation-circle",n="orange",o=e.data,i.find(".type, .desc, #wpforms-setting-license-key-deactivate").hide(),a.prop("disabled",!1)),l.alert({title:o.header??!1,content:o.msg??o,icon:t,type:n,buttons:{confirm:{text:wpforms_admin.ok,btnClass:"btn-confirm",keys:["enter"]}}}),s.html(r).css("width","auto").prop("disabled",!1)}).fail(function(e){a.prop("disabled",!1),console.log(e.responseText)})},licenseEditMessage(){l.alert({title:wpforms_admin.heads_up,content:wpforms_admin.edit_license,icon:"fa fa-exclamation-circle",type:"orange",buttons:{confirm:{text:wpforms_admin.ok,btnClass:"btn-confirm",keys:["enter"]}}})},licenseDeactivate(e){let a=l(e),r=a.closest(".wpforms-setting-row");e=a.outerWidth();let c=a.text();var t={action:"wpforms_deactivate_license",nonce:wpforms_admin.nonce};a.html(m.iconSpinner).css("width",e).prop("disabled",!0),l.post(wpforms_admin.ajax_url,t,function(e){let t="fa fa-info-circle",n="blue",o=wpforms_admin.success;var s=e.data,i=s.msg&&"string"==typeof s.msg?s.msg:wpforms_admin.something_went_wrong;e.success?(r.find("#wpforms-setting-license-key").val("").attr("value","").prop({readonly:!1,disabled:!1}).removeClass(),r.find(".wpforms-license-key-deactivate-remove").remove(),r.find("#wpforms-setting-license-key-info-message").html(s.info).show(),r.find("#wpforms-setting-license-key-verify").prop("disabled",!1).show(),r.find(".type, .desc, #wpforms-setting-license-key-deactivate").hide()):(t="fa fa-exclamation-circle",n="orange",o=wpforms_admin.oops),l.alert({title:o,content:i,icon:t,type:n,buttons:{confirm:{text:wpforms_admin.ok,btnClass:"btn-confirm",keys:["enter"]}}}),a.html(c).css("width","auto").prop("disabled",!1)}).fail(function(e){console.log(e.responseText)})},licenseRefresh(e){let t=l(e),s=t.closest(".wpforms-setting-row"),i=l("#wpforms-setting-license-key"),n={action:"wpforms_refresh_license",nonce:wpforms_admin.nonce};l.post(wpforms_admin.ajax_url,n,function(e){let t="fa fa-check-circle",n="green",o;e.success?(o=e.data.msg,s.find(".type strong").text(e.data.type)):(t="fa fa-exclamation-circle",n="orange",o=e.data,s.find(".type, .desc").hide(),i.removeClass("wpforms-setting-license-is-valid").addClass("wpforms-setting-license-is-invalid")),l.alert({title:o.header??!1,content:o.msg??o,icon:t,type:n,buttons:{confirm:{text:wpforms_admin.ok,btnClass:"btn-confirm",keys:["enter"]}}})}).fail(function(e){console.log(e.responseText)})},integrationConnect(t){let e=t.outerWidth(),n=t.text(),o=t.closest(".wpforms-settings-provider"),s={action:"wpforms_settings_provider_add_"+t.data("provider"),data:t.closest("form").serialize(),provider:t.data("provider"),nonce:wpforms_admin.nonce},i=wpforms_admin.provider_auth_error;t.html(wpforms_admin.connecting).css("width",e).prop("disabled",!0),l.post(wpforms_admin.ajax_url,s,function(e){e.success?(o.find(".wpforms-settings-provider-accounts-list ul").append(e.data.html),o.addClass("connected"),t.closest(".wpforms-settings-provider-accounts-connect").stop().slideToggle()):(Object.prototype.hasOwnProperty.call(e,"data")&&Object.prototype.hasOwnProperty.call(e.data,"error_msg")&&(i+="
"+e.data.error_msg),p.integrationError(i))}).fail(function(){p.integrationError(i)}).always(function(){t.html(n).css("width","auto").prop("disabled",!1)})},integrationDisconnect(e){let n=l(e),o=n.parents(".wpforms-settings-provider"),t={action:"wpforms_settings_provider_disconnect_"+n.data("provider"),provider:n.data("provider"),key:n.data("key"),nonce:wpforms_admin.nonce},s=wpforms_admin.provider_delete_error;l.confirm({title:wpforms_admin.heads_up,content:wpforms_admin.provider_delete_confirm,icon:"fa fa-exclamation-circle",type:"orange",buttons:{confirm:{text:wpforms_admin.ok,btnClass:"btn-confirm",keys:["enter"],action(){l.post(wpforms_admin.ajax_url,t,function(e){var t;e.success?(n.parent().parent().remove(),void 0!==(t=o.find(".wpforms-settings-provider-accounts-list li").length)&&0!==t||o.removeClass("connected"),l(document).trigger("wpformsProviderRemoved",[o,e])):(Object.prototype.hasOwnProperty.call(e,"data")&&Object.prototype.hasOwnProperty.call(e.data,"error_msg")&&(s+="
"+e.data.error_msg),p.integrationError(s))}).fail(function(){p.integrationError(s)})}},cancel:{text:wpforms_admin.cancel,keys:["esc"]}}})},integrationError(e){l.alert({title:wpforms_admin.something_went_wrong,content:e,icon:"fa fa-exclamation-circle",type:"orange",buttons:{confirm:{text:wpforms_admin.ok,btnClass:"btn-confirm",keys:["enter"]}}})},initTools(){l(document).on("change","#wpforms-tools-form-import, #wpforms-tools-form-other-import, #wpforms-tools-form-export, #wpforms-tools-form-template",function(){var e=l(this);e.parents("form").find("button").attr("aria-disabled",0===e.val().length)}),l(document).on("click","#wpforms-system-information-copy",function(e){e.preventDefault(),p.copySystemInformation()}),l(document).on("click","#wpforms-ssl-verify",function(e){e.preventDefault(),p.verifySSLConnection()}),l(document).on("click","#wpforms-recreate-tables",function(e){e.preventDefault(),p.recreateTables()}),l(document).on("click","#wpforms-importer-forms-submit",function(e){e.preventDefault();e=l("#wpforms-importer-forms input:checked");if(e.length){let t=[];e.each(function(e){t[e]=l(this).val()}),wpforms_admin.isPro?p.importForms(t):p.analyzeForms(t)}else l.alert({title:wpforms_admin.heads_up,content:wpforms_admin.importer_forms_required,icon:"fa fa-info-circle",type:"blue",buttons:{confirm:{text:wpforms_admin.ok,btnClass:"btn-confirm",keys:["enter"]}}})}),l(document).on("click","#wpforms-importer-continue-submit",function(e){e.preventDefault(),p.importForms(m.formIDs)})},copySystemInformation(){l("#wpforms-system-information").select(),document.execCommand("copy")},verifySSLConnection(){let t=l("#wpforms-ssl-verify"),n=t.text(),o=t.outerWidth(),s=t.parent();t.css("width",o).prop("disabled",!0).text(wpforms_admin.testing);var e={action:"wpforms_verify_ssl",nonce:wpforms_admin.nonce};l.post(wpforms_admin.ajax_url,e,function(e){p.debug(e),s.find(".wpforms-notice").remove(),e.success&&t.before('
'+e.data.msg+"
"),!e.success&&e.data.msg&&t.before('
'+e.data.msg+"
"),!e.success&&e.data.debug&&t.before('
'+e.data.debug+"
"),t.css("width",o).prop("disabled",!1).text(n)})},recreateTables(){let t=l("#wpforms-recreate-tables"),e=t.text(),n=t.outerWidth(),o=t.parent();t.css("width",n).prop("disabled",!0).text(wpforms_admin.recreating);var s={action:"wpforms_recreate_tables",nonce:wpforms_admin.nonce};l.post(wpforms_admin.ajax_url,s,function(e){p.debug(e),o.find(".wpforms-notice").remove(),e.success&&(t.before('
'+e.data.msg+"
"),t.hide()),!e.success&&e.data.msg&&t.before('
'+e.data.msg+"
"),!e.success&&e.data.debug&&t.before('
'+e.data.debug+"
")}).always(function(){t.css("width",n).prop("disabled",!1).text(e)})},analyzeForms(e){var t=l("#wpforms-importer-analyze");t.find(".form-total").text(e.length),t.find(".form-current").text("1"),l("#wpforms-importer-forms").hide(),t.show(),m.analyzeQueue=e,m.analyzed=0,m.analyzeUpgrade=[],m.formIDs=e,p.analyzeForm()},analyzeForm(){let t=l("#wpforms-importer-analyze"),n=_.first(m.analyzeQueue),e=p.getQueryString("provider"),o={action:"wpforms_import_form_"+e,analyze:1,form_id:n,nonce:wpforms_admin.nonce};l.post(wpforms_admin.ajax_url,o,function(e){e.success&&(_.isEmpty(e.data.upgrade_plain)&&_.isEmpty(e.data.upgrade_omit)||m.analyzeUpgrade.push({name:e.data.name,fields:_.union(e.data.upgrade_omit,e.data.upgrade_plain)}),m.analyzeQueue=_.without(m.analyzeQueue,n),m.analyzed++,_.isEmpty(m.analyzeQueue)?_.isEmpty(m.analyzeUpgrade)?p.importForms(m.formIDs):(e=wp.template("wpforms-importer-upgrade"),t.find(".upgrade").append(e(m.analyzeUpgrade)),t.find(".upgrade").show(),t.find(".process-analyze").hide()):(t.find(".form-current").text(m.analyzed+1),p.analyzeForm()))})},importForms(e){var t=l("#wpforms-importer-process");t.find(".form-total").text(e.length),t.find(".form-current").text("1"),l("#wpforms-importer-forms, #wpforms-importer-analyze").hide(),t.show(),m.importQueue=e,m.imported=0,p.importForm()},importForm(){let n=l("#wpforms-importer-process"),o=_.first(m.importQueue),e=p.getQueryString("provider"),t={action:"wpforms_import_form_"+e,form_id:o,nonce:wpforms_admin.nonce};l.post(wpforms_admin.ajax_url,t,function(t){if(t.success){let e;e=t.data.error?wp.template("wpforms-importer-status-error"):wp.template("wpforms-importer-status-update"),n.find(".status").prepend(e(t.data)),n.find(".status").show(),m.importQueue=_.without(m.importQueue,o),m.imported++,_.isEmpty(m.importQueue)?(n.find(".process-count").hide(),n.find(".forms-completed").text(m.imported),n.find(".process-completed").show()):(n.find(".form-current").text(m.imported+1),p.importForm())}})},initUpgrades(){l(document).on("click","#wpforms-upgrade-143 button",function(e){e.preventDefault();let t=l(this),n=t.outerWidth(),o=l("#wpforms-upgrade-143 .status"),s={action:"wpforms_upgrade_143",nonce:wpforms_admin.nonce,init:!0,incomplete:t.data("incomplete")};t.html(m.iconSpinner).css("width",n).prop("disabled",!0),l.post(wpforms_admin.ajax_url,s,function(e){e.success&&(m.upgraded=Number(e.data.upgraded),m.upgradeTotal=Number(e.data.total),e=Math.round(Number(m.upgraded)/Number(m.upgradeTotal)*100),t.remove(),o.find(".bar").css("width",e+"%"),o.show().find(".total").text(m.upgradeTotal),o.find(".current").text(m.upgraded),o.find(".percent").text(e+"%"),p.upgrade143())})})},upgrade143(){let n=l("#wpforms-upgrade-143 .status"),e={action:"wpforms_upgrade_143",nonce:wpforms_admin.nonce,upgraded:m.upgraded};l.post(wpforms_admin.ajax_url,e,function(e){var t;e.success&&(m.upgraded=Number(m.upgraded)+Number(e.data.count),t=Math.round(Number(m.upgraded)/Number(m.upgradeTotal)*100),n.find(".bar").css("width",t+"%"),Number(e.data.count)<10?(n.find(".progress-bar").addClass("complete"),n.find(".msg").text(wpforms_admin.upgrade_completed)):(n.find(".current").text(m.upgraded),n.find(".percent").text(t+"%"),p.upgrade143()))})},initFlyoutMenu(){let r=l("#wpforms-flyout");if(0!==r.length){let e=r.find(".wpforms-flyout-head"),t=e.find("img"),n={state:"inactive",srcInactive:t.attr("src"),srcActive:t.data("active")},a=(e.on("click",function(e){e.preventDefault(),"active"===n.state?(r.removeClass("opened"),t.attr("src",n.srcInactive),n.state="inactive"):(r.addClass("opened"),t.attr("src",n.srcActive),n.state="active")}),l("#wpfooter"));if(0!==a.length){let i=l("#wpforms-overview, #wpforms-entries-list, #wpforms-tools.wpforms-tools-tab-action-scheduler, #wpforms-tools.wpforms-tools-tab-logs");l(window).on("resize scroll",_.debounce(function(){var e=a.offset().top,t=e+a.height(),n=0["spam","trash"].includes(e)?{contentAll:wpforms_admin.entry_delete_all_confirm,content:wpforms_admin.entry_delete_n_confirm,action:"delete"}:{contentAll:wpforms_admin.entry_trash_all_confirm,content:wpforms_admin.entry_trash_n_confirm,action:"trash"},initScrollableMenu(){l(document).on("wpformsReady",function(){let t=l(".wpforms-admin-tabs");if(t.length){let e=t.find("li:last-child");wpf.isInViewport(e)||t.addClass("wpforms-admin-tabs--scrollable"),t.on("scroll",function(){t.toggleClass("wpforms-admin-tabs--scrollable",!wpf.isInViewport(e))})}})}};p.init(),window.WPFormsAdmin=p})(jQuery); \ No newline at end of file diff --git a/wp-content/plugins/wpforms-lite/assets/js/admin/builder/admin-builder-providers.js b/wp-content/plugins/wpforms-lite/assets/js/admin/builder/admin-builder-providers.js new file mode 100755 index 00000000..19e23d75 --- /dev/null +++ b/wp-content/plugins/wpforms-lite/assets/js/admin/builder/admin-builder-providers.js @@ -0,0 +1,594 @@ +/* global wpforms_builder_providers, wpforms_builder, wpf, WPForms, WPFormsBuilder */ + +( function( $ ) { + + var s; + + var WPFormsProviders = { + + settings: { + spinner: '', + spinnerWhite: '', + }, + + /** + * Start the engine. + * + * @since 1.0.0 + */ + init: function() { + + s = this.settings; + + // Document ready. + $( WPFormsProviders.ready ); + + WPFormsProviders.bindUIActions(); + }, + + /** + * Document ready. + * + * @since 1.1.1 + */ + ready: function() { + + // Setup/cache some vars not available before. + s.form = $( '#wpforms-builder-form' ); + }, + + /** + * Element bindings. + * + * @since 1.0.0 + */ + bindUIActions: function() { + + // Delete connection. + $( document ).on( 'click', '.wpforms-provider-connection-delete', function( e ) { + WPFormsProviders.connectionDelete( this, e ); + } ); + + // Add new connection. + $( document ).on( 'click', '.wpforms-provider-connections-add', function( e ) { + WPFormsProviders.connectionAdd( this, e ); + } ); + + // Add new provider account. + $( document ).on( 'click', '.wpforms-provider-account-add button', function( e ) { + WPFormsProviders.accountAdd( this, e ); + } ); + + // Select provider account. + $( document ).on( 'change', '.wpforms-provider-accounts select', function( e ) { + WPFormsProviders.accountSelect( this, e ); + } ); + + // Select account list. + $( document ).on( 'change', '.wpforms-provider-lists select', function( e ) { + WPFormsProviders.accountListSelect( this, e ); + } ); + + // BC: Constant Contact v2, Aweber v1 and Campaign Monitor don't have JS logic for updating select fields with form fields options. + // That's why we have to refresh the form every time when change something in fields and visit the Marketing tab. + $( document ).on( 'wpformsPanelSwitch', function( e, targetPanel ) { + const legacyProviders = [ 'aweber', 'campaign-monitor', 'constant-contact' ]; + const hasConfiguredLegacyProvider = legacyProviders.some( ( legacyProvider ) => $( `.wpforms-panel-content-section-${ legacyProvider } .wpforms-provider-connection` ).length > 0 ); + + if ( hasConfiguredLegacyProvider ) { + WPFormsProviders.providerPanelConfirm( targetPanel ); + } + } ); + + // Alert users if they save a form and do not configure required + // fields. + $( document ).on( 'wpformsSaved', function( e, data ) { + var providerAlerts = []; + var $connectionBlocks = $( '#wpforms-panel-providers' ).find( '.wpforms-connection-block' ); + + if ( ! $connectionBlocks.length ) { + return; + } + + $connectionBlocks.each( function() { + var requiredEmpty = false, + providerName; + $( this ).find( 'table span.required' ).each( function() { + var $element = $( this ).parent().parent().find( 'select' ); + if ( $element.val() === '' ) { + requiredEmpty = true; + } + } ); + if ( requiredEmpty ) { + var $titleArea = $( this ).closest( '.wpforms-panel-content-section' ).find( '.wpforms-panel-content-section-title' ).clone(); + $titleArea.find( 'button' ).remove(); + providerName = $titleArea.text().trim(); + var msg = wpforms_builder.provider_required_flds; + + if ( -1 < providerAlerts.indexOf( providerName ) ) { + return; + } + $.alert( { + title: wpforms_builder.heads_up, + content: msg.replace( '{provider}', providerName ), + icon: 'fa fa-exclamation-circle', + type: 'orange', + buttons: { + confirm: { + text: wpforms_builder.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + }, + }, + } ); + providerAlerts.push( providerName ); + } + } ); + } ); + }, + + /** + * Delete provider connection + * + * @since 1.0.0 + */ + connectionDelete: function( el, e ) { + e.preventDefault(); + + var $this = $( el ); + + $.confirm( { + title: false, + content: wpforms_builder_providers.confirm_connection, + icon: 'fa fa-exclamation-circle', + type: 'orange', + buttons: { + confirm: { + text: wpforms_builder.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + action: function() { + + const $section = $this.closest( '.wpforms-panel-content-section' ); + + $this.closest( '.wpforms-provider-connection' ).remove(); + + // Update sidebar icon near the provider. + const provider = $this.closest( '.wpforms-provider-connection' ).data( 'provider' ), + $sidebarItem = $( '.wpforms-panel-sidebar-section-' + provider ); + + $sidebarItem.find( '.fa-check-circle-o' ).toggleClass( 'wpforms-hidden', $( $section ).find( '.wpforms-provider-connection' ).length <= 0 ); + + if ( ! $section.find( '.wpforms-provider-connection' ).length ) { + $section.find( '.wpforms-builder-provider-connections-default' ).removeClass( 'wpforms-hidden' ); + } + }, + }, + cancel: { + text: wpforms_builder.cancel, + }, + }, + } ); + }, + + /** + * Add new provider connection. + * + * @since 1.0.0 + */ + connectionAdd: function( el, e ) { + e.preventDefault(); + + var $this = $( el ), + $connections = $this.parent().parent(), + $container = $this.parent(), + provider = $this.data( 'provider' ), + defaultValue = WPFormsProviders.getDefaultConnectionName( provider ).trim(), + type = $this.data( 'type' ), + namePrompt = wpforms_builder_providers.prompt_connection, + nameField = '', + nameError = '

' + wpforms_builder_providers.error_name + '

', + modalContent = namePrompt + nameField + nameError; + + modalContent = modalContent.replace( /%type%/g, type ); + + $.confirm( { + title: false, + content: modalContent, + icon: 'fa fa-info-circle', + type: 'blue', + buttons: { + confirm: { + text: wpforms_builder.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + action: function() { + var name = this.$content.find( 'input#provider-connection-name' ).val().trim(); + var error = this.$content.find( '.error' ); + if ( name === '' ) { + error.show(); + return false; + } else { + + // Disable button. + WPFormsProviders.inputToggle( $this, 'disable' ); + + // Fire AJAX. + var data = { + action : 'wpforms_provider_ajax_' + provider, + provider: provider, + task : 'new_connection', + name : name, + id : s.form.data( 'id' ), + nonce : wpforms_builder.nonce, + }; + WPFormsProviders.fireAJAX( $this, data, function( res ) { + if ( res.success ) { + $connections.find( '.wpforms-builder-provider-connections-default' ).addClass( 'wpforms-hidden' ); + $connections.find( '.wpforms-provider-connections' ).prepend( res.data.html ); + + // Process and load the accounts if they exist. + var $connection = $connections.find( '.wpforms-provider-connection' ).first(); + if ( $connection.find( '.wpforms-provider-accounts option:selected' ) ) { + $connection.find( '.wpforms-provider-accounts option' ).first().prop( 'selected', true ); + $connection.find( '.wpforms-provider-accounts select' ).trigger( 'change' ); + } + } else { + WPFormsProviders.errorDisplay( res.data.error, $container ); + } + } ); + } + }, + }, + cancel: { + text: wpforms_builder.cancel, + }, + }, + } ); + }, + + /** + * Add and authorize provider account. + * + * @since 1.0.0 + */ + accountAdd: function( el, e ) { + e.preventDefault(); + + var $this = $( el ), + provider = $this.data( 'provider' ), + $connection = $this.closest( '.wpforms-provider-connection' ), + $container = $this.parent(), + $fields = $container.find( ':input' ), + errors = WPFormsProviders.requiredCheck( $fields, $container ); + + // Disable button. + WPFormsProviders.inputToggle( $this, 'disable' ); + + // Bail if we have any errors. + if ( errors ) { + $this.prop( 'disabled', false ).find( 'i' ).remove(); + return false; + } + + // Fire AJAX. + var data = { + action : 'wpforms_provider_ajax_' + provider, + provider : provider, + connection_id: $connection.data( 'connection_id' ), + task : 'new_account', + data : WPFormsProviders.fakeSerialize( $fields ), + }; + WPFormsProviders.fireAJAX( $this, data, function( res ) { + if ( res.success ) { + $container.nextAll( '.wpforms-connection-block' ).remove(); + $container.nextAll( '.wpforms-conditional-block' ).remove(); + $container.after( res.data.html ); + $container.slideUp(); + $connection.find( '.wpforms-provider-accounts select' ).trigger( 'change' ); + } else { + WPFormsProviders.errorDisplay( res.data.error, $container ); + } + } ); + }, + + /** + * Selecting a provider account + * + * @since 1.0.0 + */ + accountSelect: function( el, e ) { + e.preventDefault(); + + var $this = $( el ), + $connection = $this.closest( '.wpforms-provider-connection' ), + $container = $this.parent(), + provider = $connection.data( 'provider' ); + + // Disable select, show loading. + WPFormsProviders.inputToggle( $this, 'disable' ); + + // Remove any blocks that might exist as we prep for new account. + $container.nextAll( '.wpforms-connection-block' ).remove(); + $container.nextAll( '.wpforms-conditional-block' ).remove(); + + if ( ! $this.val() ) { + + // User selected to option to add new account. + $connection.find( '.wpforms-provider-account-add input' ).val( '' ); + $connection.find( '.wpforms-provider-account-add' ).slideDown(); + WPFormsProviders.inputToggle( $this, 'enable' ); + + } else { + + $connection.find( '.wpforms-provider-account-add' ).slideUp(); + + // Fire AJAX. + var data = { + action : 'wpforms_provider_ajax_' + provider, + provider : provider, + connection_id: $connection.data( 'connection_id' ), + task : 'select_account', + account_id : $this.find( ':selected' ).val(), + }; + WPFormsProviders.fireAJAX( $this, data, function( res ) { + if ( res.success ) { + $container.after( res.data.html ); + + // Process first list found. + $connection.find( '.wpforms-provider-lists option' ).first().prop( 'selected', true ); + $connection.find( '.wpforms-provider-lists select' ).trigger( 'change' ); + } else { + WPFormsProviders.errorDisplay( res.data.error, $container ); + } + } ); + } + }, + + /** + * Selecting a provider account list. + * + * @since 1.0.0 + */ + accountListSelect: function( el, e ) { + e.preventDefault(); + + var $this = $( el ), + $connection = $this.closest( '.wpforms-provider-connection' ), + $container = $this.parent(), + provider = $connection.data( 'provider' ); + + // Disable select, show loading. + WPFormsProviders.inputToggle( $this, 'disable' ); + + // Remove any blocks that might exist as we prep for new account. + $container.nextAll( '.wpforms-connection-block' ).remove(); + $container.nextAll( '.wpforms-conditional-block' ).remove(); + + var data = { + action : 'wpforms_provider_ajax_' + provider, + provider : provider, + connection_id: $connection.data( 'connection_id' ), + task : 'select_list', + account_id : $connection.find( '.wpforms-provider-accounts option:selected' ).val(), + list_id : $this.find( ':selected' ).val(), + form_id : s.form.data( 'id' ), + }; + + WPFormsProviders.fireAJAX( $this, data, function( res ) { + if ( res.success ) { + $container.after( res.data.html ); + + // Re-init tooltips for new fields. + wpf.initTooltips(); + } else { + WPFormsProviders.errorDisplay( res.data.error, $container ); + } + } ); + }, + + /** + * Confirm form save before loading Provider panel. + * If confirmed, save and reload panel. + * + * @since 1.0.0 + */ + providerPanelConfirm: function( targetPanel ) { + + wpforms_panel_switch = true; + if ( targetPanel === 'providers' && ! s.form.data( 'revision' ) ) { + if ( ! WPFormsBuilder.formIsSaved() ) { + wpforms_panel_switch = false; + $.confirm( { + title: false, + content: wpforms_builder_providers.confirm_save, + icon: 'fa fa-info-circle', + type: 'blue', + buttons: { + confirm: { + text: wpforms_builder.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + action: function() { + $( '#wpforms-save' ).trigger( 'click' ); + $( document ).on( 'wpformsSaved', function() { + let wpforms_builder_provider_url = wpforms_builder_providers.url; + const $section = $( `#wpforms-panel-${ targetPanel } .wpforms-panel-sidebar-section.active` ); + const section = $section.length && $section.data( 'section' ) !== 'default' ? $section.data( 'section' ) : null; + + // Adding an active section parameter. + if ( section ) { + wpforms_builder_provider_url += `§ion=${ section }`; + } + + window.location.href = wpforms_builder_provider_url; + } ); + }, + }, + cancel: { + text: wpforms_builder.cancel, + }, + }, + } ); + } + } + }, + + //--------------------------------------------------------------------// + // Helper functions. + //--------------------------------------------------------------------// + + /** + * Fire AJAX call. + * + * @since 1.0.0 + */ + fireAJAX: function( el, d, success ) { + var $this = $( el ); + var data = { + id : $( '#wpforms-builder-form' ).data( 'id' ), + nonce : wpforms_builder.nonce, + }; + + $.extend( data, d ); + $.post( wpforms_builder.ajax_url, data, function( res ) { + success( res ); + WPFormsProviders.inputToggle( $this, 'enable' ); + } ).fail( function( xhr, textStatus, e ) { + console.log( xhr.responseText ); + } ); + }, + + /** + * Toggle input with loading indicator. + * + * @since 1.0.0 + */ + inputToggle: function( el, status ) { + var $this = $( el ); + if ( status === 'enable' ) { + if ( $this.is( 'select' ) ) { + $this.prop( 'disabled', false ).next( 'i' ).remove(); + } else { + $this.prop( 'disabled', false ).find( 'i' ).remove(); + } + } else if ( status === 'disable' ) { + if ( $this.is( 'select' ) ) { + $this.prop( 'disabled', true ).after( s.spinner ); + } else { + $this.prop( 'disabled', true ).prepend( s.spinnerWhite ); + } + } + }, + + /** + * Display error. + * + * @since 1.0.0 + */ + errorDisplay: function( msg, location ) { + location.find( '.wpforms-error-msg' ).remove(); + location.prepend( '

' + msg + '

' ); + }, + + /** + * Check for required fields. + * + * @since 1.0.0 + */ + requiredCheck: function( fields, location ) { + var error = false; + + // Remove any previous errors. + location.find( '.wpforms-alert-required' ).remove(); + + // Loop through input fields and check for values. + fields.each( function( index, el ) { + if ( $( el ).hasClass( 'wpforms-required' ) && $( el ).val().length === 0 ) { + $( el ).addClass( 'wpforms-error' ); + error = true; + } else { + $( el ).removeClass( 'wpforms-error' ); + } + } ); + if ( error ) { + location.prepend( '

' + wpforms_builder_providers.required_field + '

' ); + } + return error; + }, + + /** + * Pseudo serializing. Fake it until you make it. + * + * @since 1.0.0 + */ + fakeSerialize: function( els ) { + var fields = els.clone(); + + fields.each( function( index, el ) { + if ( $( el ).data( 'name' ) ) { + $( el ).attr( 'name', $( el ).data( 'name' ) ); + } + } ); + return fields.serialize(); + }, + + /** + * Get the default name for a new connection. + * + * @since 1.9.3 + * + * @param {string} provider Current provider slug. + * + * @return {string} Returns the default name for a new connection. + */ + getDefaultConnectionName( provider ) { + const providerName = $( `#${ provider }-provider` ).data( 'provider-name' ); + const numberOfConnections = WPFormsProviders.getCountConnectionsOf( provider ); + const defaultName = `${ providerName } ${ wpforms_builder.connection_label }`; + + return numberOfConnections < 1 ? defaultName : ''; + }, + + /** + * Get the number of connections for the provider. + * + * @since 1.9.3 + * + * @param {string} provider Current provider slug. + * + * @return {number} Returns the number of connections for the provider. + */ + getCountConnectionsOf( provider ) { + return $( `#${ provider }-provider .wpforms-provider-connection` ).length; + }, + + /** + * Get a provider JS object. + * + * @since 1.9.3 + * @deprecated 1.9.5 Not used anymore. + * + * @param {string} provider Provider name. + * + * @return {Object|null} Return provider object or null. + */ + getProviderClass( provider ) { + // eslint-disable-next-line no-console + console.warn( 'WARNING! Function "WPFormsProviders.getProviderClass()" has been deprecated!' ); + + const upperProviderPart = ( providerPart ) => ( + providerPart.charAt( 0 ).toUpperCase() + providerPart.slice( 1 ) + ); + + const getClassName = provider.split( '-' ).map( upperProviderPart ).join( '' ); + + if ( typeof WPForms?.Admin?.Builder?.Providers?.[ getClassName ] === 'undefined' ) { + return null; + } + return WPForms.Admin.Builder.Providers[ getClassName ]; + }, + }; + + WPFormsProviders.init(); +} )( jQuery ); diff --git a/wp-content/plugins/wpforms-lite/assets/js/admin/builder/admin-builder-providers.min.js b/wp-content/plugins/wpforms-lite/assets/js/admin/builder/admin-builder-providers.min.js new file mode 100755 index 00000000..b3e622e8 --- /dev/null +++ b/wp-content/plugins/wpforms-lite/assets/js/admin/builder/admin-builder-providers.min.js @@ -0,0 +1 @@ +(c=>{var s,a={settings:{spinner:'',spinnerWhite:''},init:function(){s=this.settings,c(a.ready),a.bindUIActions()},ready:function(){s.form=c("#wpforms-builder-form")},bindUIActions:function(){c(document).on("click",".wpforms-provider-connection-delete",function(e){a.connectionDelete(this,e)}),c(document).on("click",".wpforms-provider-connections-add",function(e){a.connectionAdd(this,e)}),c(document).on("click",".wpforms-provider-account-add button",function(e){a.accountAdd(this,e)}),c(document).on("change",".wpforms-provider-accounts select",function(e){a.accountSelect(this,e)}),c(document).on("change",".wpforms-provider-lists select",function(e){a.accountListSelect(this,e)}),c(document).on("wpformsPanelSwitch",function(e,n){["aweber","campaign-monitor","constant-contact"].some(e=>0')+('

'+wpforms_builder_providers.error_name+"

")).replace(/%type%/g,e);c.confirm({title:!1,content:n,icon:"fa fa-info-circle",type:"blue",buttons:{confirm:{text:wpforms_builder.ok,btnClass:"btn-confirm",keys:["enter"],action:function(){var e=this.$content.find("input#provider-connection-name").val().trim(),n=this.$content.find(".error");if(""===e)return n.show(),!1;a.inputToggle(o,"disable");n={action:"wpforms_provider_ajax_"+t,provider:t,task:"new_connection",name:e,id:s.form.data("id"),nonce:wpforms_builder.nonce};a.fireAJAX(o,n,function(e){var n;e.success?(r.find(".wpforms-builder-provider-connections-default").addClass("wpforms-hidden"),r.find(".wpforms-provider-connections").prepend(e.data.html),(n=r.find(".wpforms-provider-connection").first()).find(".wpforms-provider-accounts option:selected")&&(n.find(".wpforms-provider-accounts option").first().prop("selected",!0),n.find(".wpforms-provider-accounts select").trigger("change"))):a.errorDisplay(e.data.error,i)})}},cancel:{text:wpforms_builder.cancel}}})},accountAdd:function(e,n){n.preventDefault();var n=c(e),e=n.data("provider"),o=n.closest(".wpforms-provider-connection"),r=n.parent(),i=r.find(":input"),t=a.requiredCheck(i,r);if(a.inputToggle(n,"disable"),t)return n.prop("disabled",!1).find("i").remove(),!1;t={action:"wpforms_provider_ajax_"+e,provider:e,connection_id:o.data("connection_id"),task:"new_account",data:a.fakeSerialize(i)};a.fireAJAX(n,t,function(e){e.success?(r.nextAll(".wpforms-connection-block").remove(),r.nextAll(".wpforms-conditional-block").remove(),r.after(e.data.html),r.slideUp(),o.find(".wpforms-provider-accounts select").trigger("change")):a.errorDisplay(e.data.error,r)})},accountSelect:function(e,n){n.preventDefault();var n=c(e),o=n.closest(".wpforms-provider-connection"),r=n.parent(),e=o.data("provider");a.inputToggle(n,"disable"),r.nextAll(".wpforms-connection-block").remove(),r.nextAll(".wpforms-conditional-block").remove(),n.val()?(o.find(".wpforms-provider-account-add").slideUp(),e={action:"wpforms_provider_ajax_"+e,provider:e,connection_id:o.data("connection_id"),task:"select_account",account_id:n.find(":selected").val()},a.fireAJAX(n,e,function(e){e.success?(r.after(e.data.html),o.find(".wpforms-provider-lists option").first().prop("selected",!0),o.find(".wpforms-provider-lists select").trigger("change")):a.errorDisplay(e.data.error,r)})):(o.find(".wpforms-provider-account-add input").val(""),o.find(".wpforms-provider-account-add").slideDown(),a.inputToggle(n,"enable"))},accountListSelect:function(e,n){n.preventDefault();var n=c(e),e=n.closest(".wpforms-provider-connection"),o=n.parent(),r=e.data("provider"),r=(a.inputToggle(n,"disable"),o.nextAll(".wpforms-connection-block").remove(),o.nextAll(".wpforms-conditional-block").remove(),{action:"wpforms_provider_ajax_"+r,provider:r,connection_id:e.data("connection_id"),task:"select_list",account_id:e.find(".wpforms-provider-accounts option:selected").val(),list_id:n.find(":selected").val(),form_id:s.form.data("id")});a.fireAJAX(n,r,function(e){e.success?(o.after(e.data.html),wpf.initTooltips()):a.errorDisplay(e.data.error,o)})},providerPanelConfirm:function(o){wpforms_panel_switch=!0,"providers"!==o||s.form.data("revision")||WPFormsBuilder.formIsSaved()||(wpforms_panel_switch=!1,c.confirm({title:!1,content:wpforms_builder_providers.confirm_save,icon:"fa fa-info-circle",type:"blue",buttons:{confirm:{text:wpforms_builder.ok,btnClass:"btn-confirm",keys:["enter"],action:function(){c("#wpforms-save").trigger("click"),c(document).on("wpformsSaved",function(){let e=wpforms_builder_providers.url;var n=c(`#wpforms-panel-${o} .wpforms-panel-sidebar-section.active`),n=n.length&&"default"!==n.data("section")?n.data("section"):null;n&&(e+="§ion="+n),window.location.href=e})}},cancel:{text:wpforms_builder.cancel}}}))},fireAJAX:function(e,n,o){var r=c(e),e={id:c("#wpforms-builder-form").data("id"),nonce:wpforms_builder.nonce};c.extend(e,n),c.post(wpforms_builder.ajax_url,e,function(e){o(e),a.inputToggle(r,"enable")}).fail(function(e,n,o){console.log(e.responseText)})},inputToggle:function(e,n){e=c(e);"enable"===n?(e.is("select")?e.prop("disabled",!1).next("i"):e.prop("disabled",!1).find("i")).remove():"disable"===n&&(e.is("select")?e.prop("disabled",!0).after(s.spinner):e.prop("disabled",!0).prepend(s.spinnerWhite))},errorDisplay:function(e,n){n.find(".wpforms-error-msg").remove(),n.prepend('

'+e+"

")},requiredCheck:function(e,n){var o=!1;return n.find(".wpforms-alert-required").remove(),e.each(function(e,n){c(n).hasClass("wpforms-required")&&0===c(n).val().length?(c(n).addClass("wpforms-error"),o=!0):c(n).removeClass("wpforms-error")}),o&&n.prepend('

'+wpforms_builder_providers.required_field+"

"),o},fakeSerialize:function(e){e=e.clone();return e.each(function(e,n){c(n).data("name")&&c(n).attr("name",c(n).data("name"))}),e.serialize()},getDefaultConnectionName(e){var n=c(`#${e}-provider`).data("provider-name"),e=a.getCountConnectionsOf(e),n=n+" "+wpforms_builder.connection_label;return e<1?n:""},getCountConnectionsOf(e){return c(`#${e}-provider .wpforms-provider-connection`).length},getProviderClass(e){console.warn('WARNING! Function "WPFormsProviders.getProviderClass()" has been deprecated!');e=e.split("-").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join("");return void 0===WPForms?.Admin?.Builder?.Providers?.[e]?null:WPForms.Admin.Builder.Providers[e]}};a.init()})(jQuery); \ No newline at end of file diff --git a/wp-content/plugins/wpforms-lite/assets/js/admin/builder/admin-builder.js b/wp-content/plugins/wpforms-lite/assets/js/admin/builder/admin-builder.js new file mode 100755 index 00000000..cfdccb4f --- /dev/null +++ b/wp-content/plugins/wpforms-lite/assets/js/admin/builder/admin-builder.js @@ -0,0 +1,9815 @@ +/* global wpforms_builder, wpf, jconfirm, wpforms_panel_switch, Choices, WPForms */ +/* global WPFormsFormEmbedWizard, wpCookies, tinyMCE, WPFormsUtils, List, wpforms_preset_choices */ +// noinspection TypeScriptUMDGlobal + +/** + * @param window.Jconfirm.prototype._updateContentMaxHeight + * @param wpforms_builder.allow_deny_lists_intersect + * @param wpforms_builder.allow_only_email_fields + * @param wpforms_builder.allow_only_one_email + * @param wpforms_builder.are_you_sure_to_close + * @param wpforms_builder.bulk_add_button + * @param wpforms_builder.bulk_add_heading + * @param wpforms_builder.bulk_add_hide + * @param wpforms_builder.bulk_add_placeholder + * @param wpforms_builder.bulk_add_presets_show + * @param wpforms_builder.bulk_add_show + * @param wpforms_builder.choices_icons + * @param wpforms_builder.choices_images + * @param wpforms_builder.date_select_day + * @param wpforms_builder.date_select_month + * @param wpforms_builder.delete_choice_confirm + * @param wpforms_builder.duplicate_confirm + * @param wpforms_builder.duplicate_copy + * @param wpforms_builder.dynamic_choices.empty_message + * @param wpforms_builder.dynamic_choices.limit_message + * @param wpforms_builder.empty_email_address + * @param wpforms_builder.empty_label + * @param wpforms_builder.entry_preview_default_notice + * @param wpforms_builder.entry_preview_require_page_break + * @param wpforms_builder.entry_preview_require_previous_button + * @param wpforms_builder.error_choice + * @param wpforms_builder.error_contact_support + * @param wpforms_builder.error_number_slider_increment + * @param wpforms_builder.error_save_form + * @param wpforms_builder.error_save_form_forbidden + * @param wpforms_builder.exit_confirm + * @param wpforms_builder.field_locked_no_delete_msg + * @param wpforms_builder.field_locked_no_duplicate_msg + * @param wpforms_builder.file_upload.preview_hint + * @param wpforms_builder.file_upload.preview_title_plural + * @param wpforms_builder.file_upload.preview_title_plural_camera + * @param wpforms_builder.file_upload.preview_title_single + * @param wpforms_builder.file_upload.preview_title_single_camera + * @param wpforms_builder.icon_choices.choice_empty_label_tpl + * @param wpforms_builder.icon_choices.default_color + * @param wpforms_builder.icon_choices.default_icon + * @param wpforms_builder.icon_choices.default_icon_style + * @param wpforms_builder.icon_choices.delete_confirm + * @param wpforms_builder.icon_choices.field_locked + * @param wpforms_builder.icon_choices.icons_per_page + * @param wpforms_builder.icon_choices.is_active + * @param wpforms_builder.icon_choices.is_installed + * @param wpforms_builder.icon_choices.strings.icon_picker_description + * @param wpforms_builder.icon_choices.strings.icon_picker_not_found + * @param wpforms_builder.icon_choices.strings.icon_picker_search_placeholder + * @param wpforms_builder.icon_choices.strings.icon_picker_title + * @param wpforms_builder.icon_choices.strings.install_content + * @param wpforms_builder.icon_choices.strings.install_error_content + * @param wpforms_builder.icon_choices.strings.install_prompt_content + * @param wpforms_builder.icon_choices.strings.install_success_content + * @param wpforms_builder.icon_choices.strings.install_title + * @param wpforms_builder.icon_choices.strings.reinstall_prompt_content + * @param wpforms_builder.layout_selector_column + * @param wpforms_builder.layout_selector_hide + * @param wpforms_builder.layout_selector_layout + * @param wpforms_builder.layout_selector_show + * @param wpforms_builder.notification_by_status_enable_alert + * @param wpforms_builder.notification_by_status_switch_alert + * @param wpforms_builder.number_slider_error_valid_default_value + * @param wpforms_builder.payment_choice_empty_label_tpl + * @param wpforms_builder.preview_url + * @param wpforms_builder.pro + * @param wpforms_builder.redirect_url_field_error + * @param wpforms_builder.restricted_default_email + * @param wpforms_builder.restricted_rules + * @param wpforms_builder.revision_update_confirm + * @param wpforms_builder.save_exit + * @param wpforms_builder.scrollbars_css_url + * @param wpforms_builder.select_choice + * @param wpforms_builder.shortcuts_modal_msg + * @param wpforms_builder.shortcuts_modal_title + * @param wpforms_builder.smart_tags_disabled_for_confirmations + * @param wpforms_builder.smart_tags_dropdown_mce_icon + * @param wpforms_builder.smart_tags_hide + * @param wpforms_builder.smart_tags_show + * @param wpforms_builder.something_went_wrong + * @param wpforms_builder.template_modal_msg + * @param wpforms_builder.template_modal_title + * @param wpforms_builder.upload_image_button + * @param wpforms_builder.upload_image_extensions + * @param wpforms_builder.upload_image_extensions_error + * @param wpforms_builder.upload_image_remove + * @param wpforms_builder.upload_image_title + * @param wpforms_builder.wpforms_builder.bulk_add_presets_hide + */ + +/* noinspection JSUnusedLocalSymbols */ +/* eslint-disable no-unused-expressions, no-shadow */ + +// noinspection ES6ConvertVarToLetConst +var WPFormsBuilder = window.WPFormsBuilder || ( function( document, window, $ ) { // eslint-disable-line no-var + let s, + $builder; + const elements = {}, + browser = {}; + + /** + * Whether to show the close confirmation dialog or not. + * + * @since 1.6.0 + * + * @type {boolean} + */ + let closeConfirmation = true; + + /** + * A field is adding. + * + * @since 1.7.1 + * + * @type {boolean} + */ + let adding = false; + + /** + * Preview tab. + * + * @since 1.9.4 + * + * @type {Window|null} + */ + let previewTab = null; + + // noinspection JSUnusedGlobalSymbols + const app = { + /** + * @typedef {Object} JQ + * @property {(selector: string) => JQ} closest Closest function. + * @property {(prop: string) => string} css Css function. + * @property {(prop: string) => string} data Data function. + * @property {() => JQ} fadeIn FadeIn function. + * @property {(selector: string) => JQ} find Find function. + * @property {(text: string) => undefined} insertAtCaret InsertAtCaret function. + * @property {(selector: string) => JQ} next Next function. + * @property {() => JQ} slideDown SlideDown function. + * @property {() => JQ} slideToggle SlideToggle function. + * @property {() => JQ} slideUp SlideUp function. + * @property {() => JQ} stop Stop function. + */ + + /** + * @param {(selector: string) => JQ} $ The jQuery-compatible function. + */ + + /** + * @typedef {Object} jqXHR + * @property {(callback: (data: any, textStatus: string, jqXHR: jqXHR) => void) => jqXHR} done Done function. + */ + + /** + * @typedef {Object} Options + * @property {string|number} position Position. + */ + + /** + * @typedef {Object} Modal + * @property {jQuery} $title Title. + * @property {jQuery} $content Content. + */ + + /* eslint-disable camelcase */ + + settings: { + spinner: '', + spinnerInline: '', + tinymceDefaults: { + tinymce: { toolbar1: 'bold,italic,underline,blockquote,strikethrough,bullist,numlist,alignleft,aligncenter,alignright,undo,redo,link' }, + quicktags: true, + }, + pagebreakTop: false, + pagebreakBottom: false, + upload_img_modal: false, + choicesLimit: 20, // Choices limit for fields different from Dropdown. + choicesLimitLong: 250, // Choices limit for Dropdown field. + }, + + /** + * Start the engine. + * + * @since 1.0.0 + */ + init() { + const that = this; + + wpforms_panel_switch = true; + s = this.settings; + + // Document ready. + $( app.ready ); + + // Page load. + $( window ).on( 'load', function() { + // In the case of jQuery 3.+, we need to wait for a ready event first. + if ( typeof $.ready.then === 'function' ) { + $.ready.then( app.load ); + } else { + app.load(); + } + } ); + + $( window ).on( 'beforeunload', function() { + if ( ! that.formIsSaved() && closeConfirmation ) { + return wpforms_builder.are_you_sure_to_close; + } + } ); + }, + + /** + * Page load. + * + * @since 1.0.0 + * @since 1.7.9 Added `wpformsBuilderReady` hook. + * + * @return {false|void} False if default event is prevented. + */ + load() { + // Trigger initial save for new forms. + if ( wpf.getQueryString( 'newform' ) ) { + app.formSave( false ); + } + + const panel = $( '#wpforms-panels-toggle .active' ).data( 'panel' ); + + // Render form preview on the Revisions panel if the panel is active. + if ( panel === 'revisions' ) { + app.updateRevisionPreview(); + } + + // Allow callbacks to prevent making Form Builder ready... + const event = WPFormsUtils.triggerEvent( $builder, 'wpformsBuilderReady' ); + + // ...by triggering `event.preventDefault()`. + if ( event.isDefaultPrevented() ) { + return false; + } + + // Hide the loading overlay and make the Form Builder ready to use. + app.hideLoadingOverlay(); + + app.determineActiveSections(); + + // Confirmations' initial setup. + app.confirmationsSetup(); + + WPFormsUtils.triggerEvent( $builder, 'wpformsBuilderConfirmationsReady' ); + + app.loadMsWinCSS(); + + // Maybe display informational modal. + + // noinspection JSUnresolvedReference, EqualityComparisonWithCoercionJS + if ( wpforms_builder.template_modal_display == '1' && 'fields' === wpf.getQueryString( 'view' ) ) { // eslint-disable-line + $.alert( { + title: wpforms_builder.template_modal_title, + content: wpforms_builder.template_modal_msg, + icon: 'fa fa-info-circle', + type: 'blue', + buttons: { + confirm: { + text: wpforms_builder.close, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + }, + }, + } ); + } + + wpf._updateFormState(); + }, + + /** + * Init elements cache. + * + * @since 1.9.2 + */ + initElementsCache() { + // Cache builder element. + $builder = $( '#wpforms-builder' ); + + browser.isWindows = /Win/.test( navigator.userAgent ); + browser.isLinux = /Linux/.test( navigator.userAgent ); + browser.isMac = /Mac/.test( navigator.userAgent ); + + // Action buttons. + elements.$helpButton = $( '.js-wpforms-help' ); + elements.$previewButton = $( '#wpforms-preview-btn' ); + elements.$embedButton = $( '#wpforms-embed' ); + elements.$saveButton = $( '#wpforms-save' ); + elements.$exitButton = $( '#wpforms-exit' ); + + // Cache other elements. + elements.$noFieldsOptions = $( '#wpforms-panel-fields .wpforms-no-fields-holder .no-fields' ); + elements.$noFieldsPreview = $( '#wpforms-panel-fields .wpforms-no-fields-holder .no-fields-preview' ); + elements.$formPreview = $( '#wpforms-panel-fields .wpforms-preview-wrap' ); + elements.$revisionPreview = $( '#wpforms-panel-revisions .wpforms-panel-content' ); + elements.defaultEmailSelector = '.wpforms-field-option-email .wpforms-field-option-row-default_value input'; + elements.$defaultEmail = $( elements.defaultEmailSelector ); + elements.$focusOutTarget = null; + + elements.$nextFieldId = $( '#wpforms-field-id' ); + elements.$addFieldsTab = $( '#add-fields a' ); + elements.$fieldOptions = $( '#wpforms-field-options' ); + elements.$fieldsPreviewWrap = $( '#wpforms-panel-fields .wpforms-panel-content-wrap' ); + elements.$sortableFieldsWrap = $( '#wpforms-panel-fields .wpforms-field-wrap' ); + elements.$addFieldsButtons = $( '.wpforms-add-fields-button' ).not( '.not-draggable' ).not( '.warning-modal' ).not( '.education-modal' ); + elements.$fieldsSidebar = $( '#wpforms-panel-fields .wpforms-add-fields' ); + elements.$searchInput = $( '#wpforms-search-fields-input' ); + elements.$sidebarToggle = $( '.wpforms-panels .wpforms-panel-sidebar-content .wpforms-panel-sidebar-toggle' ); + }, + + /** + * Document ready. + * + * @since 1.0.0 + */ + ready() { // eslint-disable-line max-lines-per-function + if ( app.isVisitedViaBackButton() ) { + location.reload(); + + return; + } + + app.initElementsCache(); + + // Add `_wp_http_referer` to the data of every AJAX request. + $.ajaxSetup( { + data: { + // eslint-disable-next-line camelcase + _wp_http_referer: wpf.updateQueryString( '_wp_http_referer', null ), + }, + } ); + + // Remove Embed button if builder opened in the popup. + if ( app.isBuilderInPopup() ) { + elements.$embedButton.remove(); + elements.$previewButton.addClass( 'wpforms-alone' ); + } + + // Bind all actions. + app.bindUIActions(); + + // Setup/cache some vars not available before + s.formID = $( '#wpforms-builder-form' ).data( 'id' ); + s.pagebreakTop = $( '.wpforms-pagebreak-top' ).length; + s.pagebreakBottom = $( '.wpforms-pagebreak-bottom' ).length; + + // Disable implicit submission for every form inside the builder. + // All form values are managed by JS and should not be submitted by pressing Enter. + $builder.on( 'keypress', '#wpforms-builder-form :input:not(textarea)', function( e ) { + if ( e.keyCode === 13 ) { + e.preventDefault(); + } + } ); + + app.loadEntryPreviewFields(); + + // Drag and drop sortable elements. + app.fieldChoiceSortable( 'select' ); + app.fieldChoiceSortable( 'radio' ); + app.fieldChoiceSortable( 'checkbox' ); + app.fieldChoiceSortable( 'payment-multiple' ); + app.fieldChoiceSortable( 'payment-checkbox' ); + app.fieldChoiceSortable( 'payment-select' ); + + // Set field group visibility. + $( '.wpforms-add-fields-group' ).each( function() { + app.fieldGroupToggle( $( this ), 'load' ); + } ); + + app.registerTemplates(); + + // Trim long form titles. + app.trimFormTitle(); + + // Load Tooltips. + wpf.initTooltips(); + + // Load Color Pickers. + app.loadColorPickers(); + + // Hide/Show CAPTCHA in form. + app.captchaToggle(); + + // Notification settings. + app.notificationToggle(); + app.notificationsByStatusAlerts(); + + // Secret builder hotkeys. + app.builderHotkeys(); + + // jquery-confirm defaults. + jconfirm.defaults = { + closeIcon: false, + backgroundDismiss: false, + escapeKey: true, + animationBounce: 1, + useBootstrap: false, + theme: 'modern', + boxWidth: '400px', + animateFromElement: false, + content: wpforms_builder.something_went_wrong, + }; + + app.dropdownField.init(); + + app.iconChoices.init(); + + app.disabledFields.init(); + + app.checkEmptyDynamicChoices(); + + app.initSomeFieldOptions(); + + app.dismissNotice(); + + wpf.initializeChoicesEventHandlers(); + }, + + checkEmptyDynamicChoices() { + const choices = wpf.orders.choices || {}; + + if ( ! Object.keys( choices ).length ) { + return; + } + + wpf.orders.fields.forEach( function( fieldId ) { + const isDynamic = app.dropdownField.helpers.isDynamicChoices( fieldId ); + + if ( ! isDynamic ) { + return; + } + + const $fieldPreview = $( '#wpforms-field-' + fieldId ); + const type = app.dropdownField.helpers.getDynamicChoicesOptionType( fieldId ); + const source = app.dropdownField.helpers.getDynamicChoicesOptionSource( fieldId ); + const isModern = app.dropdownField.helpers.isDynamicChoicesOptionModern( fieldId ); + let isEmpty = isModern + ? $fieldPreview.find( '.has-no-choices' ).length + : $fieldPreview.find( '.primary-input option:not(.placeholder), .primary-input li' ).length === 0; + + if ( isModern && ! isEmpty ) { + const placeholder = $( '#wpforms-field-option-' + fieldId + '-placeholder' ).val(); + const choices = app.dropdownField.helpers.getInitialChoices( fieldId ); + isEmpty = choices.length === 1 && choices[ 0 ].label === placeholder && choices[ 0 ].placeholder === true; + } + + if ( isEmpty ) { + app.emptyChoicesNotice( fieldId, source, type ); + } + } ); + }, + + /** + * Load Microsoft Windows specific stylesheet. + * + * @since 1.6.8 + */ + loadMsWinCSS() { + // Detect OS & browsers. + if ( browser.isMac ) { + return; + } + + // language=HTML + $( '' ) + .appendTo( 'head' ) + .attr( { + type: 'text/css', + rel: 'stylesheet', + href: wpforms_builder.scrollbars_css_url, + } ); + }, + + /** + * Builder was visited via the back button in the browser. + * + * @since 1.6.5 + * + * @return {boolean} True if the builder was visited via back button in browser. + */ + isVisitedViaBackButton() { + if ( ! performance ) { + return false; + } + + let isVisitedViaBackButton = false; + + performance.getEntriesByType( 'navigation' ).forEach( function( nav ) { + if ( nav.type === 'back_forward' ) { + isVisitedViaBackButton = true; + } + } ); + + return isVisitedViaBackButton; + }, + + /** + * Remove loading overlay. + * + * @since 1.6.8 + */ + hideLoadingOverlay() { + const $overlay = $( '#wpforms-builder-overlay' ); + + $overlay.addClass( 'fade-out' ); + + setTimeout( function() { + $overlay.hide(); + }, 250 ); + }, + + /** + * Show loading overlay. + * + * @since 1.6.8 + */ + showLoadingOverlay() { + const $overlay = $( '#wpforms-builder-overlay' ); + + $overlay.removeClass( 'fade-out' ); + $overlay.show(); + }, + + /** + * Initialize some fields options controls. + * + * @since 1.6.3 + */ + initSomeFieldOptions() { + // Show a toggled options group. + app.toggleAllOptionGroups( $builder ); + + // Date/Time field Date type option. + $builder.find( '.wpforms-field-option-row-date .type select' ).trigger( 'change' ); + + // Read-Only + Required field options init. + $builder.find( '.wpforms-field-option-row-read_only input:checked' ).trigger( 'change' ); + }, + + /** + * Dropdown field component. + * + * @since 1.6.1 + */ + dropdownField: { + + /** + * Field configuration. + * + * @since 1.6.1 + */ + config: { + modernClass: 'choicesjs-select', + args: { + searchEnabled: false, + searchChoices: false, + renderChoiceLimit: 1, + shouldSort: false, + callbackOnInit() { + const $element = $( this.containerOuter.element ), + $previewSelect = $element.closest( '.wpforms-field' ).find( 'select' ); + + // Turn off disabled styles. + if ( $element.hasClass( 'is-disabled' ) ) { + $element.removeClass( 'is-disabled' ); + } + + // Disable instances on the preview panel. + if ( $previewSelect.is( '[readonly]' ) ) { + this.disable(); + $previewSelect.prop( 'disabled', false ); + } + + if ( this.passedElement.element.multiple ) { + // Hide a placeholder if the field has selected choices. + if ( this.getValue( true ).length ) { + $( this.input.element ).addClass( 'choices__input--hidden' ); + } + } + + // Decode allowed HTML entities for choices. + $element.find( '.choices__item--selectable' ).each( function() { + const $choice = $( this ); + const text = wpf.decodeAllowedHTMLEntities( $choice.text() ); + + $choice.text( text ); + } ); + }, + }, + }, + + /** + * Initialization for a field component. + * + * @since 1.6.1 + */ + init() { + // Choices.js init. + $builder.find( '.' + app.dropdownField.config.modernClass ).each( function() { + app.dropdownField.events.choicesInit( $( this ) ); + } ); + + // Multiple option. + $builder.on( + 'change', + '.wpforms-field-option-select .wpforms-field-option-row-multiple input', + app.dropdownField.events.multiple + ); + + // Style option. + $builder.on( + 'change', + '.wpforms-field-option-select .wpforms-field-option-row-style select, .wpforms-field-option-payment-select .wpforms-field-option-row-style select', + app.dropdownField.events.applyStyle + ); + + // Add the ability to close the drop-down menu. + $builder.on( 'click', '.choices', function( e ) { + const $choices = $( this ), + choicesObj = $choices.find( 'select' ).data( 'choicesjs' ); + + if ( + choicesObj && + $choices.hasClass( 'is-open' ) && + e.target.classList.contains( 'choices__inner' ) + ) { + choicesObj.hideDropdown(); + } + } ); + }, + + /** + * Field events. + * + * @since 1.6.1 + */ + events: { + + /** + * Load Choices.js library. + * + * @since 1.6.1 + * + * @param {Object} $element jQuery element selector. + */ + choicesInit( $element ) { + const useAjax = $element.data( 'choicesjs-use-ajax' ) === 1; + let instance; + + if ( $element.data( 'choicesjs-callback-fn' ) === 'select_pages' ) { + instance = WPForms.Admin.Builder.WPFormsChoicesJS.setup( + $element[ 0 ], + app.dropdownField.config.args, + { + action: 'wpforms_ajax_search_pages_for_dropdown', + nonce: useAjax ? wpforms_builder.nonce : null, + } + ); + } else { + instance = new Choices( $element[ 0 ], app.dropdownField.config.args ); + } + + app.dropdownField.helpers.setInstance( $element, instance ); + app.dropdownField.helpers.addPlaceholderChoice( $element, instance ); + + $element.closest( '.choices' ).toggleClass( 'wpforms-hidden', ! instance.config.choices.length ); + }, + + /** + * Multiple option callback. + * + * @since 1.6.1 + * + * @param {Object} event Event object. + */ + multiple( event ) { + const fieldId = $( this ).closest( '.wpforms-field-option-row-multiple' ).data().fieldId, + $primary = app.dropdownField.helpers.getPrimarySelector( fieldId ), + $optionChoicesItems = $( `#wpforms-field-option-row-${ fieldId }-choices input.default` ), + $placeholder = $primary.find( '.placeholder' ), + isDynamicChoices = app.dropdownField.helpers.isDynamicChoices( fieldId ), + isMultiple = event.target.checked, + choicesType = isMultiple ? 'checkbox' : 'radio'; + + // Add/remove a `multiple` attribute. + $primary.prop( 'multiple', isMultiple ); + + // Change a `Choices` fields type: + // checkbox - needed for multiple selection + // radio - needed for single selection + $optionChoicesItems.prop( 'type', choicesType ); + + // Dynamic Choices doesn't have default choices (selected options) - make all as unselected. + if ( isDynamicChoices ) { + $primary.find( 'option:selected' ).prop( 'selected', false ); + } + + // Gets default choices. + const selectedChoices = $optionChoicesItems.filter( ':checked' ); + + if ( ! isMultiple && selectedChoices.length ) { + // Uncheck all choices. + $optionChoicesItems.prop( 'checked', false ); + + // For a single selection, we can choose only one. + $( selectedChoices.get( 0 ) ).prop( 'checked', true ); + } + + // Toggle selection for a placeholder option based on a select type. + if ( $placeholder.length ) { + $placeholder.prop( 'selected', ! isMultiple ); + } + + // Update a primary field. + app.dropdownField.helpers.update( fieldId, isDynamicChoices ); + }, + + /** + * Apply a style to . + * + * @since 1.6.1 + * + * @param {string} fieldId Field ID. + */ + convertModernToClassic: ( fieldId ) => { + const $primary = app.dropdownField.helpers.getPrimarySelector( fieldId ), + isDynamicChoices = app.dropdownField.helpers.isDynamicChoices( fieldId ), + instance = app.dropdownField.helpers.getInstance( $primary ), + $sidebarChoices = $( '#wpforms-field-option-row-' + fieldId + '-choices' ), + $sidebarList = $sidebarChoices.find( '.choices-list' ), + elementsCount = $sidebarList.find( 'li' ).length; + + if ( instance && typeof instance.destroy === 'function' ) { + // Destroy the instance of Choices.js. + instance.destroy(); + + // Update a placeholder. + app.dropdownField.helpers.updatePlaceholderChoice( instance, fieldId ); + } + + // Update choices. + if ( ! isDynamicChoices ) { + app.fieldChoiceUpdate( 'select', fieldId, elementsCount ); + } + }, + + /** + * Get initial choices. + * + * @since 1.8.2 + * + * @param {string} fieldId Field ID. + * + * @return {Object} Choices. + */ + getInitialChoices( fieldId ) { + const $primary = app.dropdownField.helpers.getPrimarySelector( fieldId ), + instance = app.dropdownField.helpers.getInstance( $primary ); + + return instance.config.choices; + }, + + /** + * Convert a Classic to Modern style selector. + * + * @since 1.6.1 + * + * @param {string} fieldId Field ID. + */ + convertClassicToModern( fieldId ) { + const $primary = app.dropdownField.helpers.getPrimarySelector( fieldId ), + isDynamicChoices = app.dropdownField.helpers.isDynamicChoices( fieldId ); + + // Update choices. + if ( ! isDynamicChoices ) { + app.fieldChoiceUpdate( 'select', fieldId ); + } + + // Call a Choices.js initialization. + app.dropdownField.events.choicesInit( $primary ); + }, + + /** + * Update a primary field. + * + * @since 1.6.1 + * + * @param {string} fieldId Field ID. + * @param {boolean} isDynamicChoices True if `Dynamic Choices` is turned on. + */ + update( fieldId, isDynamicChoices ) { + const $primary = app.dropdownField.helpers.getPrimarySelector( fieldId ); + + if ( app.dropdownField.helpers.isModernSelect( $primary ) ) { + // If we had a `Modern` `select` before, then we need to make re-init - destroy() + init(). + app.dropdownField.helpers.convertModernToClassic( fieldId ); + + if ( ! isDynamicChoices ) { + app.dropdownField.events.choicesInit( $primary ); + } + } else if ( ! isDynamicChoices ) { + // Update choices. + app.fieldChoiceUpdate( 'select', fieldId ); + } + }, + + /** + * Add a new choice to behave like a placeholder. + * + * @since 1.6.1 + * + * @param {Object} $jquerySelector jQuery primary selector. + * @param {Object} instance The instance of Choices.js. + * + * @return {boolean} False if a fake placeholder wasn't added. + */ + addPlaceholderChoice( $jquerySelector, instance ) { // eslint-disable-line complexity + const wpFormsField = $jquerySelector.closest( '.wpforms-field' ); + if ( wpFormsField.length <= 0 ) { + return false; + } + + const fieldId = wpFormsField.data().fieldId; + let hasDefaults = app.dropdownField.helpers.hasDefaults( fieldId ); + + if ( app.dropdownField.helpers.isDynamicChoices( fieldId ) ) { + hasDefaults = false; + } + + // Already has a placeholder. + if ( false !== app.dropdownField.helpers.searchPlaceholderChoice( instance ) ) { + return false; + } + + // No choices. + if ( ! instance.config.choices.length ) { + return false; + } + + const placeholder = $( '#wpforms-field-option-' + fieldId + '-placeholder' ).val(), + sanitizedPlaceholder = wpf.decodeAllowedHTMLEntities( placeholder ), + isMultiple = $( instance.passedElement.element ).prop( 'multiple' ), + selected = ! ( isMultiple || hasDefaults ); + + // Add a new choice as a placeholder. + instance.setChoices( + [ + { value: '', label: sanitizedPlaceholder, selected, placeholder: true }, + ], + 'value', + 'label', + false + ); + + // Additional case for multiple select. + if ( isMultiple ) { + $( instance.input.element ).prop( 'placeholder', placeholder ); + } + + return true; + }, + + /** + * Search a choice-placeholder item. + * + * @since 1.6.1 + * + * @param {Object} instance The instance of Choices.js. + * + * @return {boolean|object} False if a field doesn't have a choice-placeholder. + * Otherwise - return choice item. + */ + searchPlaceholderChoice( instance ) { + let find = false; + + instance.config.choices.forEach( function( item, i ) { + if ( 'undefined' !== typeof item.placeholder && true === item.placeholder ) { + find = { + key: i, + item, + }; + + return false; + } + } ); + + return find; + }, + + /** + * Add/update a placeholder. + * + * @since 1.6.1 + * + * @param {Object} instance The instance of Choices.js. + * @param {string} fieldId Field ID. + */ + updatePlaceholderChoice( instance, fieldId ) { + const $primary = $( instance.passedElement.element ), + placeholderValue = wpf.sanitizeHTML( $( '#wpforms-field-option-' + fieldId + '-placeholder' ).val() ), + placeholderChoice = app.dropdownField.helpers.searchPlaceholderChoice( instance ); + let $placeholderOption = {}; + + // Get an option with placeholder. + // Note: `.placeholder` class is skipped when calling Choices.js destroy() method. + if ( 'object' === typeof placeholderChoice ) { + $placeholderOption = $( $primary.find( 'option' ).get( placeholderChoice.key ) ); + } + + // We have a placeholder and need to update the UI with it. + if ( '' !== placeholderValue ) { + if ( ! $.isEmptyObject( $placeholderOption ) && $placeholderOption.length ) { + // Update a placeholder option. + $placeholderOption + .addClass( 'placeholder' ) + .text( placeholderValue ); + } else { + // Add a placeholder option. + $primary.prepend( '' ); + } + } else if ( $placeholderOption.length ) { + // Remove the placeholder as it's empty. + $placeholderOption.remove(); + } + }, + + /** + * Is it a `Modern` style dropdown field? + * + * @since 1.6.1 + * + * @param {Object} $jquerySelector jQuery primary selector. + * + * @return {boolean} True if it's a `Modern` style select, false otherwise. + */ + isModernSelect( $jquerySelector ) { + const instance = app.dropdownField.helpers.getInstance( $jquerySelector ); + + if ( 'object' !== typeof instance ) { + return false; + } + + if ( $.isEmptyObject( instance ) ) { + return false; + } + + return instance.initialised; + }, + + /** + * Save an instance of Choices.js. + * + * @since 1.6.1 + * + * @param {Object} $jquerySelector jQuery primary selector. + * @param {Object} instance The instance of Choices.js. + */ + setInstance( $jquerySelector, instance ) { + $jquerySelector.data( 'choicesjs', instance ); + }, + + /** + * Retrieve an instance of Choices.js. + * + * @since 1.6.1 + * + * @param {Object} $jquerySelector jQuery primary selector. + * + * @return {Object} The instance of Choices.js. + */ + getInstance( $jquerySelector ) { + return $jquerySelector.data( 'choicesjs' ); + }, + + /** + * Get the Dynamic Choices option field. + * + * @since 1.8.2 + * + * @param {string|number} fieldId Field ID. + * + * @return {HTMLElement|boolean} False if a field doesn't have a `Dynamic Choices` option. + * Otherwise - return option field. + */ + getDynamicChoicesOption( fieldId ) { + const $fieldOption = $( '#wpforms-field-option-' + fieldId + '-dynamic_choices' ); + + if ( ! $fieldOption.length ) { + return false; + } + + return $fieldOption; + }, + + /** + * Is `Dynamic Choices` used? + * + * @since 1.6.1 + * + * @param {string|number} fieldId Field ID. + * + * @return {boolean} True if a `Dynamic Choices` are active, false otherwise. + */ + isDynamicChoices( fieldId ) { + const $fieldOption = app.dropdownField.helpers.getDynamicChoicesOption( fieldId ); + + if ( ! $fieldOption.length ) { + return false; + } + + return '' !== $fieldOption.val(); + }, + + /** + * Whether the `Dynamic Choices` option type is `Modern`? + * + * @since 1.8.2 + * + * @param {string|number} fieldId Field ID. + * @return {boolean} True if a `Dynamic Choices` option type is `Modern`, false otherwise. + */ + isDynamicChoicesOptionModern( fieldId ) { + const $fieldOption = $( '#wpforms-field-option-' + fieldId + '-style' ); + + if ( ! $fieldOption.length ) { + return false; + } + + return $fieldOption.val() === 'modern'; + }, + + /** + * Get a Dynamic Choices option type. + * + * @since 1.8.2 + * + * @param {string|number} fieldId Field ID. + * + * @return {string|boolean} False if a field doesn't have a `Dynamic Choices` option. + * Otherwise - return an option type. + */ + getDynamicChoicesOptionType( fieldId ) { + const $fieldOption = app.dropdownField.helpers.getDynamicChoicesOption( fieldId ); + + if ( ! $fieldOption.length ) { + return false; + } + + return $fieldOption.val(); + }, + + /** + * Get a Dynamic Choices option source. + * + * @since 1.8.2 + * + * @param {string|number} fieldId Field ID. + * + * @return {string|boolean} False if a field doesn't have a `Dynamic Choices` option. + * Otherwise - return an option source. + */ + getDynamicChoicesOptionSource( fieldId ) { + const type = app.dropdownField.helpers.getDynamicChoicesOptionType( fieldId ); + const $fieldOption = $( '#wpforms-field-option-' + fieldId + '-dynamic_' + type ); + + if ( ! $fieldOption.length ) { + return false; + } + + return $fieldOption.find( 'option:selected' ).text(); + }, + + /** + * Is a field having default choices? + * + * @since 1.6.1 + * + * @param {string} fieldId Field ID. + * + * @return {boolean} True if a field has default choices. + */ + hasDefaults( fieldId ) { + const $choicesList = $( `#wpforms-field-option-row-${ fieldId }-choices .choices-list` ); + + return !! $choicesList.find( 'input.default:checked' ).length; + }, + + /** + * Retrieve a jQuery selector for the Primary field. + * + * @since 1.6.1 + * + * @param {string} fieldId Field ID. + * + * @return {Object} jQuery primary selector. + */ + getPrimarySelector( fieldId ) { + return $( '#wpforms-field-' + fieldId + ' .primary-input' ); + }, + }, + }, + + /** + * Add number slider events listeners. + * + * @since 1.5.7 + * + * @param {Object} $builder JQuery object. + */ + numberSliderEvents( $builder ) { + // Minimum update. + $builder.on( + 'focusout', + '.wpforms-field-option-row-min_max .wpforms-input-row .wpforms-number-slider-min', + app.fieldNumberSliderUpdateMin + ); + + // Maximum update. + $builder.on( + 'focusout', + '.wpforms-field-option-row-min_max .wpforms-input-row .wpforms-number-slider-max', + app.fieldNumberSliderUpdateMax + ); + + // Change default input value. + $builder.on( + 'input', + '.wpforms-number-slider-default-value', + _.debounce( app.changeNumberSliderDefaultValue, 500 ) + ); + + // Change the default input value if it's empty. + $builder.on( + 'focusout', + '.wpforms-number-slider-default-value', + app.changeNumberSliderEmptyDefaultValue + ); + + // Trigger the input event on default value input to check if it's valid. + $builder.find( '.wpforms-number-slider-default-value' ).trigger( 'input' ); + + // Change step value. + $builder.on( + 'input', + '.wpforms-number-slider-step', + _.debounce( app.changeNumberSliderStep, 500 ) + ); + + // Check step value. + $builder.on( + 'focusout', + '.wpforms-number-slider-step', + app.checkNumberSliderStep + ); + + // Change value display. + $builder.on( + 'input', + '.wpforms-number-slider-value-display', + _.debounce( app.changeNumberSliderValueDisplay, 500 ) + ); + + // Change min value. + $builder.on( + 'input', + '.wpforms-number-slider-min', + _.debounce( app.changeNumberSliderMin, 500 ) + ); + + // Change max value. + $builder.on( + 'input', + '.wpforms-number-slider-max', + _.debounce( app.changeNumberSliderMax, 500 ) + ); + }, + + /** + * Change number slider min option. + * + * @since 1.5.7 + * + * @param {Object} event Input event. + */ + changeNumberSliderMin( event ) { + const value = parseFloat( event.target.value ); + + if ( isNaN( value ) ) { + return; + } + + const fieldID = $( event.target ).parents( '.wpforms-field-option-row' ).data( 'fieldId' ); + + app.updateNumberSliderDefaultValueAttr( fieldID, event.target.value, 'min' ); + }, + + /** + * Change number slider max option. + * + * @since 1.5.7 + * + * @param {Object} event Input event. + */ + changeNumberSliderMax( event ) { + const value = parseFloat( event.target.value ); + + if ( isNaN( value ) ) { + return; + } + + const fieldID = $( event.target ).parents( '.wpforms-field-option-row' ).data( 'fieldId' ); + + app.updateNumberSliderDefaultValueAttr( fieldID, event.target.value, 'max' ) + .updateNumberSliderStepValueMaxAttr( fieldID, event.target.value ); + }, + + /** + * Change number slider value display option. + * + * @since 1.5.7 + * + * @param {Object} event Input event. + */ + changeNumberSliderValueDisplay( event ) { + const str = event.target.value; + const fieldID = $( event.target ).parents( '.wpforms-field-option-row' ).data( 'fieldId' ); + const defaultValue = document.getElementById( 'wpforms-field-option-' + fieldID + '-default_value' ); + + if ( defaultValue ) { + app.updateNumberSliderHintStr( fieldID, str ) + .updateNumberSliderHint( fieldID, defaultValue.value ); + } + }, + + /** + * Change the number slider step option. + * + * @since 1.5.7 + * + * @param {Object} event Input event. + */ + changeNumberSliderStep( event ) { + const $el = $( this ); + const value = parseFloat( $el.val() ); + + if ( isNaN( value ) ) { + return; + } + + if ( value <= 0 ) { + return; + } + + const $options = $( $el ).closest( '.wpforms-field-option' ); + const max = parseFloat( $options.find( '.wpforms-number-slider-max' ).val() ); + const min = parseFloat( $options.find( '.wpforms-number-slider-min' ).val() ); + const maxStep = ( max - min ).toFixed( 2 ); + + if ( value > maxStep ) { + event.target.value = maxStep; + $el.trigger( 'input' ); + + return; + } + + const fieldID = $( event.target ).parents( '.wpforms-field-option-row' ).data( 'fieldId' ); + const defaultValue = $( '#wpforms-field-option-' + fieldID + '-default_value' ).val(); + + app.checkMultiplicitySliderDefaultValue( fieldID, defaultValue, value, min, max ) + .updateNumberSliderAttr( fieldID, value, 'step' ) + .updateNumberSliderDefaultValueAttr( fieldID, value, 'step' ); + }, + + /** + * Check multiplicity of a slider default value. + * + * @since 1.8.4 + * + * @param {string} fieldId Field ID. + * @param {number} value Default value. + * @param {number} step Step value. + * @param {number} min Min value. + * @param {number} max Max value. + * + * @return {Object} App instance. + */ + checkMultiplicitySliderDefaultValue( fieldId, value, step, min = 0, max = 0 ) { + const $printSelector = $( `#wpforms-field-option-row-${ fieldId }-default_value` ); + value = parseFloat( value ); + + if ( ( value - min ) % step === 0 ) { + app.removeNotice( $printSelector ); + + return this; + } + + const { + closestSmallerMultiple, + closestLargerMultiple, + } = this.calculateClosestMultiples( value, step, min, max ); + + const formatNumber = ( num ) => ( num % 1 === 0 ? num.toString() : num.toFixed( 2 ) ); + + const normalizedValue = formatNumber( value ); + const normalizedSmaller = formatNumber( closestSmallerMultiple ); + const normalizedLarger = formatNumber( closestLargerMultiple ); + + if ( normalizedSmaller === normalizedLarger || + normalizedSmaller === normalizedValue || + normalizedLarger === normalizedValue + ) { + app.removeNotice( $printSelector ); + return this; + } + + const updatedMessage = wpforms_builder.number_slider_error_valid_default_value + .replace( '{from}', normalizedSmaller ) + .replace( '{to}', normalizedLarger ); + + app.printNotice( updatedMessage, $printSelector ); + + return this; + }, + + /** + * Calculate the closest multiples for a value. + * + * @since 1.9.5 + * + * @param {number} value Default value. + * @param {number} step Step value. + * @param {number} min Min value. + * @param {number} max Max value. + * + * @return {Object} Closest smaller and larger multiples. + */ + // eslint-disable-next-line complexity + calculateClosestMultiples( value, step, min, max ) { + // Calculate the closest smaller value. + let closestSmallerMultiple = min + ( Math.floor( ( value - min ) / step ) * step ); + + // Calculate the closest larger value. + let closestLargerMultiple = min + ( Math.ceil( ( value - min ) / step ) * step ); + + // Handle edge cases where the value is exactly on a step. + if ( value === closestSmallerMultiple && value !== min ) { + closestLargerMultiple = closestSmallerMultiple + step; + } + + if ( value === closestLargerMultiple && value !== max ) { + closestSmallerMultiple = closestLargerMultiple - step; + } + + // Handle edge cases when the value is min or max + if ( value === min ) { + closestLargerMultiple = min + step; + } + if ( value === max ) { + closestSmallerMultiple = max - step; + } + + // Ensure the closest values stay within the min and max bounds. + closestSmallerMultiple = Math.max( closestSmallerMultiple, min ); + closestLargerMultiple = Math.min( closestLargerMultiple, max ); + + return { closestSmallerMultiple, closestLargerMultiple }; + }, + + /** + * Print a notice. + * + * @since 1.8.4 + * + * @param {string} message Message to print. + * @param {Object} $printSelector jQuery element selector. + * @param {boolean} wide Wide notice flag, optional, default is false. + */ + printNotice( message, $printSelector, wide = false ) { + if ( $printSelector.length ) { + this.removeNotice( $printSelector ); + + const wideClass = wide ? 'wpforms-alert-warning-wide' : ''; + + $printSelector.append( `

${ message }

` ); + } + }, + + /** + * Remove a notice. + * + * @since 1.8.4 + * + * @param {Object} $printSelector jQuery element selector. + */ + removeNotice( $printSelector ) { + if ( $printSelector.length && $printSelector.find( '.wpforms-alert' ).length ) { + $printSelector.find( '.wpforms-alert' ).remove(); + } + }, + + /** + * Check the number slider step option. + * + * @since 1.6.2.3 + * + * @param {Object} event Focusout event object. + */ + checkNumberSliderStep( event ) { + const value = parseFloat( event.target.value ); + + if ( ! isNaN( value ) && value > 0 ) { + return; + } + + const $input = $( this ); + + $.confirm( { + title: wpforms_builder.heads_up, + content: wpforms_builder.error_number_slider_increment, + icon: 'fa fa-exclamation-circle', + type: 'orange', + buttons: { + confirm: { + text: wpforms_builder.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + action() { + $input.val( '' ).trigger( 'focus' ); + }, + }, + }, + } ); + }, + + /** + * Update number slider default value if it's empty. + * + * @since 1.9.3 + * + * @param {Object} event Input event. + */ + changeNumberSliderEmptyDefaultValue( event ) { + const value = parseFloat( event.target.value ); + + if ( isNaN( value ) ) { + const newValue = parseFloat( event.target.min ); + event.target.value = newValue; + + const step = parseFloat( event.target.step ); + const min = parseFloat( event.target.min ); + const max = parseFloat( event.target.max ); + const fieldID = $( event.target ).parents( '.wpforms-field-option-row-default_value' ).data( 'fieldId' ); + + app.checkMultiplicitySliderDefaultValue( fieldID, newValue, step, min, max ) + .updateNumberSlider( fieldID, newValue ) + .updateNumberSliderHint( fieldID, newValue ); + } + }, + + /** + * Change number slider default value option. + * + * @since 1.5.7 + * + * @param {Object} event Input event. + */ + changeNumberSliderDefaultValue( event ) { + const value = parseFloat( event.target.value ); + + if ( ! isNaN( value ) ) { + const max = parseFloat( event.target.max ); + + if ( value > max ) { + event.target.value = max; + + return; + } + + const min = parseFloat( event.target.min ); + + if ( value < min ) { + event.target.value = min; + + return; + } + + const step = parseFloat( event.target.step ); + const fieldID = $( event.target ).parents( '.wpforms-field-option-row-default_value' ).data( 'fieldId' ); + + app.checkMultiplicitySliderDefaultValue( fieldID, value, step, min, max ) + .updateNumberSlider( fieldID, value ) + .updateNumberSliderHint( fieldID, value ); + } + }, + + /** + * Update number slider default value attribute. + * + * @since 1.5.7 + * + * @param {number} fieldID Field ID. + * @param {*} newValue Default value attribute. + * @param {*} attr Attribute name. + * + * @return {Object} App instance. + */ + updateNumberSliderDefaultValueAttr( fieldID, newValue, attr ) { + const input = document.getElementById( 'wpforms-field-option-' + fieldID + '-default_value' ); + + if ( input ) { + const value = parseFloat( input.value ); + + input.setAttribute( attr, newValue ); + newValue = parseFloat( newValue ); + + if ( 'max' === attr && value > newValue ) { + input.value = newValue; + } + + if ( 'min' === attr && value < newValue ) { + input.value = newValue; + } + } + + return this; + }, + + /** + * Update number slider value. + * + * @since 1.5.7 + * + * @param {number} fieldID Field ID. + * @param {string} value Number slider value. + * + * @return {Object} App instance. + */ + updateNumberSlider( fieldID, value ) { + const numberSlider = document.getElementById( 'wpforms-number-slider-' + fieldID ); + + if ( numberSlider ) { + numberSlider.value = value; + } + + return this; + }, + + /** + * Update number slider attribute. + * + * @since 1.5.7 + * + * @param {number} fieldID Field ID. + * @param {any} value Attribute value. + * @param {*} attr Attribute name. + * + * @return {Object} App instance. + */ + updateNumberSliderAttr( fieldID, value, attr ) { + const numberSlider = document.getElementById( 'wpforms-number-slider-' + fieldID ); + + if ( numberSlider ) { + numberSlider.setAttribute( attr, value ); + } + + return this; + }, + + /** + * Update number slider hint string. + * + * @since 1.5.7 + * + * @param {number} fieldID Field ID. + * @param {string} str Hint string. + * + * @return {Object} App instance. + */ + updateNumberSliderHintStr( fieldID, str ) { + const hint = document.getElementById( 'wpforms-number-slider-hint-' + fieldID ); + + if ( hint ) { + hint.dataset.hint = str; + } + + return this; + }, + + /** + * Update number slider Hint value. + * + * @since 1.5.7 + * + * @param {number} fieldID Field ID. + * @param {string} value Hint value. + * + * @return {Object} App instance. + */ + updateNumberSliderHint( fieldID, value ) { + const hint = document.getElementById( 'wpforms-number-slider-hint-' + fieldID ); + + if ( hint ) { + hint.innerHTML = wpf.sanitizeHTML( hint.dataset.hint ).replaceAll( '{value}', '' + value + '' ); + } + + return this; + }, + + /** + * Update min attribute. + * + * @since 1.5.7 + * + * @param {Object} event Input event. + */ + fieldNumberSliderUpdateMin( event ) { + const current = parseFloat( event.target.value ); + + if ( isNaN( current ) ) { + return; + } + + const $options = $( event.target ).parents( '.wpforms-field-option-row-min_max' ); + const max = parseFloat( $options.find( '.wpforms-number-slider-max' ).val() ); + + if ( max <= current ) { + event.preventDefault(); + this.value = max; + + return; + } + + const fieldId = $options.data( 'field-id' ); + const numberSlider = $builder.find( '#wpforms-field-' + fieldId + ' input[type="range"]' ); + + numberSlider.attr( 'min', current ); + }, + + /** + * Update max attribute. + * + * @since 1.5.7 + * + * @param {Object} event Input event. + */ + fieldNumberSliderUpdateMax( event ) { + const current = parseFloat( event.target.value ); + + if ( isNaN( current ) ) { + return; + } + + const $options = $( event.target ).parents( '.wpforms-field-option-row-min_max' ); + const min = parseFloat( $options.find( '.wpforms-number-slider-min' ).val() ); + + if ( min >= current ) { + event.preventDefault(); + this.value = min; + + return; + } + + const fieldId = $options.data( 'field-id' ); + const numberSlider = $builder.find( '#wpforms-field-' + fieldId + ' input[type="range"]' ); + + numberSlider.attr( 'max', current ); + }, + + /** + * Update max attribute for step value. + * + * @since 1.5.7 + * + * @param {number} fieldID Field ID. + * @param {*} newValue Default value attribute. + * + * @return {Object} App instance. + */ + updateNumberSliderStepValueMaxAttr( fieldID, newValue ) { + const input = document.getElementById( 'wpforms-field-option-' + fieldID + '-step' ); + + if ( input ) { + const value = parseFloat( input.value ); + + input.setAttribute( 'max', newValue ); + newValue = parseFloat( newValue ); + + if ( value > newValue ) { + input.value = newValue; + $( input ).trigger( 'input' ); + } + } + + return this; + }, + + /** + * Update upload selector. + * + * @since 1.5.6 + * + * @param {Object} target Changed :input. + */ + fieldFileUploadPreviewUpdate( target ) { + /** + * @type {jQuery} + */ + const $options = $( target ).parents( '.wpforms-field-option-file-upload' ); + const fieldId = $options.data( 'field-id' ); + + const styleOption = $options.find( '#wpforms-field-option-' + fieldId + '-style' ).val(); + const $maxFileNumberRow = $options.find( '#wpforms-field-option-row-' + fieldId + '-max_file_number' ); + const maxFileNumber = parseInt( $maxFileNumberRow.find( 'input' ).val(), 10 ); + const isCameraEnabled = $options.find( '#wpforms-field-option-' + fieldId + '-camera_enabled' ).is( ':checked' ); + + const $preview = $( '#wpforms-field-' + fieldId ); + const classicPreview = '.wpforms-file-upload-builder-classic'; + const modernPreview = '.wpforms-file-upload-builder-modern'; + + if ( styleOption === 'classic' ) { + $( classicPreview, $preview ).removeClass( 'wpforms-hide' ); + $( modernPreview, $preview ).addClass( 'wpforms-hide' ); + $maxFileNumberRow.addClass( 'wpforms-hidden' ); + $( $preview ).find( '.wpforms-file-upload-capture-camera-classic' ).toggleClass( 'wpforms-hidden', ! isCameraEnabled ); + } else { + // Change hint and title. + if ( maxFileNumber > 1 ) { + const titleText = isCameraEnabled + ? wpforms_builder.file_upload.preview_title_plural_camera + : wpforms_builder.file_upload.preview_title_plural; + $preview + .find( '.modern-title' ) + .html( titleText ); + $preview + .find( '.modern-hint' ) + .text( wpforms_builder.file_upload.preview_hint.replace( '{maxFileNumber}', maxFileNumber ) ) + .removeClass( 'wpforms-hide' ); + } else { + const titleText = isCameraEnabled + ? wpforms_builder.file_upload.preview_title_single_camera + : wpforms_builder.file_upload.preview_title_single; + $preview + .find( '.modern-title' ) + .html( titleText ); + $preview + .find( '.modern-hint' ) + .text( wpforms_builder.file_upload.preview_hint.replace( '{maxFileNumber}', 1 ) ) + .addClass( 'wpforms-hide' ); + } + + // Display the preview. + $( classicPreview, $preview ).addClass( 'wpforms-hide' ); + $( modernPreview, $preview ).removeClass( 'wpforms-hide' ); + $maxFileNumberRow.removeClass( 'wpforms-hidden' ); + } + }, + + /** + * Update limit controls by changing the checkbox. + * + * @since 1.5.6 + * + * @param {number} id Field id. + * @param {boolean} checked Whether an option is checked or not. + */ + updateTextFieldsLimitControls( id, checked ) { + if ( ! checked ) { + $( '#wpforms-field-option-row-' + id + '-limit_controls' ).addClass( 'wpforms-hide' ); + } else { + $( '#wpforms-field-option-row-' + id + '-limit_controls' ).removeClass( 'wpforms-hide' ); + } + }, + + /** + * Update disabling today's date controls by changing the checkbox. + * + * @since 1.8.9.4 + * + * @param {number} id Field id. + * @param {boolean} checked Whether an option is checked or not. + */ + updateDisableTodaysDateControls( id, checked ) { + $( `#wpforms-field-option-row-${ id }-date_disable_todays_date` ) + .toggleClass( 'wpforms-hide', ! checked ); + }, + + /** + * Toggles the visibility of the password eye icon. + * + * @since 1.9.8 + */ + togglePasswordEyeIcon() { + const $this = $( this ); + const fieldId = $this.closest( '.wpforms-field-option-row-password-visibility' ).data( 'field-id' ); + const $fieldPreview = $( `#wpforms-field-${ fieldId }` ); + + $fieldPreview.find( '.wpforms-confirm' ).toggleClass( 'wpforms-field-password-visibility-enabled', $this.is( ':checked' ) ); + }, + + /** + * Update Password Strength controls by changing the checkbox. + * + * @since 1.6.7 + * + * @param {number} id Field id. + * @param {boolean} checked Whether an option is checked or not. + */ + updatePasswordStrengthControls( id, checked ) { + const $strengthControls = $( '#wpforms-field-option-row-' + id + '-password-strength-level' ); + + if ( checked ) { + $strengthControls.removeClass( 'wpforms-hidden' ); + } else { + $strengthControls.addClass( 'wpforms-hidden' ); + } + }, + + /** + * Update Rich Text media controls by changing the checkbox. + * + * @since 1.7.0 + */ + updateRichTextMediaFieldsLimitControls() { + const $this = $( this ), + fieldId = $this.closest( '.wpforms-field-option-row-media_enabled' ).data( 'field-id' ), + $mediaControls = $( '#wpforms-field-option-row-' + fieldId + '-media_controls' ), + $toolbar = $( '#wpforms-field-' + fieldId + ' .wpforms-richtext-wrap .mce-toolbar-grp' ); + + if ( ! $this.is( ':checked' ) ) { + $mediaControls.hide(); + $toolbar.removeClass( 'wpforms-field-richtext-media-enabled' ); + } else { + $mediaControls.show(); + $toolbar.addClass( 'wpforms-field-richtext-media-enabled' ); + } + }, + + /** + * Update the Rich Text style preview by changing select. + * + * @since 1.7.0 + */ + updateRichTextStylePreview() { + const $this = $( this ), + fieldId = $this.closest( '.wpforms-field-option-row-style' ).data( 'field-id' ), + $toolbar = $( '#wpforms-field-' + fieldId + ' .wpforms-richtext-wrap .mce-toolbar-grp' ); + + $toolbar.toggleClass( 'wpforms-field-richtext-toolbar-basic', $this.val() !== 'full' ); + }, + + /** + * Element bindings. + * + * @since 1.0.0 + */ + bindUIActions() { + // General Panels. + app.bindUIActionsPanels(); + + // Fields Panel. + app.bindUIActionsFields(); + + // Settings Panel. + app.bindUIActionsSettings(); + + // Revisions Panel. + app.bindUIActionsRevisions(); + + // Save and Exit. + app.bindUIActionsSaveExit(); + + // General/ global. + app.bindUIActionsGeneral(); + + // Preview actions. + app.bindUIActionsPreview(); + }, + + /** + * Bind UI actions for the preview tab. + * + * @since 1.9.4 + */ + bindUIActionsPreview() { + // Open the preview tab or focus on it if it's already opened. + elements.$previewButton.on( 'click', function( e ) { + e.preventDefault(); + + const previewUrl = $( this ).attr( 'href' ); + + // Try to check if the preview tab is still open and from the same origin + let isSameOrigin = false; + if ( previewTab && ! previewTab.closed ) { + try { + // This will throw an error if cross-origin + isSameOrigin = previewTab.location.href.includes( 'wpforms_form_preview' ); + } catch ( error ) { + // Cross-origin access error, we can't access the location + isSameOrigin = false; + } + } + + if ( isSameOrigin ) { + previewTab.focus(); + } else { + previewTab = window.open( previewUrl, '_blank' ); + } + } ); + + // Reload the preview tab after saving the form. + $builder.on( 'wpformsSaved', function() { + if ( previewTab && ! previewTab.closed ) { + try { + // This will throw an error if cross-origin + if ( previewTab.location.href.includes( 'wpforms_form_preview' ) ) { + previewTab.location.reload(); + } + } catch ( error ) { + // Silently handle cross-origin errors + // We can't access or reload cross-origin tabs + } + } + } ); + }, + + //--------------------------------------------------------------------// + // General Panels + //--------------------------------------------------------------------// + + /** + * Element bindings for general panel tasks. + * + * @since 1.0.0 + */ + bindUIActionsPanels() { + // Panel switching. + $builder.on( 'click', '#wpforms-panels-toggle button, .wpforms-panel-switch', function( e ) { + e.preventDefault(); + app.panelSwitch( $( this ).data( 'panel' ) ); + } ); + + // Panel sections switching. + $builder.on( 'click', '.wpforms-panel .wpforms-panel-sidebar-section', function( e ) { + app.panelSectionSwitch( this, e ); + } ); + + // Panel tab switching. + $builder.on( 'click', '.wpforms-panel .wpforms-panel-content .wpforms-panel-content-section-tabs-list-item', function( e ) { + app.panelSectionTabSwitch( this, e ); + } ); + + // Panel sidebar toggle. + $builder.on( 'click', '.wpforms-panels .wpforms-panel-sidebar-content .wpforms-panel-sidebar-toggle', function() { + $( this ).parent().toggleClass( 'wpforms-panel-sidebar-closed' ); + } ); + }, + + /** + * Switch Panels. + * + * @since 1.0.0 + * @since 1.5.9 Added `wpformsPanelSwitched` trigger. + * + * @param {string} panel Panel slug. + * + * @return {void|boolean} Void or false. + */ + panelSwitch( panel ) { + const $panel = $( '#wpforms-panel-' + panel ); + + if ( ! $panel.hasClass( 'active' ) ) { + const event = WPFormsUtils.triggerEvent( $builder, 'wpformsPanelSwitch', [ panel ] ); + + // Allow callbacks on `wpformsPanelSwitch` to cancel panel switching by triggering `event.preventDefault()`. + if ( event.isDefaultPrevented() || ! wpforms_panel_switch ) { + return false; + } + + $( '#wpforms-panels-toggle' ).find( 'button' ).removeClass( 'active' ); + $( '.wpforms-panel' ).removeClass( 'active' ); + $( '.wpforms-panel-' + panel + '-button' ).addClass( 'active' ); + $panel.addClass( 'active' ); + + history.replaceState( {}, null, wpf.updateQueryString( 'view', panel ) ); + + // Update the active section parameter in the URL. + let section; + const activeSectionElement = $panel.find( '.active' ); + + if ( activeSectionElement.length && activeSectionElement.data( 'section' ) !== 'default' ) { + section = activeSectionElement.data( 'section' ); + } + + history.replaceState( {}, null, wpf.updateQueryString( 'section', section ) ); + + $builder.trigger( 'wpformsPanelSwitched', [ panel ] ); + } + }, + + /** + * Switch Panel section. + * + * @since 1.0.0 + * + * @param {Element} el Element. + * @param {Event} e Event. + * + * @return {boolean|void} False when not switched. + */ + panelSectionSwitch( el, e ) { // eslint-disable-line complexity + if ( e ) { + e.preventDefault(); + } + + const $this = $( el ); + + if ( $this.hasClass( 'upgrade-modal' ) || $this.hasClass( 'education-modal' ) ) { + return; + } + + const $panel = $this.parent().parent(), + section = $this.data( 'section' ), + $sectionButton = $panel.find( `.wpforms-panel-sidebar-section[data-section="${ section }"]` ); + + if ( ! $sectionButton.hasClass( 'active' ) ) { + const event = WPFormsUtils.triggerEvent( $builder, 'wpformsPanelSectionSwitch', section ); + + // Allow callbacks on `wpformsPanelSectionSwitch` to cancel panel section switching by triggering `event.preventDefault()`. + if ( event.isDefaultPrevented() || ! wpforms_panel_switch ) { + return false; + } + + const $sectionButtons = $panel.find( '.wpforms-panel-sidebar-section' ); + + $sectionButtons.removeClass( 'active' ); + $sectionButton.addClass( 'active' ); + $panel.find( '.wpforms-panel-content-section' ).hide().removeClass( 'active' ); + $panel.find( '.wpforms-panel-content-section-' + section ).show().addClass( 'active' ); + + // Update the active section parameter in the URL. + history.replaceState( {}, null, wpf.updateQueryString( 'section', section ) ); + } + }, + + /** + * Switches panel sections. + * + * @since 1.9.8.6 + * + * @param {Element} el Element. + * @param {Event} e Event. + * + * @return {void} + */ + panelSectionTabSwitch( el, e ) { + e.preventDefault(); + + const $tabToggle = $( el ), + disabledClass = 'wpforms-disabled', + activeToggleClass = 'wpforms-panel-content-section-tabs-list-item-active', + activeTab = $tabToggle.data( 'tab' ); + + if ( ! activeTab || $tabToggle.hasClass( disabledClass ) || $tabToggle.hasClass( activeToggleClass ) ) { + return; + } + + const event = WPFormsUtils.triggerEvent( $builder, 'wpformsPanelSectionTabBeforeSwitch', [ activeTab, $tabToggle ] ); + + if ( event.isDefaultPrevented() ) { + return; + } + + const activeContentClass = 'wpforms-panel-content-section-tabs-content-tab-active', + $tabs = $tabToggle.closest( '.wpforms-panel-content-section-tabs-list' ), + $tabContent = $tabs.closest( '.wpforms-panel-content' ).find( '.wpforms-panel-content-section-tabs-content-tab' ); + + $tabs.find( '.wpforms-panel-content-section-tabs-list-item' ).removeClass( activeToggleClass ); + $tabToggle.addClass( activeToggleClass ); + + $tabContent.removeClass( activeContentClass ); + $tabContent.filter( `[data-tab="${ activeTab }"]` ).addClass( activeContentClass ); + + WPFormsUtils.triggerEvent( $builder, 'wpformsPanelSectionTabSwitch', [ activeTab, $tabToggle ] ); + }, + + //--------------------------------------------------------------------// + // Setup Panel + //--------------------------------------------------------------------// + + /** + * Element bindings for a Setup panel. + * + * @since 1.0.0 + * @since 1.6.8 Deprecated. + * + * @deprecated Use `WPForms.Admin.Builder.Setup.events()` instead. + */ + bindUIActionsSetup() { + // eslint-disable-next-line no-console + console.warn( 'WARNING! Function "WPFormsBuilder.bindUIActionsSetup()" has been deprecated, please use the new "WPForms.Admin.Builder.Setup.events()" function instead!' ); + + WPForms.Admin.Builder.Setup.events(); + }, + + /** + * Select template. + * + * @since 1.0.0 + * @since 1.6.8 Deprecated. + * + * @deprecated Use `WPForms.Admin.Builder.Setup.selectTemplate()` instead. + * + * @param {Object} el DOM element object. + * @param {Object} e Event object. + */ + templateSelect( el, e ) { + // eslint-disable-next-line no-console + console.warn( 'WARNING! Function "WPFormsBuilder.templateSelect()" has been deprecated, please use the new "WPForms.Admin.Builder.Setup.selectTemplate()" function instead!' ); + + WPForms.Admin.Builder.Setup.selectTemplate( e ); + }, + + //--------------------------------------------------------------------// + // Fields Panel + //--------------------------------------------------------------------// + + /** + * Element bindings for Fields panel. + * + * @since 1.0.0 + */ + bindUIActionsFields() { // eslint-disable-line max-lines-per-function + // Switched to the Fields panel. + $builder.on( 'wpformsPanelSwitched', function( e, panel ) { + if ( panel !== 'fields' ) { + return; + } + + // Detect the case when the field Options tab is active, but there is no active field on the preview panel. + if ( + $( '#field-options a' ).hasClass( 'active' ) && + $( '.wpforms-field-wrap .wpforms-field.active' ).length === 0 + ) { + app.fieldTabToggle( 'field-options' ); + } + } ); + + // Field sidebar tab toggle + $builder.on( 'click', '.wpforms-tab a', function( e ) { + e.preventDefault(); + app.fieldTabToggle( $( this ).parent().attr( 'id' ) ); + } ); + + // Field sidebar group toggle + $builder.on( 'click', '.wpforms-add-fields-heading', function( e ) { + e.preventDefault(); + app.fieldGroupToggle( $( this ), 'click' ); + } ); + + // Form field preview clicking. + $builder.on( 'click', '.wpforms-field', function( event, extraParameters ) { + if ( app.isFieldPreviewActionsDisabled( this ) ) { + return; + } + + // Allow clicking on the "dismiss" button inside the field. + if ( event.target.classList.contains( 'wpforms-dismiss-button' ) ) { + return; + } + + // Dismiss the main context menu when it is open. + if ( WPForms.Admin.Builder.ContextMenu && extraParameters !== 'ignore-contextmenu' ) { + WPForms.Admin.Builder.ContextMenu.hideMainContextMenu( event ); + } + + event.stopPropagation(); + + app.fieldTabToggle( $( this ).data( 'field-id' ) ); + } ); + + // Prevent interactions with inputs on the preview panel. + $builder.on( 'mousedown click', '.wpforms-field input, .wpforms-field select, .wpforms-field textarea', function( e ) { + e.preventDefault(); + this.blur(); + } ); + + // Field delete. + $builder.on( 'click', '.wpforms-field-delete', function( e ) { + e.preventDefault(); + e.stopPropagation(); + + if ( app.isFormPreviewActionsDisabled( this ) ) { + return; + } + + if ( WPForms.Admin.Builder.ContextMenu ) { + WPForms.Admin.Builder.ContextMenu.hideMenu(); + } + + app.fieldDelete( $( this ).parent().data( 'field-id' ) ); + } ); + + // Field duplicate. + $builder.on( 'click', '.wpforms-field-duplicate', function( e ) { + e.preventDefault(); + e.stopPropagation(); + + if ( app.isFormPreviewActionsDisabled( this ) ) { + return; + } + + if ( WPForms.Admin.Builder.ContextMenu ) { + WPForms.Admin.Builder.ContextMenu.hideMenu(); + } + + app.fieldDuplicate( $( this ).parent().data( 'field-id' ) ); + } ); + + // Field add. + $builder.on( 'click', '.wpforms-add-fields-button', function( e ) { + e.preventDefault(); + + const $field = $( this ); + + if ( $field.hasClass( 'ui-draggable-disabled' ) ) { + return; + } + + const type = $field.data( 'field-type' ), + event = WPFormsUtils.triggerEvent( $builder, 'wpformsBeforeFieldAddOnClick', [ type, $field ] ); + + // Allow callbacks on `wpformsBeforeFieldAddOnClick` to cancel adding field + // by triggering `event.preventDefault()`. + if ( event.isDefaultPrevented() ) { + return; + } + + app.fieldAdd( type, { $sortable: 'default' } ); + } ); + + // New field choices should be sortable + $builder.on( 'wpformsFieldAdd', function( event, id, type ) { + const fieldTypes = [ + 'select', + 'radio', + 'checkbox', + 'payment-multiple', + 'payment-checkbox', + 'payment-select', + ]; + + if ( $.inArray( type, fieldTypes ) !== -1 ) { + app.fieldChoiceSortable( type, `#wpforms-field-option-row-${ id }-choices ul` ); + } + } ); + + // Field option tab toggle. + $builder.on( 'wpformsFieldOptionTabToggle', function( e, fieldId ) { + app.fieldLayoutSelectorInit( fieldId ); + } ); + + // Field choice "Add new". + $builder.on( 'click', '.wpforms-field-option-row-choices .add', function( e ) { + app.fieldChoiceAdd( e, $( this ) ); + } ); + + // Field choice "Delete". + $builder.on( 'click', '.wpforms-field-option-row-choices .remove', function( e ) { + app.fieldChoiceDelete( e, $( this ) ); + } ); + + // Field choices' defaults, before change. + $builder.on( 'mousedown', '.wpforms-field-option-row-choices input[type=radio]', function() { + const $this = $( this ); + + if ( $this.is( ':checked' ) ) { + $this.attr( 'data-checked', '1' ); + } else { + $this.attr( 'data-checked', '0' ); + } + } ); + + // Field choices' defaults. + $builder.on( 'click', '.wpforms-field-option-row-choices input[type=radio]', function() { + const $this = $( this ), + list = $this.parent().parent(); + + $this.parent().parent().find( 'input[type=radio]' ).not( this ).prop( 'checked', false ); + + if ( $this.attr( 'data-checked' ) === '1' ) { + $this.prop( 'checked', false ); + $this.attr( 'data-checked', '0' ); + } + + app.fieldChoiceUpdate( list.data( 'field-type' ), list.data( 'field-id' ), list.find( 'li' ).length ); + } ); + + // Field choices update preview area. + $builder.on( 'change', '.wpforms-field-option-row-choices input[type=checkbox]', function() { + const list = $( this ).parent().parent(); + + app.fieldChoiceUpdate( list.data( 'field-type' ), list.data( 'field-id' ), list.find( 'li' ).length ); + } ); + + // Field choices display value toggle. + $builder.on( 'change', '.wpforms-field-option-row-show_values input', function() { // eslint-disable-line max-lines-per-function + const $toggle = $( this ); + const $options = $toggle.closest( '.wpforms-field-option' ); + const $choicesList = $options.find( '.wpforms-field-option-row-choices .choices-list' ); + const fieldId = $choicesList.data( 'field-id' ); + const type = $choicesList.data( 'field-type' ); + const showValuesOn = $toggle.is( ':checked' ); + // Toggle show-values class in the options UI as before. + $choicesList.toggleClass( 'show-values', showValuesOn ); + // Refresh preview. + app.fieldChoiceUpdate( type, fieldId ); + // If Show Values is enabled, sync the Other input value in preview from the Other choice Value field. + WPForms.Admin.Builder.MultipleChoices.updatePreviewState( fieldId ); + } ); + + // Field choices image toggle. + $builder.on( 'change', '.wpforms-field-option-row-choices_images input', function() { + const $this = $( this ), + $optionRow = $this.closest( '.wpforms-field-option-row' ), + fieldID = $optionRow.data( 'field-id' ), + $fieldOptions = $( '#wpforms-field-option-' + fieldID ), + checked = $this.is( ':checked' ), + type = $fieldOptions.find( '.wpforms-field-option-hidden-type' ).val(), + $iconToggle = $optionRow.siblings( '.wpforms-field-option-row-choices_icons' ).find( 'input' ); + + // Toggle icon choices off. + if ( checked && $iconToggle.is( ':checked' ) ) { + $iconToggle.prop( 'checked', false ).trigger( 'change' ); + } + + $optionRow.find( '.wpforms-alert' ).toggleClass( 'wpforms-hidden' ); + $fieldOptions.find( '.wpforms-field-option-row-choices ul' ).toggleClass( 'show-images' ); + $fieldOptions.find( '.wpforms-field-option-row-choices_images_style' ).toggleClass( 'wpforms-hidden' ); + $fieldOptions.find( '.wpforms-field-option-row-dynamic_choices' ).toggleClass( 'wpforms-hidden', checked ); + + if ( checked ) { + $( '#wpforms-field-option-' + fieldID + '-input_columns' ).val( 'inline' ).trigger( 'change' ); + } else { + $( '#wpforms-field-option-' + fieldID + '-input_columns' ).val( '' ).trigger( 'change' ); + } + + $( `#wpforms-field-option-row-${ fieldID }-choices_images_hide` ).toggleClass( 'wpforms-hidden', ! checked ); + + app.fieldChoiceUpdate( type, fieldID ); + } ); + + // Field choices image upload add/remove image. + $builder.on( 'wpformsImageUploadAdd wpformsImageUploadRemove', function( event, $this, $container ) { + const $list = $container.closest( '.choices-list' ), + fieldID = $list.data( 'field-id' ), + type = $list.data( 'field-type' ); + + app.fieldChoiceUpdate( type, fieldID ); + } ); + + // Field choices image style toggle. + $builder.on( 'change', '.wpforms-field-option-row-choices_images_style select', function() { + const fieldID = $( this ).parent().data( 'field-id' ), + type = $( '#wpforms-field-option-' + fieldID ).find( '.wpforms-field-option-hidden-type' ).val(); + + app.fieldChoiceUpdate( type, fieldID ); + } ); + + // Updates field choices text in almost real time. + $builder.on( 'keyup', '.wpforms-field-option-row-choices input.label, .wpforms-field-option-row-choices input.value', function() { + const $list = $( this ).parent().parent(); + + app.fieldChoiceUpdate( $list.data( 'field-type' ), $list.data( 'field-id' ) ); + } ); + + // Sanitize field choices text on focus out. + $builder.on( 'focusout', '.wpforms-field-option-row-choices input.label, .wpforms-field-option-row-choices input.value', function() { + const input = $( this ); + + input.val( wpf.sanitizeHTML( input.val(), wpforms_builder.allowed_label_html_tags ) ); + } ); + + // Field Choices Bulk Add + $builder.on( 'click', '.toggle-bulk-add-display', function( e ) { + e.preventDefault(); + app.fieldChoiceBulkAddToggle( this ); + } ); + + $builder.on( 'click', '.toggle-bulk-add-presets', function( e ) { + e.preventDefault(); + + /** + * @type {JQ|jQuery} + */ + const $presetList = $( this ).closest( '.bulk-add-display' ).find( 'ul' ); + + if ( $presetList.css( 'display' ) === 'block' ) { + $( this ).text( wpforms_builder.bulk_add_presets_show ); + } else { + $( this ).text( wpforms_builder.bulk_add_presets_hide ); + } + + $presetList.stop().slideToggle(); + } ); + + $builder.on( 'click', '.bulk-add-preset-insert', function( e ) { + e.preventDefault(); + + /** @type {JQ|jQuery} */ + const $this = $( this ); + const preset = $this.data( 'preset' ), + $container = $this.closest( '.bulk-add-display' ), + $presetList = $container.find( 'ul' ), + $presetToggle = $container.find( '.toggle-bulk-add-presets' ), + $textarea = $container.find( 'textarea' ); + + $textarea.val( '' ); + $textarea.insertAtCaret( wpforms_preset_choices[ preset ].choices.join( '\n' ) ); + $presetToggle.text( wpforms_builder.bulk_add_presets_show ); + $presetList.slideUp(); + } ); + + $builder.on( 'click', '.bulk-add-insert', function( e ) { + e.preventDefault(); + app.fieldChoiceBulkAddInsert( this ); + } ); + + // Field Options group tabs. + $builder.on( 'click', '.wpforms-field-option-group-toggle:not(.education-modal)', function( e ) { + const event = WPFormsUtils.triggerEvent( $builder, 'wpformsFieldOptionGroupToggle' ); + + // Allow callbacks on `wpformsFieldOptionGroupToggle` to cancel the tab toggle by triggering `event.preventDefault()`. + if ( event.isDefaultPrevented() ) { + return false; + } + + e.preventDefault(); + + const $group = $( this ).closest( '.wpforms-field-option-group' ); + + $group.siblings( '.wpforms-field-option-group' ).removeClass( 'active' ); + $group.addClass( 'active' ); + + $builder.trigger( 'wpformsFieldOptionGroupToggled', [ $group ] ); + } ); + + // Display toggle for an Address field hide address line 2 option. + $builder.on( 'change', '.wpforms-field-option-address input.wpforms-subfield-hide', function() { + const $optionRow = $( this ).closest( '.wpforms-field-option-row' ), + id = $optionRow.data( 'field-id' ), + subfield = $optionRow.data( 'subfield' ); + + $( '#wpforms-field-' + id ).find( '.wpforms-' + subfield ).toggleClass( 'wpforms-hide' ); + } ); + + // Real-time updates for the "Label" field option. + $builder.on( 'input', '.wpforms-field-option-row-label input, .wpforms-field-option-row-name input', function() { + const $this = $( this ), + id = $this.parent().data( 'field-id' ), + $preview = $( '#wpforms-field-' + id ), + type = $preview.data( 'field-type' ); + + let value = $this.val(), + showEmptyLabel = value.length === 0; + + // Do not modify the label of the HTML field. + if ( type === 'html' ) { + showEmptyLabel = false; + } + + if ( showEmptyLabel ) { + value = wpforms_builder.empty_label; + } + + $preview.toggleClass( 'label_empty', showEmptyLabel ).find( '> .label-title .text' ).text( value ); + } ); + + // Real-time updates for the "Description" field option + $builder.on( 'input', '.wpforms-field-option-row-description textarea', function() { + // noinspection CssUnusedSymbol + const $this = $( this ), + value = wpf.sanitizeHTML( $this.val() ), + id = $this.parent().data( 'field-id' ), + // IIF description is not following other fields structure and needs to be selected separately. + $desc = $( + `#wpforms-field-${ id } > .description, + #wpforms-field-${ id } .format-selected-single > .description, + #wpforms-field-${ id } .wpforms-field-internal-information-row-description` + ); + + app.updateDescription( $desc, value ); + + $this.trigger( 'wpformsDescriptionFieldUpdated', { id, descField: $desc, value } ); + } ); + + // Real-time updates the for "Required" field option + $builder.on( 'change', '.wpforms-field-option-row-required input', function() { + const id = $( this ).closest( '.wpforms-field-option-row' ).data( 'field-id' ), + $preview = $( '#wpforms-field-' + id ); + + $preview.toggleClass( 'required' ); + + app.onUpdateSelectPlaceholder( id, $preview ); + } ); + + // Real-time updates for a selected default choice option. + $builder.on( 'click', '.choices-list input.default', function() { + const $this = $( this ), + fieldId = $this.closest( '.choices-list' ).data( 'field-id' ), + checked = $this.is( ':checked' ); + + if ( ! checked ) { + app.maybeUpdateRequiredPlaceholder( fieldId ); + } + + /** + * Default choice option changing state event. + * + * @since 1.9.8.3 + * + * @type {Object} The selected default choice option. + */ + $builder.trigger( 'wpformsChoicesSetDefault', [ this ] ); + } ); + + // Real-time updates for the "Summary" field option + $builder.on( 'change', '.wpforms-field-option-row-summary input', function() { + const $this = $( this ), + id = $this.closest( '.wpforms-field-option-row' ).data( 'field-id' ); + + $( `#wpforms-field-${ id }` ).toggleClass( 'wpforms-summary-enabled' ); + $this.closest( '.wpforms-field-option-group-inner' ).find( '.wpforms-total-summary-alert' ).toggleClass( 'wpforms-hidden' ); + } ); + + // Real-time updates for the "Confirmation" field option + $builder.on( 'change', '.wpforms-field-option-row-confirmation input', function() { + const id = $( this ).closest( '.wpforms-field-option-row' ).data( 'field-id' ); + + $( '#wpforms-field-' + id ).find( '.wpforms-confirm' ).toggleClass( 'wpforms-confirm-enabled wpforms-confirm-disabled' ); + $( '#wpforms-field-option-' + id ).toggleClass( 'wpforms-confirm-enabled wpforms-confirm-disabled' ); + } ); + + // Real-time updates for "Filter" field option + $builder.on( 'change', '.wpforms-field-option-row-filter_type select', function() { + const id = $( this ).parent().data( 'field-id' ), + $toggledField = $( '#wpforms-field-option-' + id ); + + if ( $( this ).val() ) { + $toggledField.removeClass( 'wpforms-filter-allowlist' ); + $toggledField.removeClass( 'wpforms-filter-denylist' ); + $toggledField.addClass( 'wpforms-filter-' + $( this ).val() ); + } else { + $toggledField.removeClass( 'wpforms-filter-allowlist' ); + $toggledField.removeClass( 'wpforms-filter-denylist' ); + } + } ); + + $builder.on( 'focusout', '.wpforms-field-option-row-allowlist textarea,.wpforms-field-option-row-denylist textarea', function() { // eslint-disable-line max-lines-per-function + const $currentField = $( this ); + + let $current = 'allow'; + + $currentField.next( '.wpforms-alert' ).remove(); + + if ( $currentField.val() === '' ) { + return; + } + + const $allowField = $( '.wpforms-field-option-row-allowlist textarea' ), + $denyField = $( '.wpforms-field-option-row-denylist textarea' ); + + if ( $currentField.is( $denyField ) ) { + $current = 'deny'; + } + + $.get( + wpforms_builder.ajax_url, + { + nonce: wpforms_builder.nonce, + content: JSON.stringify( + { + allow: $allowField.val(), + deny: $denyField.val(), + current: $current, + } + ), + action: 'wpforms_sanitize_restricted_rules', + }, + function( res ) { + if ( res.success ) { + $currentField.val( res.data.currentField ); + const intersect = res.data.intersect; + if ( intersect.length !== 0 ) { + const content = '

' + wpforms_builder.allow_deny_lists_intersect + '

' + + '

' + intersect + '

'; + $.alert( { + title: wpforms_builder.heads_up, + content, + icon: 'fa fa-exclamation-circle', + type: 'red', + buttons: { + confirm: { + text: wpforms_builder.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + }, + }, + } ); + } + + const restricted = res.data.restricted || 0; + if ( restricted ) { + $currentField.after( '

' + wpforms_builder.restricted_rules + '

' ); + } + } + } + ); + } ); + + // Save focusout target. + $builder.on( 'focusout', elements.defaultEmailSelector, function() { + elements.$focusOutTarget = $( this ); + app.focusOutEvent(); + } ); + + // Real-time updates for the "Size" field option + $builder.on( 'change', '.wpforms-field-option-row-size select', function() { + const $this = $( this ), + value = $this.val(), + id = $this.parent().data( 'field-id' ); + + $( '#wpforms-field-' + id ).removeClass( 'size-small size-medium size-large' ).addClass( 'size-' + value ); + } ); + + // Real-time updates for the "Placeholder" field option. + $builder.on( 'input', '.wpforms-field-option-row-placeholder input', function() { // eslint-disable-line complexity + const $this = $( this ), + id = $this.parent().data( 'field-id' ), + $preview = $( '#wpforms-field-' + id ), + $primary = $preview.find( '.primary-input' ); + + let value = wpf.sanitizeHTML( $this.val() ); + + // Single Item Field - if a placeholder is cleared, set it to "price" placeholder. + if ( $preview.data( 'field-type' ) === 'payment-single' && value === '' ) { + value = $( '#wpforms-field-option-' + id + '-price' ).prop( 'placeholder' ); + } + + // Set the placeholder value for `input` fields. + if ( ! $primary.is( 'select' ) ) { + $primary.prop( 'placeholder', value ); + return; + } + + // Modern select style. + if ( app.dropdownField.helpers.isModernSelect( $primary ) ) { + const choiceInstance = app.dropdownField.helpers.getInstance( $primary ); + + // Additional case for multiple select. + if ( $primary.prop( 'multiple' ) ) { + $( choiceInstance.input.element ).prop( 'placeholder', value ); + } else { + choiceInstance.setChoiceByValue( '' ); + $primary.closest( '.choices' ).find( '.choices__inner .choices__placeholder' ).text( value ); + + const isDynamicChoices = $( '#wpforms-field-option-' + id + '-dynamic_choices' ).val(); + + // We need to re-initialize the modern dropdown to properly determine and update placeholder. + app.dropdownField.helpers.update( id, isDynamicChoices ); + } + + return; + } + + const $placeholder = $primary.find( '.placeholder' ); + + // Classic select style. + if ( ! value.length && $placeholder.length ) { + $placeholder.remove(); + } else { + if ( $placeholder.length ) { + $placeholder.text( value ); + } else { + $primary.prepend( '' ); + } + + $primary.find( '.placeholder' ).prop( 'selected', ! $primary.prop( 'multiple' ) ); + } + } ); + + // Real-time updates for the "Confirmation Placeholder" field option + $builder.on( 'input', '.wpforms-field-option-row-confirmation_placeholder input', function() { + const $this = $( this ), + value = $this.val(), + id = $this.parent().data( 'field-id' ); + + $( '#wpforms-field-' + id ).find( '.secondary-input' ).attr( 'placeholder', value ); + } ); + + // Real-time updates for Date/Time, and Name "Placeholder" field options + $builder.on( 'input', '.wpforms-field-option .format-selected input.placeholder', function() { + const $this = $( this ); + const value = $this.val(); + const $fieldOptionRow = $this.closest( '.wpforms-field-option-row' ); + const id = $fieldOptionRow.data( 'field-id' ); + const subfield = $fieldOptionRow.data( 'subfield' ); + + $( '#wpforms-field-' + id ).find( '.wpforms-' + subfield + ' input' ).attr( 'placeholder', value ); + } ); + + // Real-time updates for Address field "Placeholder" field options. + $builder.on( 'input', '.wpforms-field-option-address input.placeholder', function() { + const $this = $( this ); + const $fieldOptionRow = $this.closest( '.wpforms-field-option-row' ); + const id = $fieldOptionRow.data( 'field-id' ); + const subfield = $fieldOptionRow.data( 'subfield' ); + const $fieldPreviews = $( '#wpforms-field-' + id + ' .wpforms-' + subfield ).find( 'input, select' ); + const $default = $fieldOptionRow.find( '#wpforms-field-option-' + id + '-' + subfield + '_default' ); + const defaultValue = $default.val(); + const defaultText = $default.find( 'option:selected' ).text(); + + const placeholderValue = $this.val(); + + $fieldPreviews.each( function() { + const $fieldPreview = $( this ); + + if ( $fieldPreview.is( 'select' ) ) { + const $option = $fieldPreview.find( '.placeholder' ); + const value = defaultValue === '' && placeholderValue !== '' ? placeholderValue : defaultText; + + $option.text( value ); + + return; + } + + $fieldPreview.attr( 'placeholder', placeholderValue ); + } ); + } ); + + // Real-time updates for the "Default" field option. + $builder.on( 'input', '.wpforms-field-option-row-default_value input:not([type="search"])', function() { + const $this = $( this ); + const value = wpf.sanitizeHTML( $this.val() ); + const id = $this.closest( '.wpforms-field-option-row' ).data( 'field-id' ); + const $preview = $( '#wpforms-field-' + id + ' .primary-input' ); + + $preview.val( value ); + } ); + + // Real-time updates for "Default" field option of the Name and Address fields. + $builder.on( 'input', '.wpforms-field-options-column input.default', function() { + const $this = $( this ); + const value = wpf.sanitizeHTML( $this.val() ); + const $fieldOptionRow = $this.closest( '.wpforms-field-option-row' ); + const id = $fieldOptionRow.data( 'field-id' ); + const subfield = $fieldOptionRow.data( 'subfield' ); + const $fieldPreview = $( '#wpforms-field-' + id + ' .wpforms-' + subfield + ' input' ); + + $fieldPreview.val( value ); + } ); + + // Real-time updates for "Default" select field option of the Address field. + $builder.on( 'change', '.wpforms-field-option-address select.default', function() { + const $this = $( this ); + const value = $this.val(); + const textValue = $this.find( 'option:selected' ).text(); + const $fieldOptionRow = $this.closest( '.wpforms-field-option-row' ); + const id = $fieldOptionRow.data( 'field-id' ); + const subfield = $fieldOptionRow.data( 'subfield' ); + const scheme = $( '#wpforms-field-option-' + id + '-scheme' ).val(); + const $placeholder = $fieldOptionRow.find( '#wpforms-field-option-' + id + '-' + subfield + '_placeholder' ); + const placeholderValue = $placeholder.val(); + const $fieldPreview = $( '#wpforms-field-' + id + ' .wpforms-address-scheme-' + scheme + ' .wpforms-' + subfield + ' .placeholder' ); + + value === '' && placeholderValue.trim().length > 0 + ? $fieldPreview.text( placeholderValue ) + : $fieldPreview.text( textValue ); + } ); + + // Real-time updates for the "Confirmation Placeholder" field option + $builder.on( 'input', '.wpforms-field-option-row-confirmation_placeholder input', function() { + const $this = $( this ), + value = $this.val(), + id = $this.parent().data( 'field-id' ); + + $( '#wpforms-field-' + id ).find( '.secondary-input' ).attr( 'placeholder', value ); + } ); + + // Real-time updates for the "Hide Label" field option. + $builder.on( 'change', '.wpforms-field-option-row-label_hide input', function() { + const id = $( this ).closest( '.wpforms-field-option-row' ).data( 'field-id' ); + + $( '#wpforms-field-' + id ).toggleClass( 'label_hide' ); + } ); + + // Real-time updates for a Sub Label visibility field option. + $builder.on( 'change', '.wpforms-field-option-row-sublabel_hide input', function() { + const id = $( this ).closest( '.wpforms-field-option-row' ).data( 'field-id' ); + + $( '#wpforms-field-' + id ).toggleClass( 'sublabel_hide' ); + } ); + + // Real-time updates for the "Read-Only" field option. + $builder.on( 'change', '.wpforms-field-option-row-read_only input', app.fieldReadOnlyToggleChange ); + + // Real-time updates for a Quantity visibility field option. + $builder.on( 'change', '.wpforms-field-option-row-enable_quantity input', function() { + const id = $( this ).closest( '.wpforms-field-option-row' ).data( 'field-id' ), + $preview = $( `#wpforms-field-${ id }` ); + + $( `#wpforms-field-option-row-${ id }-quantity` ).toggleClass( 'wpforms-hidden' ); + $preview.find( '.quantity-input' ).toggleClass( 'wpforms-hidden' ); + $preview.toggleClass( 'payment-quantity-enabled' ); + } ); + + // Real-time updates for Quantity preview minimum value. + $builder.on( 'input', '.wpforms-field-option-row-quantity input', function() { + const $this = $( this ); + + // Allow only a positive integer value less than 9999. + $this.val( Math.min( Math.abs( Math.round( $this.val() ) ), 9999 ) ); + + const $optionRow = $this.closest( '.wpforms-field-option-row' ), + id = $optionRow.data( 'field-id' ), + isMinInput = $this.hasClass( 'min-quantity-input' ), + $minInput = $optionRow.find( '.min-quantity-input' ), + $maxInput = $optionRow.find( '.max-quantity-input' ); + + if ( isMinInput ) { + $( '#wpforms-field-' + id ).find( '.quantity-input option' ).text( $this.val() ); + } + + $minInput.toggleClass( 'wpforms-error', parseInt( $minInput.val(), 10 ) > parseInt( $maxInput.val(), 10 ) ); + } ); + + // Real-time updates for Date/Time, Name and Single Item "Format" option. + $builder.on( 'change', '.wpforms-field-option-row-format select', function() { + const $this = $( this ), + value = $this.val(), + id = $this.parent().data( 'field-id' ), + $sublabelToggle = $( '#wpforms-field-option-row-' + id + '-sublabel_hide' ), + $preview = $( '#wpforms-field-' + id ); + + $preview.find( '.format-selected' ).removeClass().addClass( 'format-selected format-selected-' + value ); + $( '#wpforms-field-option-' + id ).find( '.format-selected' ).removeClass().addClass( 'format-selected format-selected-' + value ); + + // Show toggle for "Hide Sub labels" only when the field consists of more than one subfield. + if ( [ 'date-time', 'first-last', 'first-middle-last' ].includes( value ) ) { + $sublabelToggle.removeClass( 'wpforms-hidden' ); + } else { + $sublabelToggle.addClass( 'wpforms-hidden' ); + } + + // Hide the label field if it's not a single item. + $( `#wpforms-field-option-row-${ id }-price_label` ).toggleClass( 'wpforms-hidden', value !== 'single' ); + + // Toggle options based on Single Item "Format". + if ( [ 'single', 'user', 'hidden' ].includes( value ) ) { + const isUserDefined = value === 'user', + isSingle = value === 'single', + isHidden = value === 'hidden', + isQuantityEnabled = $( '#wpforms-field-option-' + id + '-enable_quantity' ).is( ':checked' ), + $minPriceOption = $( '#wpforms-field-option-' + id + '-min_price' ), + minPrice = wpf.amountSanitize( $minPriceOption.val() ), + isValidMinPrice = minPrice >= $minPriceOption.data( 'minimum-price' ), + $minPriceOptionRow = $( '#wpforms-field-option-row-' + id + '-min_price' ); + + // Toggle Placeholder option. + $( '#wpforms-field-option-row-' + id + '-placeholder' ).toggleClass( 'wpforms-hidden', ! isUserDefined ); + + // Toggle Quantity options. + $( '#wpforms-field-option-row-' + id + '-enable_quantity' ).toggleClass( 'wpforms-hidden', ! isSingle ); + $( '#wpforms-field-option-row-' + id + '-quantities_alert' ).toggleClass( 'wpforms-hidden', ! isSingle ); + $( '#wpforms-field-option-row-' + id + '-quantity' ).toggleClass( 'wpforms-hidden', ! isSingle || ! isQuantityEnabled ); + $preview.find( '.quantity-input' ).toggleClass( 'wpforms-hidden', ! isSingle || ! isQuantityEnabled ); + + // Toggle Minimum Price options. + $minPriceOptionRow.toggleClass( 'wpforms-hidden', ! isUserDefined ); + $minPriceOptionRow.find( '.wpforms-item-minimum-price-alert' ).toggleClass( 'wpforms-hidden', isValidMinPrice ); + $preview.find( '.item-min-price' ).toggleClass( 'wpforms-hidden', isUserDefined && minPrice <= 0 ); + $preview.toggleClass( 'min-price-warning', ! isValidMinPrice ); + $preview.find( '.fa-exclamation-triangle' ).toggleClass( 'wpforms-hidden', isValidMinPrice ); + + // Toggle the label + $( `#wpforms-field-${ id } .item-price-single` ).toggleClass( 'wpforms-hidden', ! isSingle ); + $( `#wpforms-field-${ id } .item-price-hidden` ).toggleClass( 'wpforms-hidden', ! isHidden ); + } + } ); + + // Real-time updates specific for Address "Scheme" option + $builder.on( 'change', '.wpforms-field-option-row-scheme select', function() { + const $this = $( this ); + const value = $this.val(); + const fieldId = $this.parent().data( 'field-id' ); + + const $fieldPreview = $( `#wpforms-field-${ fieldId }` ); + const $stateOption = $( `#wpforms-field-option-row-${ fieldId }-state` ); + const $countryOption = $( `#wpforms-field-option-row-${ fieldId }-country` ); + + // Switch the scheme in a Preview panel. + $fieldPreview.find( '.wpforms-address-scheme' ).addClass( 'wpforms-hide' ); + $fieldPreview.find( `.wpforms-address-scheme-${ value }` ).removeClass( 'wpforms-hide' ); + + // Show an or hide country option depending on the scheme. + const $countryPreviewField = $fieldPreview.find( `.wpforms-address-scheme-${ value } .wpforms-country select, .wpforms-address-scheme-${ value } .wpforms-country input` ); + + $countryPreviewField.length === 0 + ? $countryOption.addClass( 'wpforms-hidden' ) + : $countryOption.removeClass( 'wpforms-hidden' ); + + // Inputs/selects for a currently selected scheme and the one that we're changing to. + const $currentState = $stateOption.find( '.default .default' ).not( '.wpforms-hidden-strict' ); + const $newState = $stateOption.find( `.default [data-scheme="${ value }"]` ); + const $currentCountry = $countryOption.find( '.default .default' ).not( '.wpforms-hidden-strict' ); + const $newCountry = $countryOption.find( `.default [data-scheme="${ value }"]` ); + + // Switch the state field type in options to match the scheme. + $newState.attr( { + id: $currentState.attr( 'id' ), + name: $currentState.attr( 'name' ), + } ).removeClass( 'wpforms-hidden-strict' ); + $currentState.attr( { id: '', name: '' } ).addClass( 'wpforms-hidden-strict' ); + $newCountry.attr( { + id: $currentCountry.attr( 'id' ), + name: $currentCountry.attr( 'name' ), + } ).removeClass( 'wpforms-hidden-strict' ); + $currentCountry.attr( { id: '', name: '' } ).addClass( 'wpforms-hidden-strict' ); + } ); + + // Real-time updates for a Date/Time date type + $builder.on( 'change', '.wpforms-field-option-row-date .type select', function() { + const $this = $( this ), + value = $this.val(), + id = $( this ).closest( '.wpforms-field-option-row' ).data( 'field-id' ), + addClass = value === 'datepicker' ? 'wpforms-date-type-datepicker' : 'wpforms-date-type-dropdown', + removeClass = value === 'datepicker' ? 'wpforms-date-type-dropdown' : 'wpforms-date-type-datepicker'; + + $( '#wpforms-field-' + id ).find( '.wpforms-date' ).addClass( addClass ).removeClass( removeClass ); + $( '#wpforms-field-option-' + id ).addClass( addClass ).removeClass( removeClass ); + + const $limitDays = $this.closest( '.wpforms-field-option-group-advanced' ) + .find( '.wpforms-field-option-row-date_limit_days, .wpforms-field-option-row-date_limit_days_options, .wpforms-field-option-row-date_disable_past_dates' ), + $limitDaysOptions = $( '#wpforms-field-option-row-' + id + '-date_limit_days_options' ); + + if ( value === 'dropdown' ) { + const $dateSelect = $( '#wpforms-field-option-' + id + '-date_format' ); + + if ( $dateSelect.find( 'option:selected' ).hasClass( 'datepicker-only' ) ) { + $dateSelect.prop( 'selectedIndex', 0 ).trigger( 'change' ); + } + + $limitDays.hide(); + } else { + $limitDays.show(); + $( '#wpforms-field-option-' + id + '-date_limit_days' ).is( ':checked' ) + ? $limitDaysOptions.show() + : $limitDaysOptions.hide(); + } + } ); + + // Real-time updates for Date/Time date select format + $builder.on( 'change', '.wpforms-field-option-row-date .format select', function() { + const $this = $( this ), + value = $this.val(), + id = $( this ).closest( '.wpforms-field-option-row' ).data( 'field-id' ), + $field = $( '#wpforms-field-' + id ); + + if ( value === 'm/d/Y' || value === 'm.d.Y' ) { + $field.find( '.wpforms-date-dropdown .first option' ).text( wpforms_builder.date_select_month ); + $field.find( '.wpforms-date-dropdown .second option' ).text( wpforms_builder.date_select_day ); + $field.find( '.wpforms-date-dropdown .third option' ).text( wpforms_builder.date_select_year ); + } else if ( value === 'd/m/Y' || value === 'd.m.Y' ) { + $field.find( '.wpforms-date-dropdown .first option' ).text( wpforms_builder.date_select_day ); + $field.find( '.wpforms-date-dropdown .second option' ).text( wpforms_builder.date_select_month ); + $field.find( '.wpforms-date-dropdown .third option' ).text( wpforms_builder.date_select_year ); + } else if ( value === 'Y/m/d' || value === 'Y.m.d' ) { + $field.find( '.wpforms-date-dropdown .first option' ).text( wpforms_builder.date_select_year ); + $field.find( '.wpforms-date-dropdown .second option' ).text( wpforms_builder.date_select_month ); + $field.find( '.wpforms-date-dropdown .third option' ).text( wpforms_builder.date_select_day ); + } + } ); + + // Real-time updates for Date/Time select format + $builder.on( 'change', '.wpforms-field-option-row-time .format select', function() { + const $this = $( this ), + id = $this.closest( '.wpforms-field-option-row' ).data( 'field-id' ); + + let options = '', + hh; + + // Determine a time format type. + // If the format contains `g` or `h`, then this is a 12-hour format, otherwise 24 hours. + const format = $this.val().match( /[gh]/ ) ? 12 : 24, + minHour = format === 12 ? 1 : 0, + maxHour = format === 12 ? 13 : 24; + + // Generate a new set of hour options. + for ( let i = minHour; i < maxHour; i++ ) { + hh = i < 10 ? '0' + i : i; + options += ''.replace( /{hh}/g, hh ); + } + + _.forEach( [ 'start', 'end' ], function( field ) { + const $hour = $builder.find( '#wpforms-field-option-' + id + '-time_limit_hours_' + field + '_hour' ), + $ampm = $builder.find( '#wpforms-field-option-' + id + '-time_limit_hours_' + field + '_ampm' ); + + let hourValue = parseInt( $hour.val(), 10 ), + ampmValue = $ampm.val(); + + if ( format === 24 ) { + hourValue = ampmValue === 'pm' ? hourValue + 12 : hourValue; + } else { + ampmValue = hourValue > 12 ? 'pm' : 'am'; + hourValue = hourValue > 12 ? hourValue - 12 : hourValue; + } + + hourValue = hourValue < 10 ? '0' + hourValue : hourValue; + $hour.html( options ).val( hourValue ); + $ampm.toggleClass( 'wpforms-hidden-strict', format === 24 ).val( ampmValue ); + $ampm.nextAll( 'div' ).toggleClass( 'wpforms-hidden-strict', format === 12 ); + } ); + } ); + + // Real-time updates for the "Hide Divider Line" field option. + $builder.on( 'change', '.wpforms-field-option-row-hide_divider_line input', function() { + const id = $( this ).closest( '.wpforms-field-option-row' ).data( 'field-id' ); + + $( `#wpforms-field-${ id }` ).toggleClass( 'hide_line' ); + } ); + + // Consider the field active when a disabled nav button is clicked + $builder.on( 'click', '.wpforms-pagebreak-button', function( e ) { + e.preventDefault(); + $( this ).closest( '.wpforms-field' ).trigger( 'click' ); + } ); + + /* + * Pagebreak field. + */ + app.fieldPageBreakInitDisplayPrevious( $builder.find( '.wpforms-field-pagebreak.wpforms-pagebreak-normal' ).first() ); + + $builder + .on( 'input', '.wpforms-field-option-row-next input', function() { + // Real-time updates for the "Next" pagebreak field option. + const $this = $( this ), + value = $this.val(), + $next = $( '#wpforms-field-' + $this.parent().data( 'field-id' ) ).find( '.wpforms-pagebreak-next' ); + + if ( value ) { + $next.css( 'display', 'inline-block' ).text( value ); + } else { + $next.css( 'display', 'none' ).empty(); + } + } ) + .on( 'input', '.wpforms-field-option-row-prev input', function() { + // Real-time updates for the "Prev" pagebreak field option. + const $this = $( this ), + value = $this.val().trim(), + $field = $( '#wpforms-field-' + $this.parent().data( 'field-id' ) ), + $prevBtn = $field.find( '.wpforms-pagebreak-prev' ); + + if ( value && $field.prevAll( '.wpforms-field-pagebreak.wpforms-pagebreak-normal' ).length > 0 ) { + $prevBtn.removeClass( 'wpforms-hidden' ).text( value ); + } else { + $prevBtn.addClass( 'wpforms-hidden' ).empty(); + } + } ) + .on( 'change', '.wpforms-field-option-row-prev_toggle input', function() { // eslint-disable-line complexity + // Real-time updates for "Display Previous" pagebreak field option. + const $input = $( this ), + $wrapper = $input.closest( '.wpforms-field-option-row-prev_toggle' ); + + if ( $wrapper.hasClass( 'wpforms-entry-preview-block' ) ) { + return; + } + + const $prev = $input.closest( '.wpforms-field-option-group-inner' ).find( '.wpforms-field-option-row-prev' ); + + const $prevLabel = $prev.find( 'input' ), + $prevBtn = $( '#wpforms-field-' + $input.closest( '.wpforms-field-option' ).data( 'field-id' ) ).find( '.wpforms-pagebreak-prev' ); + + $prev.toggleClass( 'wpforms-hidden', ! $input.prop( 'checked' ) ); + $prevBtn.toggleClass( 'wpforms-hidden', ! $input.prop( 'checked' ) ); + + if ( $input.prop( 'checked' ) && ! $prevLabel.val() ) { + let message = $prevLabel.data( 'last-value' ); + message = message && message.trim() ? message.trim() : wpforms_builder.previous; + + $prevLabel.val( message ); + } + + // Backward compatibility for forms that were created before the toggle was added. + if ( ! $input.prop( 'checked' ) ) { + $prevLabel.data( 'last-value', $prevLabel.val() ); + $prevLabel.val( '' ); + } + + $prevLabel.trigger( 'input' ); + } ) + .on( 'wpformsFieldAdd', app.fieldPagebreakAdd ) + .on( 'wpformsFieldDelete', app.fieldPagebreakDelete ) + .on( 'wpformsFieldAdd', app.toggleOrderSummaryConfirmation ) + .on( 'wpformsFieldDelete', app.toggleOrderSummaryConfirmation ) + .on( 'wpformsBeforeFieldDelete', app.fieldEntryPreviewDelete ); + + // Update Display Previous option visibility for all Pagebreak fields. + $builder.on( 'wpformsFieldMove wpformsFieldAdd wpformsFieldDelete', function() { + $builder.find( '.wpforms-field-pagebreak.wpforms-pagebreak-normal' ).each( function() { + app.fieldPageBreakInitDisplayPrevious( $( this ) ); + } ); + } ); + + // Real-time updates for "Page Title" pagebreak field option + $builder.on( 'input', '.wpforms-field-option-row-title input', function() { + const $this = $( this ), + value = $this.val(), + id = $this.parent().data( 'field-id' ); + + if ( value ) { + $( '#wpforms-field-' + id ).find( '.wpforms-pagebreak-title' ).text( value ); + } else { + $( '#wpforms-field-' + id ).find( '.wpforms-pagebreak-title' ).empty(); + } + } ); + + // Real-time updates for "Page Navigation Alignment" pagebreak field option + $builder.on( 'change', '.wpforms-field-option-row-nav_align select', function() { + const $this = $( this ); + let value = $this.val(); + + if ( ! value ) { + value = 'center'; + } + + $( '.wpforms-pagebreak-buttons' ) + .removeClass( 'wpforms-pagebreak-buttons-center wpforms-pagebreak-buttons-left wpforms-pagebreak-buttons-right wpforms-pagebreak-buttons-split' ) + .addClass( 'wpforms-pagebreak-buttons-' + value ); + } ); + + // Real-time updates for Single Item field "Item Price" option. + $builder.on( 'input', '.wpforms-field-option-row-price input', function() { + const $this = $( this ), + value = $this.val(), + formatted = wpf.amountFormat( wpf.amountSanitize( value ) ), + id = $this.parent().data( 'field-id' ), + placeholder = $( '#wpforms-field-option-' + id + '-placeholder' ).val().trim(), + $preview = $( '#wpforms-field-' + id ), + newValue = value === '' && placeholder !== '' ? '' : formatted; + + $preview.find( '.primary-input' ).val( newValue ); + $preview.find( '.price' ).text( wpf.amountFormatCurrency( value ) ); + } ); + + // Real-time updates for Single Item field "Minimum Price" option. + $builder.on( 'input', '.wpforms-field-option-row-min_price input', function() { + const $this = $( this ), + amount = $this.val(), + sanitized = wpf.amountSanitize( amount ), + isEmpty = sanitized <= 0, + isValid = sanitized >= $this.data( 'minimum-price' ), + $fieldOptionRow = $this.parent(), + $preview = $( '#wpforms-field-' + $fieldOptionRow.data( 'field-id' ) ); + + $fieldOptionRow.find( '.wpforms-item-minimum-price-alert' ).toggleClass( 'wpforms-hidden', isValid ); + $preview.find( '.item-min-price' ).toggleClass( 'wpforms-hidden', isEmpty ); + $preview.toggleClass( 'min-price-warning', ! isValid ); + $preview.find( '.fa-exclamation-triangle' ).toggleClass( 'wpforms-hidden', isValid ); + + if ( isEmpty ) { + return; + } + + $preview.find( '.min-price' ).text( wpf.amountFormatCurrency( amount ) ); + } ); + + // Real-time updates for price label for single item field. + $builder.on( 'input', '.wpforms-single-item-price-label-display', function() { + const $this = $( this ), + value = wpf.sanitizeHTML( $this.val(), '<>' ), + id = $this.parent().data( 'field-id' ), + $preview = $( `#wpforms-field-${ id }` ), + $price = wpf.amountFormatCurrency( $( `#wpforms-field-option-${ id }-price` ).val() ); + + if ( ! value ) { + $this.val( '{price}' ); + $preview.find( '.price-label' ).html( ` ${ $price } ` ); + return; + } + + $preview.find( '.price-label' ).html( value.replaceAll( '{price}', ` ${ $price } ` ) ); + } ); + + // Real-time updates for payment CC icons + $builder.on( 'change', '.wpforms-field-option-credit-card .payment-icons input', function() { + const $this = $( this ), + card = $this.data( 'card' ), + id = $this.parent().data( 'field-id' ); + + $( '#wpforms-field-' + id ).find( 'img.icon-' + card ).toggleClass( 'card_hide' ); + } ); + + // Generic updates for various additional placeholder fields (at least Stripe's "Name on Card"). + $builder.on( 'input', '.wpforms-field-option input.placeholder-update', function() { + const $this = $( this ), + value = $this.val(), + id = $this.data( 'field-id' ), + subfield = $this.data( 'subfield' ); + + $( '#wpforms-field-' + id ).find( '.wpforms-' + subfield + ' input' ).attr( 'placeholder', value ); + } ); + + // Toggle Choice Layout advanced field option. + $builder.on( 'change', '.wpforms-field-option-row-input_columns select', function() { + const $this = $( this ), + value = $this.val(), + id = $this.parent().data( 'field-id' ); + + let cls = ''; + + if ( value === '2' ) { + cls = 'wpforms-list-2-columns'; + } else if ( value === '3' ) { + cls = 'wpforms-list-3-columns'; + } else if ( value === 'inline' ) { + cls = 'wpforms-list-inline'; + } + + $( '#wpforms-field-' + id ).removeClass( 'wpforms-list-2-columns wpforms-list-3-columns wpforms-list-inline' ).addClass( cls ); + } ); + + // Toggle the toggle field. + $builder.on( 'change', '.wpforms-field-option-row .wpforms-toggle-control input', function() { + const $check = $( this ), + $control = $check.closest( '.wpforms-toggle-control' ), + $status = $control.find( '.wpforms-toggle-control-status' ), + state = $check.is( ':checked' ) ? 'on' : 'off'; + + $status.html( $status.data( state ) ); + } ); + + // Real-time updates for "Dynamic Choices" field option, for Dropdown, + // Checkboxes, and Multiple choice fields + $builder.on( 'change', '.wpforms-field-option-row-dynamic_choices select', function() { + app.fieldDynamicChoiceToggle( $( this ) ); + } ); + + // Real-time updates for the "Dynamic [type] Source" field option, for Dropdown, + // Checkboxes, and Multiple choice fields + $builder.on( 'change', '.wpforms-field-option-row-dynamic_taxonomy select, .wpforms-field-option-row-dynamic_post_type select', function() { + app.fieldDynamicChoiceSource( $( this ) ); + } ); + + // Toggle Layout selector + $builder.on( 'click', '.toggle-layout-selector-display', function( e ) { + e.preventDefault(); + app.fieldLayoutSelectorToggle( this ); + } ); + $builder.on( 'click', '.layout-selector-display-layout', function( e ) { + e.preventDefault(); + app.fieldLayoutSelectorLayout( this ); + } ); + $builder.on( 'click', '.layout-selector-display-columns span', function( e ) { + e.preventDefault(); + app.fieldLayoutSelectorInsert( this ); + } ); + + // Real-time updates for a Rating field scale option. + $( document ).on( 'change', '.wpforms-field-option-row-scale select', function() { + const $this = $( this ), + value = $this.val(), + id = $this.parent().data( 'field-id' ), + $icons = $( '#wpforms-field-' + id + ' .rating-icon' ); + + let x = 1; + + $icons.each( function() { + if ( x <= value ) { + $( this ).show(); + } else { + $( this ).hide(); + } + x++; + } ); + } ); + + // Real-time updates for a Rating field icon option. + $( document ).on( 'change', '.wpforms-field-option-row-icon select', function() { + const $this = $( this ), + value = $this.val(), + id = $this.parent().data( 'field-id' ), + $icons = $( '#wpforms-field-' + id + ' .rating-icon' ); + + let iconClass = 'fa-star'; + + if ( 'heart' === value ) { + iconClass = 'fa-heart'; + } else if ( 'thumb' === value ) { + iconClass = 'fa-thumbs-up'; + } else if ( 'smiley' === value ) { + iconClass = 'fa-smile-o'; + } + + $icons.removeClass( 'fa-star fa-heart fa-thumbs-up fa-smile-o' ).addClass( iconClass ); + } ); + + // Real-time updates for a Rating field icon size option. + $( document ).on( 'change', '.wpforms-field-option-row-icon_size select', function() { + const $this = $( this ), + value = $this.val(), + id = $this.parent().data( 'field-id' ), + $icons = $( '#wpforms-field-' + id + ' .rating-icon' ); + + let fontSize = '28'; + + if ( 'small' === value ) { + fontSize = '18'; + } else if ( 'large' === value ) { + fontSize = '38'; + } + + $icons.css( 'font-size', fontSize + 'px' ); + } ); + + // Real-time updates for a Rating field icon color option. + $( document ).on( 'input', '.wpforms-field-option-row-icon_color input.wpforms-color-picker', function() { + const $this = $( this ), + id = $this.closest( '.wpforms-field-option-row' ).data( 'field-id' ), + $icons = $( `#wpforms-field-${ id } .wpforms-rating-field-icons i.fa` ); + + $icons.css( 'color', app.getValidColorPickerValue( $this ) ); + } ); + + // Real-time updates for a Checkbox field Disclaimer option. + $( document ).on( 'change', '.wpforms-field-option-row-disclaimer_format input', function() { + const $this = $( this ), + id = $this.closest( '.wpforms-field-option-row' ).data( 'field-id' ), + $desc = $( '#wpforms-field-' + id + ' .description' ); + + $desc.toggleClass( 'disclaimer' ); + } ); + + $builder.on( + 'change', + '.wpforms-field-option-row-limit_enabled input', + function( event ) { + app.updateTextFieldsLimitControls( $( event.target ).closest( '.wpforms-field-option-row-limit_enabled' ).data().fieldId, event.target.checked ); + } + ); + + $builder.on( + 'change', + '.wpforms-field-option-row-date_disable_past_dates input', + function( event ) { + app.updateDisableTodaysDateControls( $( event.target ).closest( '.wpforms-field-option-row-date_disable_past_dates' ).data().fieldId, event.target?.checked ); + } + ); + + $builder.on( 'change', '.wpforms-field-option-row-password-visibility input', app.togglePasswordEyeIcon ); + + $builder.on( + 'change', + '.wpforms-field-option-row-password-strength input', + function( event ) { + app.updatePasswordStrengthControls( $( event.target ).parents( '.wpforms-field-option-row-password-strength' ).data().fieldId, event.target.checked ); + } + ); + + $builder.on( + 'change', + '.wpforms-field-option-richtext .wpforms-field-option-row-media_enabled input', + app.updateRichTextMediaFieldsLimitControls + ); + + $builder.on( + 'change', + '.wpforms-field-option-richtext .wpforms-field-option-row-style select', + app.updateRichTextStylePreview + ); + + // File uploader - change style. + $builder + .on( + 'change', + '.wpforms-field-option-file-upload .wpforms-field-option-row-style select, .wpforms-field-option-file-upload .wpforms-field-option-row-max_file_number input, .wpforms-field-option-file-upload .wpforms-field-option-row-camera input', + function( event ) { + app.fieldFileUploadPreviewUpdate( event.target ); + } + ); + + // Real-time updates for the Number Slider field. + app.numberSliderEvents( $builder ); + + // Hide image and icon choices if dynamic choices are not off. + app.fieldDynamicChoiceToggleImageChoices(); + app.fieldDynamicChoiceToggleIconChoices(); + + // Real-time updates for Payment field's 'Show price after item label' option. + $builder.on( 'change', '.wpforms-field-option-row-show_price_after_labels input', function() { + const $input = $( this ), + $list = $input.closest( '.wpforms-field-option-group-basic' ).find( '.wpforms-field-option-row-choices .choices-list' ); + + app.fieldChoiceUpdate( $list.data( 'field-type' ), $list.data( 'field-id' ) ); + } ); + + $builder + .on( 'input', '.wpforms-field-option-row-preview-notice textarea', app.updatePreviewNotice ) + .on( 'change', '.wpforms-field-option-row-preview-notice-enable input', app.toggleEntryPreviewNotice ) + .on( 'wpformsFieldAdd', app.maybeLockEntryPreviewGroupOnAdd ) + .on( 'wpformsFieldMove', app.maybeLockEntryPreviewGroupOnMove ) + .on( 'click', '.wpforms-entry-preview-block', app.entryPreviewBlockField ); + + app.defaultStateEntryPreviewNotice(); + }, + + /** + * Event handler for the Read-Only toggle. + * + * @since 1.9.8 + */ + fieldReadOnlyToggleChange() { + const $input = $( this ); + const fieldId = Number( $input.closest( '.wpforms-field-option-row' ).data( 'field-id' ) ); + const isChecked = $input.is( ':checked' ); + const $dependentToggles = $( `#wpforms-field-option-row-${ fieldId }-required, #wpforms-field-option-row-${ fieldId }-unique_answer` ); + const $requiredInput = $dependentToggles.filter( '.wpforms-field-option-row-required' ).find( 'input' ); + + // Disable/Enable the dependent toggles. + app.fieldReadOnlyToggleDependentToggles( $dependentToggles, isChecked ); + + // Toggle CSS classes in the field preview container. + $( `#wpforms-field-${ fieldId }` ) + .toggleClass( 'readonly', isChecked ) + .toggleClass( 'required', $requiredInput.is( ':checked' ) ); + }, + + /** + * Disable/Enable the dependent toggles. + * + * @since 1.9.8 + * + * @param {Object} $toggles jQuery object with toggles to operate. + * @param {boolean} disable True to disable, false to enable. + */ + fieldReadOnlyToggleDependentToggles( $toggles, disable = true ) { + $toggles.each( function() { + const $optionRow = $( this ); + const $optionInput = $optionRow.find( ':input' ); + const setDataChecked = disable ? $optionInput.is( ':checked' ) : null; + const setChecked = disable ? false : $optionInput.data( 'enabled-state-checked' ); + const setTitle = disable ? wp.i18n.__( 'Disabled because this field is set to Read-Only in the Advanced tab.', 'wpforms' ) : ''; + + $optionRow + .toggleClass( 'wpforms-disabled', disable ) + .find( '.wpforms-toggle-control' ) + .attr( 'title', setTitle ); + $optionInput + .data( 'enabled-state-checked', setDataChecked ) + .prop( 'checked', setChecked ) + .prop( 'disabled', disable ); + } ); + }, + + /** + * Check if we had focusout event from certain fields. + * + * @since 1.7.5 + */ + focusOutEvent() { + if ( elements.$focusOutTarget === null ) { + return; + } + + if ( elements.$defaultEmail.is( elements.$focusOutTarget ) ) { + const $field = elements.$focusOutTarget; + + $field.next( '.wpforms-alert' ).remove(); + + if ( $field.val() === '' ) { + return; + } + + $.get( + wpforms_builder.ajax_url, + { + nonce: wpforms_builder.nonce, + content: $field.val(), + action: 'wpforms_sanitize_default_email', + }, + function( res ) { + if ( res.success ) { + $field.val( res.data ); + $field.trigger( 'input' ); + + if ( ! res.data ) { + $field.after( '

' + wpforms_builder.restricted_default_email + '

' ); + } + } + } + ); + } + + elements.$focusOutTarget = null; + }, + + /** + * Determine if the field is disabled for selection/duplication/deletion. + * + * @since 1.7.1 + * + * @param {any} el DOM element or jQuery object of some container on the field preview. + * + * @return {boolean} True if actions are disabled. + */ + isFieldPreviewActionsDisabled( el ) { + return app.isFormPreviewActionsDisabled( el ) || + $( el ).closest( '.wpforms-field' ).hasClass( 'ui-sortable-disabled' ); + }, + + /** + * Determine if form wrapper has sorting locked. + * + * @since 1.7.6 + * + * @param {any} el DOM element or jQuery object of some container on the field preview. + * + * @return {boolean} True when form preview wrapper sorting is disabled. + */ + isFormPreviewActionsDisabled( el ) { + return $( el ).closest( '.wpforms-field-wrap' ).hasClass( 'ui-sortable-disabled' ); + }, + + /** + * Toggle field group visibility in the field sidebar. + * + * @since 1.0.0 + * + * @param {any} el DOM element or jQuery object. + * @param {string} action Action. + */ + fieldGroupToggle( el, action ) { + /** @type {JQ|jQuery} */ + const $this = $( el ); + let $buttons = $this.next( '.wpforms-add-fields-buttons' ); + const $group = $buttons.parent(); + let $icon = $this.find( 'i' ), + groupName = $this.data( 'group' ), + cookieName = 'wpforms_field_group_' + groupName; + + if ( action === 'click' ) { + if ( $group.hasClass( 'wpforms-closed' ) ) { + wpCookies.remove( cookieName ); + } else { + wpCookies.set( cookieName, 'true', 2592000 ); // 1 month + } + $icon.toggleClass( 'wpforms-angle-right' ); + $buttons.stop().slideToggle( '', function() { + $group.toggleClass( 'wpforms-closed' ); + } ); + + return; + } + + if ( action === 'load' ) { + $buttons = $this.find( '.wpforms-add-fields-buttons' ); + $icon = $this.find( '.wpforms-add-fields-heading i' ); + groupName = $this.find( '.wpforms-add-fields-heading' ).data( 'group' ); + cookieName = 'wpforms_field_group_' + groupName; + + if ( wpCookies.get( cookieName ) === 'true' ) { + $icon.toggleClass( 'wpforms-angle-right' ); + $buttons.hide(); + $this.toggleClass( 'wpforms-closed' ); + } + } + }, + + /** + * Update description. + * + * @since 1.6.9 + * + * @param {jQuery} $el Element. + * @param {string} value Value. + */ + updateDescription( $el, value ) { + if ( $el.hasClass( 'nl2br' ) ) { + value = value.replace( /\n/g, '
' ); + } + + $el.html( value ); + }, + + /** + * Set the default state for the entry preview notice field. + * + * @since 1.6.9 + */ + defaultStateEntryPreviewNotice() { + $( '.wpforms-field-option-row-preview-notice-enable input' ).each( function() { + $( this ).trigger( 'change' ); + } ); + }, + + /** + * Update a preview notice for the field preview. + * + * @since 1.6.9 + */ + updatePreviewNotice() { + const $this = $( this ); + let value = wpf.sanitizeHTML( $this.val() ).trim(); + const id = $this.parent().data( 'field-id' ), + $field = $( '#wpforms-field-' + id ).find( '.wpforms-entry-preview-notice' ); + + value = value ? value : wpforms_builder.entry_preview_default_notice; + + app.updateDescription( $field, value ); + }, + + /** + * Show/hide entry preview notice for the field preview. + * + * @since 1.6.9 + */ + toggleEntryPreviewNotice() { + const $this = $( this ), + id = $this.closest( '.wpforms-field-option' ).data( 'field-id' ), + $field = $( '#wpforms-field-' + id ), + $noticeField = $( '#wpforms-field-option-' + id + ' .wpforms-field-option-row-preview-notice' ), + $notice = $field.find( '.wpforms-entry-preview-notice' ), + $defaultNotice = $field.find( '.wpforms-alert-info' ); + + if ( $this.is( ':checked' ) ) { + $defaultNotice.hide(); + $notice.show(); + $noticeField.show(); + + return; + } + + $noticeField.hide(); + $notice.hide(); + $defaultNotice.show(); + }, + + /** + * Delete a field. + * + * @param {number} id Field ID. + * + * @since 1.0.0 + * @since 1.6.9 Add the entry preview logic. + */ + fieldDelete( id ) { + const $field = $( '#wpforms-field-' + id ), + type = $field.data( 'field-type' ); + + if ( type === 'pagebreak' && $field.hasClass( 'wpforms-field-entry-preview-not-deleted' ) ) { + app.youCantRemovePageBreakFieldPopup(); + + return; + } + + if ( $field.hasClass( 'no-delete' ) ) { + app.youCantRemoveFieldPopup(); + + return; + } + + app.confirmFieldDeletion( id, type ); + }, + + /** + * Show the error message in the popup that you cannot remove the page break field. + * + * @since 1.6.9 + */ + youCantRemovePageBreakFieldPopup() { + $.alert( { + title: wpforms_builder.heads_up, + content: wpforms_builder.entry_preview_require_page_break, + icon: 'fa fa-exclamation-circle', + type: 'red', + buttons: { + confirm: { + text: wpforms_builder.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + }, + }, + } ); + }, + + /** + * Show the error message in the popup that you cannot reorder the field. + * + * @since 1.7.1 + * @since 1.7.7 Deprecated. + * + * @deprecated Use `WPForms.Admin.Builder.DragFields.youCantReorderFieldPopup()` instead. + */ + youCantReorderFieldPopup() { + // eslint-disable-next-line no-console + console.warn( 'WARNING! Function "WPFormsBuilder.youCantReorderFieldPopup()" has been deprecated, please use the new "WPForms.Admin.Builder.DragFields.youCantReorderFieldPopup()" function instead!' ); + + WPForms.Admin.Builder.DragFields.youCantReorderFieldPopup(); + }, + + /** + * Show the error message in the popup that you cannot remove the field. + * + * @since 1.6.9 + */ + youCantRemoveFieldPopup() { + $.alert( { + title: wpforms_builder.field_locked, + content: wpforms_builder.field_locked_no_delete_msg, + icon: 'fa fa-info-circle', + type: 'blue', + buttons: { + confirm: { + text: wpforms_builder.close, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + }, + }, + } ); + }, + + /** + * Error alert displayed for invalid From Email Notification field. + * + * @since 1.8.1 + * @deprecated 1.9.5 + * + * @param {string} msg Message. + */ + validationErrorNotificationPopup( msg ) { + // eslint-disable-next-line no-console + console.warn( 'WARNING! Function "WPFormsBuilder.validationErrorNotificationPopup()" has been deprecated.' ); + + $.alert( { + title: wpforms_builder.heads_up, + content: msg, + icon: 'fa fa-exclamation-circle', + type: 'red', + buttons: { + confirm: { + text: wpforms_builder.close, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + }, + }, + } ); + }, + + /** + * Show the confirmation popup before the field deletion. + * + * @param {number} id Field ID. + * @param {string} type Field type. + * + * @since 1.6.9 + */ + confirmFieldDeletion( id, type ) { + const fieldData = { + id, + message: wpforms_builder.delete_confirm, + }; + + const event = WPFormsUtils.triggerEvent( $builder, 'wpformsBeforeFieldDeleteAlert', [ fieldData, type ] ); + + // Allow callbacks on `wpformsBeforeFieldDeleteAlert` to prevent field deletion by triggering `event.preventDefault()`. + if ( event.isDefaultPrevented() ) { + return; + } + + $.confirm( { + title: false, + content: fieldData.message, + icon: 'fa fa-exclamation-circle', + type: 'orange', + buttons: { + confirm: { + text: wpforms_builder.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + action() { + app.fieldDeleteById( id ); + }, + }, + cancel: { + text: wpforms_builder.cancel, + }, + }, + } ); + }, + + /** + * Remove the field by ID. + * + * @since 1.6.9 + * + * @param {number} id Field ID. + * @param {string} type Field type (deprecated) + * @param {number} duration Duration of animation. + */ + fieldDeleteById( id, type = '', duration = 400 ) { + $( `#wpforms-field-${ id }` ).fadeOut( duration, function() { + const $field = $( this ); + const $layoutParents = $field.parents( '.wpforms-field-layout-columns' ); + + type = $field.data( 'field-type' ); + + $builder.trigger( 'wpformsBeforeFieldDelete', [ id, type ] ); + + $field.remove(); + $( '#wpforms-field-option-' + id ).remove(); + $( '.wpforms-field, .wpforms-title-desc' ).removeClass( 'active' ); + app.fieldTabToggle( 'add-fields' ); + + const $fieldsOptions = $( '.wpforms-field-option' ), + $submitButton = $builder.find( '.wpforms-field-submit' ); + + // No fields remains. + if ( $fieldsOptions.length < 1 ) { + elements.$sortableFieldsWrap.append( elements.$noFieldsPreview.clone() ); + elements.$fieldOptions.append( elements.$noFieldsOptions.clone() ); + $submitButton.hide(); + } + + // Only Layout fields remains. + if ( ! $fieldsOptions.filter( ':not(.wpforms-field-option-layout)' ).length ) { + $submitButton.hide(); + } + + $builder.trigger( 'wpformsFieldDelete', [ id, type, $layoutParents ] ); + } ); + }, + + /** + * Determine which sections to activate for each panel. + * + * @since 1.9.3 + */ + determineActiveSections() { + const sectionFromUrl = wpf.getQueryString( 'section' ); + + // Gets the section to activate based on the URL. + const getSectionFromUrl = ( $panel, sectionFromUrl ) => { + if ( ! sectionFromUrl || ! $panel.hasClass( 'active' ) ) { + return null; + } + + const $sectionElement = $panel.find( `.wpforms-panel-sidebar-section[data-section="${ sectionFromUrl }"]` ); + + // Skip non-existing or non-accessible section. + if ( $sectionElement.length === 0 || $sectionElement.hasClass( 'wpforms-panel-sidebar-section-no-access' ) ) { + return null; + } + + return $sectionElement; + }; + + // Gets the configured section within a panel to activate, if available. + const getConfiguredSection = ( $panel ) => { + const $configuredSection = $panel.find( '.wpforms-panel-sidebar-section.configured' ).first(); + + return $configuredSection.length ? $configuredSection : null; + }; + + // Gets the first available section in the sidebar to activate. + const getFirstAvailableSection = ( $panel ) => { + return $panel.find( '.wpforms-panel-sidebar-section:first-of-type' ); + }; + + // Activates the specified section within a panel and its corresponding content section. + const activateSection = ( $panel, $sectionToActivate ) => { + if ( ! $sectionToActivate ) { + return; + } + + const sectionNameToActivate = $sectionToActivate.data( 'section' ); + $sectionToActivate.addClass( 'active' ); + const $contentSection = $panel.find( `.wpforms-panel-content-section-${ sectionNameToActivate }` ); + + if ( $contentSection.length ) { + $contentSection.show().addClass( 'active' ); + $panel.find( '.wpforms-panel-content-section-default' ).toggle( sectionNameToActivate === 'default' ); + } else { + $panel.find( '.wpforms-panel-content-section-default' ).show().addClass( 'active' ); + } + + WPFormsUtils.triggerEvent( $builder, 'wpformsPanelSectionSwitch', sectionNameToActivate ); + }; + + // Iterate through each panel and determine which section to activate. + $( '.wpforms-panel' ).each( function() { + const $panel = $( this ); + const $sectionToActivate = getSectionFromUrl( $panel, sectionFromUrl ) || + getConfiguredSection( $panel ) || + getFirstAvailableSection( $panel ); + + activateSection( $panel, $sectionToActivate ); + } ); + }, + + /** + * Load entry preview fields. + * + * @since 1.6.9 + */ + loadEntryPreviewFields() { + const $fields = $( '#wpforms-panel-fields .wpforms-field-wrap .wpforms-field-entry-preview' ); + + if ( ! $fields.length ) { + return; + } + + $fields.each( function() { + app.lockEntryPreviewFieldsPosition( $( this ).data( 'field-id' ) ); + } ); + }, + + /** + * Delete the entry preview field from the form preview. + * + * @since 1.6.9 + * + * @param {Event} event Event. + * @param {number} id Field ID. + * @param {string} type Field type. + */ + fieldEntryPreviewDelete( event, id, type ) { + if ( 'entry-preview' !== type ) { + return; + } + + const $field = $( '#wpforms-field-' + id ), + $previousPageBreakField = $field.prevAll( '.wpforms-field-pagebreak' ).first(), + $nextPageBreakField = $field.nextAll( '.wpforms-field-pagebreak' ).first(), + nextPageBreakId = $nextPageBreakField.data( 'field-id' ), + $nextPageBreakOptions = $( '#wpforms-field-option-' + nextPageBreakId ); + + $previousPageBreakField.removeClass( 'wpforms-field-not-draggable wpforms-field-entry-preview-not-deleted' ); + $nextPageBreakOptions.find( '.wpforms-entry-preview-block' ).removeClass( 'wpforms-entry-preview-block' ); + + $builder.trigger( 'wpformsFieldDragToggle', [ $previousPageBreakField.data( 'field-id' ), $previousPageBreakField.data( 'field-type' ) ] ); + }, + + /** + * Maybe lock the entry preview and fields nearby after the move event. + * + * @since 1.6.9 + * + * @param {Event} e Event. + * @param {Object} ui UI sortable object. + */ + maybeLockEntryPreviewGroupOnMove( e, ui ) { + if ( ! ui.item.hasClass( 'wpforms-field-pagebreak' ) ) { + return; + } + + app.maybeLockEntryPreviewGroupOnAdd( e, ui.item.data( 'field-id' ), 'pagebreak' ); + }, + + /** + * Maybe lock the entry preview and fields nearby after adding the event. + * + * @since 1.6.9 + * + * @param {Event} e Event. + * @param {number} fieldId Field id. + * @param {string} type Field type. + */ + maybeLockEntryPreviewGroupOnAdd( e, fieldId, type ) { + if ( type !== 'pagebreak' ) { + return; + } + + const $currentField = $( '#wpforms-field-' + fieldId ), + $prevField = $currentField.prevAll( '.wpforms-field-entry-preview,.wpforms-field-pagebreak' ).first(), + $nextField = $currentField.nextAll( '.wpforms-field-entry-preview,.wpforms-field-pagebreak' ).first(); + + if ( ! $prevField.hasClass( 'wpforms-field-entry-preview' ) && ! $nextField.hasClass( 'wpforms-field-entry-preview' ) ) { + return; + } + + const $currentFieldPrevToggle = $( '#wpforms-field-option-' + fieldId + ' .wpforms-field-option-row-prev_toggle' ), + $currentFieldPrevToggleField = $currentFieldPrevToggle.find( 'input' ), + $nextFieldPrevToggle = $( '#wpforms-field-option-' + $nextField.data( 'field-id' ) + ' .wpforms-field-option-row-prev_toggle' ); + + if ( $prevField.hasClass( 'wpforms-field-entry-preview' ) ) { + $currentFieldPrevToggleField.attr( 'checked', 'checked' ).trigger( 'change' ); + $currentFieldPrevToggle.addClass( 'wpforms-entry-preview-block' ); + $nextFieldPrevToggle.removeClass( 'wpforms-entry-preview-block' ); + + return; + } + + const prevFieldId = $prevField.data( 'field-id' ), + $prevFieldPrevToggle = $( '#wpforms-field-option-' + prevFieldId + ' .wpforms-field-option-row-prev_toggle' ), + $prevFieldPrevToggleField = $prevFieldPrevToggle.find( 'input' ); + + $currentField.addClass( 'wpforms-field-not-draggable wpforms-field-entry-preview-not-deleted' ); + $builder.trigger( 'wpformsFieldDragToggle', [ fieldId, type ] ); + $prevField.removeClass( 'wpforms-field-not-draggable wpforms-field-entry-preview-not-deleted' ); + $builder.trigger( 'wpformsFieldDragToggle', [ prevFieldId, $prevField.data( 'field-type' ) ] ); + + if ( $prevField.prevAll( '.wpforms-field-entry-preview,.wpforms-field-pagebreak' ).first().hasClass( 'wpforms-field-entry-preview' ) ) { + $prevFieldPrevToggleField.attr( 'checked', 'checked' ).trigger( 'change' ); + $prevFieldPrevToggle.addClass( 'wpforms-entry-preview-block' ); + } + }, + + /** + * Show the error popup that the entry preview field blocks the field. + * + * @since 1.6.9 + * + * @param {Event} e Event. + */ + entryPreviewBlockField( e ) { + e.preventDefault(); + + $.alert( { + title: wpforms_builder.heads_up, + content: wpforms_builder.entry_preview_require_previous_button, + icon: 'fa fa-exclamation-circle', + type: 'red', + buttons: { + confirm: { + text: wpforms_builder.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + }, + }, + } ); + }, + + /** + * Is it an entry preview field that should be checked before adding? + * + * @since 1.6.9 + * + * @param {string} type Field type. + * @param {Object} options Field options. + * + * @return {boolean} True when we should check it. + */ + isUncheckedEntryPreviewField( type, options ) { + // eslint-disable-next-line no-mixed-operators + return type === 'entry-preview' && ( ! options || options && ! options.passed ); + }, + + /** + * Add an entry preview field to the form preview. + * + * @since 1.6.9 + * + * @param {string} type Field type. + * @param {Object} options Field options. + */ + addEntryPreviewField( type, options ) { // eslint-disable-line complexity + const addButton = $( '#wpforms-add-fields-entry-preview' ); + + if ( addButton.hasClass( 'wpforms-entry-preview-adding' ) ) { + return; + } + + const $fields = $( '#wpforms-panel-fields .wpforms-field-wrap > .wpforms-field' ), + position = options?.position ? options.position : $fields.length, + needPageBreakBefore = app.isEntryPreviewFieldRequiresPageBreakBefore( $fields, position ), + needPageBreakAfter = app.isEntryPreviewFieldRequiresPageBreakAfter( $fields, position ); + + addButton.addClass( 'wpforms-entry-preview-adding' ); + + if ( ! options ) { + options = {}; + } + + options.passed = true; + + if ( ! needPageBreakBefore && ! needPageBreakAfter ) { + app.fieldAdd( 'entry-preview', options ).done( function( res ) { + app.lockEntryPreviewFieldsPosition( res.data.field.id ); + } ); + + return; + } + + if ( needPageBreakBefore ) { + app.addPageBreakAndEntryPreviewFields( options, position ); + + return; + } + + app.addEntryPreviewAndPageBreakFields( options, position ); + }, + + /** + * Add the entry preview field after the page break field. + * We should wait for the page break adding to avoid id duplication. + * + * @since 1.6.9 + * + * @param {Object} options Field options. + */ + addEntryPreviewFieldAfterPageBreak( options ) { + const checkExist = setInterval( function() { + if ( $( '#wpforms-panel-fields .wpforms-field-wrap' ).find( '.wpforms-pagebreak-bottom, .wpforms-pagebreak-top' ).length === 2 ) { + app.fieldAdd( 'entry-preview', options ).done( function( res ) { + app.lockEntryPreviewFieldsPosition( res.data.field.id ); + } ); + clearInterval( checkExist ); + } + }, 100 ); + }, + + /** + * Add the entry preview field after the page break field. + * + * @since 1.6.9 + * + * @param {Object} options Field options. + * @param {number} position The field position. + */ + addPageBreakAndEntryPreviewFields( options, position ) { + const hasPageBreak = $( '#wpforms-panel-fields .wpforms-field-wrap > .wpforms-field-pagebreak' ).length >= 3; + + app.fieldAdd( 'pagebreak', { position } ).done( function( res ) { + options.position = hasPageBreak ? position + 1 : position + 2; + app.addEntryPreviewFieldAfterPageBreak( options ); + + const $pageBreakOptions = $( '#wpforms-field-option-' + res.data.field.id ), + $pageBreakPrevToggle = $pageBreakOptions.find( '.wpforms-field-option-row-prev_toggle' ), + $pageBreakPrevToggleField = $pageBreakPrevToggle.find( 'input' ); + + $pageBreakPrevToggleField.attr( 'checked', 'checked' ).trigger( 'change' ); + $pageBreakPrevToggle.addClass( 'wpforms-entry-preview-block' ); + } ); + }, + + /** + * Duplicate field. + * + * @since 1.2.9 + * + * @param {string} id Field id. + */ + fieldDuplicate( id ) { + const $field = $( `#wpforms-field-${ id }` ); + + if ( $field.hasClass( 'no-duplicate' ) ) { + $.alert( { + title: wpforms_builder.field_locked, + content: wpforms_builder.field_locked_no_duplicate_msg, + icon: 'fa fa-info-circle', + type: 'blue', + buttons: { + confirm: { + text: wpforms_builder.close, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + }, + }, + } ); + + return; + } + + $.confirm( { + title: false, + content: wpforms_builder.duplicate_confirm, + icon: 'fa fa-exclamation-circle', + type: 'orange', + buttons: { + confirm: { + text: wpforms_builder.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + action() { + // Disable the current button to avoid firing multiple click events. + // By default, "jconfirm" tends to destroy any modal DOM element upon button click. + this.$$confirm.prop( 'disabled', true ); + + const beforeEvent = WPFormsUtils.triggerEvent( $builder, 'wpformsBeforeFieldDuplicate', [ id, $field ] ); + + // Allow callbacks on `wpformsFieldBeforeDuplicate` to cancel field duplication. + if ( beforeEvent.isDefaultPrevented() ) { + return; + } + + const newFieldId = app.fieldDuplicateRoutine( id, true ), + $newField = $( `#wpforms-field-${ newFieldId }` ); + + // Lastly, update the next ID stored in the database. + app.increaseNextFieldIdAjaxRequest(); + + WPFormsUtils.triggerEvent( $builder, 'wpformsFieldDuplicated', [ id, $field, newFieldId, $newField ] ); + }, + }, + cancel: { + text: wpforms_builder.cancel, + }, + }, + } ); + }, + + /** + * Update the next ID stored in the database. + * + * @since 1.7.7 + */ + increaseNextFieldIdAjaxRequest() { + /* eslint-disable camelcase */ + $.post( + wpforms_builder.ajax_url, + { + form_id: s.formID, + field_id: elements.$nextFieldId.val(), + nonce: wpforms_builder.nonce, + action: 'wpforms_builder_increase_next_field_id', + } + ); + }, + + /** + * Duplicate field routine. + * + * @since 1.7.7 + * + * @param {number|string} id Field ID. + * @param {boolean} changeLabel Is it necessary to change the label and add a copy suffix. + * + * @return {number} New field ID. + */ + fieldDuplicateRoutine( id, changeLabel = true ) { // eslint-disable-line max-lines-per-function, complexity + const $field = $( `#wpforms-field-${ id }` ), + $fieldOptions = $( `#wpforms-field-option-${ id }` ), + $fieldActive = elements.$sortableFieldsWrap.find( '>.active' ), + $visibleOptions = elements.$fieldOptions.find( '>:visible' ), + $visibleTab = $visibleOptions.find( '>.active' ), + type = $field.data( 'field-type' ), + fieldOptionsClass = $fieldOptions.attr( 'class' ), + isModernDropdown = app.dropdownField.helpers.isModernSelect( $field.find( '> .choices .primary-input' ) ); + + // Restore tooltips before cloning. + wpf.restoreTooltips( $fieldOptions ); + + // Force Modern Dropdown conversion to classic before cloning. + if ( isModernDropdown ) { + app.dropdownField.helpers.convertModernToClassic( id ); + } + + let newFieldOptions = $fieldOptions.html(); + + const $newField = $field.clone(), + newFieldID = parseInt( elements.$nextFieldId.val(), 10 ), + $fieldLabel = $( `#wpforms-field-option-${ id }-label` ), + fieldLabelVal = $fieldLabel.length ? $fieldLabel.val() : $( `#wpforms-field-option-${ id }-name` ).val(), + nextID = newFieldID + 1, + regex = {}; + + const newFieldLabel = fieldLabelVal !== '' + ? `${ fieldLabelVal } ${ wpforms_builder.duplicate_copy }` + : `${ wpforms_builder.field } #${ id } ${ wpforms_builder.duplicate_copy }`; + + regex.fieldOptionsID = new RegExp( 'ID #' + id, 'g' ); + regex.fieldID = new RegExp( 'fields\\[' + id + '\\]', 'g' ); + regex.dataFieldID = new RegExp( 'data-field-id="' + id + '"', 'g' ); + regex.referenceID = new RegExp( 'data-reference="' + id + '"', 'g' ); + regex.elementID = new RegExp( '\\b(id|for)="wpforms-(.*?)' + id + '(.*?)"', 'ig' ); + + // Toggle visibility states. + $field.after( $newField ); + $fieldActive.removeClass( 'active' ); + $newField.addClass( 'active' ).attr( { + id: `wpforms-field-${ newFieldID }`, + 'data-field-id': newFieldID, + } ); + + // Various regexes to adjust the field options to work with the new field ID. + regex.elementIdReplace = function( match, p1, p2, p3 ) { + return `${ p1 }="wpforms-${ p2 }${ newFieldID }${ p3 }"`; + }; + + newFieldOptions = newFieldOptions.replace( regex.fieldOptionsID, `ID #${ newFieldID }` ); + newFieldOptions = newFieldOptions.replace( regex.fieldID, `fields[${ newFieldID }]` ); + newFieldOptions = newFieldOptions.replace( regex.dataFieldID, `data-field-id="${ newFieldID }"` ); + newFieldOptions = newFieldOptions.replace( regex.referenceID, `data-reference="${ newFieldID }"` ); + newFieldOptions = newFieldOptions.replace( regex.elementID, regex.elementIdReplace ); + + // Hide all field options panels. + $visibleOptions.hide(); + + // Add a new field options panel. + $fieldOptions.after( `
${ newFieldOptions }
` ); + + // Get a new field options panel. + const $newFieldOptions = $( `#wpforms-field-option-${ newFieldID }` ); + + // If the user duplicates an active field. + if ( $fieldActive.data( 'field-id' ) === id && $visibleTab.length ) { + // The following will help identify which tab from the sidebar panel settings is currently being viewed, + // i.e., "General," "Advanced," "Smart Logic," etc. + const visibleTabClassName = $visibleTab.attr( 'class' ).match( /wpforms-field-option-group-\S*/i )[ 0 ]; + const $newFieldOptionsTab = $newFieldOptions.find( `>.${ visibleTabClassName }` ); + + // Remove any left-over state from previously duplicated options. + $newFieldOptions.find( '>' ).removeClass( 'active' ); + + // Set the active tab to the same tab that was active before the duplication. + $newFieldOptionsTab.addClass( 'active' ); + } + + // If the user duplicates an inactive field. + if ( $fieldActive.data( 'field-id' ) !== id && $visibleTab.length ) { + // Remove the active class from the current active tab. + $newFieldOptions.find( '>' ).removeClass( 'active' ); + + // Set the active tab to "General". + $newFieldOptions.find( '>.wpforms-field-option-group-basic' ).addClass( 'active' ); + } + + // Copy over values. + $fieldOptions.find( ':input' ).each( function() { // eslint-disable-line complexity + const $this = $( this ), + name = $this.attr( 'name' ); + + if ( ! name ) { + return 'continue'; + } + + const newName = name.replace( regex.fieldID, `fields[${ newFieldID }]` ), + type = $this.attr( 'type' ); + + if ( type === 'checkbox' || type === 'radio' ) { + if ( $this.is( ':checked' ) ) { + $newFieldOptions.find( `[name="${ newName }"]` ) + .prop( 'checked', true ) + .attr( 'checked', 'checked' ); + } else { + $newFieldOptions.find( `[name="${ newName }"]` ) + .prop( 'checked', false ) + .attr( 'checked', false ); + } + + return; + } + + if ( $this.is( 'select' ) ) { + if ( $this.find( 'option:selected' ).length ) { + const optionVal = $this.find( 'option:selected' ).val(); + + $newFieldOptions.find( `[name="${ newName }"]` ) + .find( `[value="${ optionVal }"]` ) + .prop( 'selected', true ); + } + + return; + } + + const value = $this.val(); + + if ( value === '' && $this.hasClass( 'wpforms-money-input' ) ) { + $newFieldOptions.find( `[name="${ newName }"]` ).val( + wpf.numberFormat( '0', wpforms_builder.currency_decimals, wpforms_builder.currency_decimal, wpforms_builder.currency_thousands ) + ); + } else { + // We've removed the empty value check here. + // If we are duplicating a field with no value, we should respect that. + $newFieldOptions.find( `[name="${ newName }"]` ).val( value ); + } + } ); + + // ID adjustments. + $newFieldOptions.find( '.wpforms-field-option-hidden-id' ).val( newFieldID ); + elements.$nextFieldId.val( nextID ); + + const $newFieldLabel = type === 'html' ? $( `#wpforms-field-option-${ newFieldID }-name` ) : $( `#wpforms-field-option-${ newFieldID }-label` ); + + // Adjust the label to indicate this is a copy. + if ( changeLabel ) { + $newFieldLabel.val( newFieldLabel ).trigger( 'input' ); + } + + // Fire field adds custom event. + $builder.trigger( 'wpformsFieldAdd', [ newFieldID, type ] ); + + // Re-init tooltips for a new field options panel. + wpf.initTooltips(); + + // Re-init Modern Dropdown. + if ( isModernDropdown ) { + app.dropdownField.helpers.convertClassicToModern( id ); + app.dropdownField.helpers.convertClassicToModern( newFieldID ); + } + + // Re-init instance in choices related fields. + app.fieldChoiceUpdate( $newField.data( 'field-type' ), newFieldID ); + + // Re-init color pickers. + app.loadColorPickers(); + + return newFieldID; + }, + + /** + * Add the entry preview field before the page break field. + * + * @since 1.6.9 + * + * @param {Object} options Field options. + * @param {number} position The field position. + */ + addEntryPreviewAndPageBreakFields( options, position ) { + app.fieldAdd( 'entry-preview', options ).done( function( res ) { + const entryPreviewId = res.data.field.id; + + app.fieldAdd( 'pagebreak', { position: position + 1 } ).done( function( res ) { + app.lockEntryPreviewFieldsPosition( entryPreviewId ); + + const $pageBreakField = $( '#wpforms-field-' + res.data.field.id ), + $nextField = $pageBreakField.nextAll( '.wpforms-field-pagebreak, .wpforms-field-entry-preview' ).first(); + + if ( $nextField.hasClass( 'wpforms-field-entry-preview' ) ) { + app.lockEntryPreviewFieldsPosition( $nextField.data( 'field-id' ) ); + } + } ); + } ); + }, + + /** + * Stick an entry preview field after adding. + * + * @since 1.6.9 + * + * @param {number} id ID. + */ + lockEntryPreviewFieldsPosition( id ) { + const $entryPreviewField = $( '#wpforms-field-' + id ), + $pageBreakField = $entryPreviewField.prevAll( '.wpforms-field-pagebreak:not(.wpforms-pagebreak-bottom)' ).first(), + $nextPageBreakField = $entryPreviewField.nextAll( '.wpforms-field-pagebreak' ).first(), + nextPageBreakFieldId = $nextPageBreakField.data( 'field-id' ), + $pageBreakOptions = $( '#wpforms-field-option-' + nextPageBreakFieldId ), + $pageBreakPrevToggle = $pageBreakOptions.find( '.wpforms-field-option-row-prev_toggle' ), + $pageBreakPrevToggleField = $pageBreakPrevToggle.find( 'input' ); + + $entryPreviewField.addClass( 'wpforms-field-not-draggable' ); + $pageBreakField.addClass( 'wpforms-field-not-draggable wpforms-field-entry-preview-not-deleted' ); + $pageBreakPrevToggleField.prop( 'checked', 'checked' ).trigger( 'change' ); + $pageBreakPrevToggle.addClass( 'wpforms-entry-preview-block' ); + $( '#wpforms-add-fields-entry-preview' ).removeClass( 'wpforms-entry-preview-adding' ); + + $builder.trigger( 'wpformsFieldDragToggle', [ id, $entryPreviewField.data( 'field-type' ) ] ); + $builder.trigger( 'wpformsFieldDragToggle', [ $pageBreakField.data( 'field-id' ), $pageBreakField.data( 'field-type' ) ] ); + }, + + /** + * An entry preview field requires a page break that locates before. + * + * @since 1.6.9 + * + * @param {jQuery} $fields List of fields in the form preview. + * @param {number} position The field position. + * + * @return {boolean} True if we need to add a page break field before. + */ + isEntryPreviewFieldRequiresPageBreakBefore( $fields, position ) { + const $beforeFields = $fields.slice( 0, position ).filter( '.wpforms-field-pagebreak,.wpforms-field-entry-preview' ); + let needPageBreakBefore = true; + + if ( ! $beforeFields.length ) { + return needPageBreakBefore; + } + + $( $beforeFields.get().reverse() ).each( function() { + const $this = $( this ); + + if ( $this.hasClass( 'wpforms-field-entry-preview' ) ) { + return false; + } + + if ( $this.hasClass( 'wpforms-field-pagebreak' ) && ! $this.hasClass( 'wpforms-field-stick' ) ) { + needPageBreakBefore = false; + + return false; + } + } ); + + return needPageBreakBefore; + }, + + /** + * An entry preview field requires a page break that locates after. + * + * @since 1.6.9 + * + * @param {jQuery} $fields List of fields in the form preview. + * @param {number} position The field position. + * + * @return {boolean} True if we need to add a page break field after. + */ + isEntryPreviewFieldRequiresPageBreakAfter( $fields, position ) { + const $afterFields = $fields.slice( position ).filter( '.wpforms-field-pagebreak,.wpforms-field-entry-preview' ); + let needPageBreakAfter = Boolean( $afterFields.length ); + + if ( ! $afterFields.length ) { + return needPageBreakAfter; + } + + $afterFields.each( function() { + const $this = $( this ); + + if ( $this.hasClass( 'wpforms-field-entry-preview' ) ) { + return false; + } + + if ( $this.hasClass( 'wpforms-field-pagebreak' ) ) { + needPageBreakAfter = false; + + return false; + } + } ); + + return needPageBreakAfter; + }, + + /** + * Add a new field. + * + * @since 1.0.0 + * @since 1.6.4 Added hCaptcha support. + * + * @param {string} type Field type. + * @param {Object} options Additional options. + * + * @return {Promise|void|jqXHR} jQuery.post() promise interface. + */ + fieldAdd( type, options ) { // eslint-disable-line max-lines-per-function + const $btn = $( `#wpforms-add-fields-${ type }` ); + + if ( $btn.hasClass( 'upgrade-modal' ) || $btn.hasClass( 'education-modal' ) || $btn.hasClass( 'warning-modal' ) ) { + return; + } + + if ( [ 'captcha_turnstile', 'captcha_hcaptcha', 'captcha_recaptcha', 'captcha_none' ].includes( type ) ) { + app.captchaUpdate(); + + return; + } + + adding = true; + + WPForms.Admin.Builder.DragFields.disableDragAndDrop(); + app.disableFormActions(); + + if ( app.isUncheckedEntryPreviewField( type, options ) ) { + app.addEntryPreviewField( type, options ); + + return; + } + + const defaults = { + position: 'bottom', + $sortable: 'base', + placeholder: false, + scroll: true, + defaults: false, + }; + + options = $.extend( {}, defaults, options ); + + const data = { + action: 'wpforms_new_field_' + type, + id: s.formID, + type, + defaults: options.defaults, + nonce: wpforms_builder.nonce, + }; + + return $.post( wpforms_builder.ajax_url, data, function( res ) { // eslint-disable-line complexity + if ( ! res.success ) { + wpf.debug( 'Add field AJAX call is unsuccessful:', res ); + + return; + } + + const $baseFieldsContainer = elements.$sortableFieldsWrap, + /** @type {JQ|jQuery} */ $newField = $( res.data.preview ), + /** @type {JQ|jQuery} */ $newOptions = $( res.data.options ); + + let $fieldContainer = options.$sortable; + + adding = false; + + $newField.css( 'display', 'none' ); + + if ( options.placeholder ) { + options.placeholder.remove(); + } + + if ( options.$sortable === 'default' || ! options.$sortable.length ) { + $fieldContainer = $baseFieldsContainer.find( '.wpforms-fields-sortable-default' ); + } + + if ( options.$sortable === 'base' || ! $fieldContainer.length ) { + $fieldContainer = $baseFieldsContainer; + } + + const event = WPFormsUtils.triggerEvent( + $builder, + 'wpformsBeforeFieldAddToDOM', + [ options, $newField, $newOptions, $fieldContainer ] + ); + + // Allow callbacks on `wpformsBeforeFieldAddToDOM` to cancel adding field + // by triggering `event.preventDefault()`. + if ( event.isDefaultPrevented() ) { + return; + } + + // Add a field to the base level of fields. + // Allow callbacks on `wpformsBeforeFieldAddToDOM` to skip adding field to the base level + // by setting `event.skipAddFieldToBaseLevel = true`. + if ( ! event.skipAddFieldToBaseLevel ) { + app.fieldAddToBaseLevel( options, $newField, $newOptions ); + } + + $newField.fadeIn(); + + $builder.find( '.no-fields, .no-fields-preview' ).remove(); + + if ( $( '.wpforms-field-option:not(.wpforms-field-option-layout)' ).length ) { + $builder.find( '.wpforms-field-submit' ).show(); + } + + // Scroll to the added field. + if ( options.scroll && options.position.length ) { + app.scrollPreviewToField( res.data.field.id ); + } + + // Update next field id hidden input value. + elements.$nextFieldId.val( res.data.field.id + 1 ); + + wpf.initTooltips(); + app.loadColorPickers(); + app.toggleAllOptionGroups(); + + $builder.trigger( 'wpformsFieldAdd', [ res.data.field.id, type ] ); + } ).fail( function( xhr ) { + adding = false; + + wpf.debug( 'Add field AJAX call failed:', xhr.responseText ); + } ).always( function() { + if ( ! adding ) { + WPForms.Admin.Builder.DragFields.enableDragAndDrop(); + app.enableFormActions(); + } + } ); + }, + + /** + * Add a new field to the base level of fields. + * + * @since 1.7.7 + * + * @param {Options} options Field add additional options. + * @param {jQuery} $newField New field preview object. + * @param {jQuery} $newOptions New field options object. + */ + fieldAddToBaseLevel( options, $newField, $newOptions ) { // eslint-disable-line complexity + const $baseFieldsContainer = elements.$sortableFieldsWrap, + $baseFields = $baseFieldsContainer.children( ':not(.wpforms-field-drag-pending, .no-fields-preview)' ), + totalBaseFields = $baseFields.length; + + const $fieldOptions = elements.$fieldOptions; + + if ( options.position === 'top' ) { + // Add a field to the top of base level fields. + $baseFieldsContainer.prepend( $newField ); + $fieldOptions.prepend( $newOptions ); + + return; + } + + const $lastBaseField = $baseFields.last(); + + if ( + options.position === 'bottom' && ( + ! $lastBaseField.length || + ! $lastBaseField.hasClass( 'wpforms-field-stick' ) + ) + ) { + // Add a field to the bottom of base level fields. + $baseFieldsContainer.append( $newField ); + $fieldOptions.append( $newOptions ); + + return; + } + + if ( options.position === 'bottom' ) { + options.position = totalBaseFields; + } + + if ( + options.position === totalBaseFields && + $lastBaseField.length && $lastBaseField.hasClass( 'wpforms-field-stick' ) + ) { + const lastBaseFieldId = $lastBaseField.data( 'field-id' ); + + // Check to see if the last field we have is configured to + // be stuck to the bottom, if so, add the field above it. + $lastBaseField.before( $newField ); + $fieldOptions.find( `#wpforms-field-option-${ lastBaseFieldId }` ).before( $newOptions ); + + return; + } + + const $fieldInPosition = $baseFields.eq( options.position ); + + if ( $fieldInPosition.length ) { + const fieldInPositionId = $fieldInPosition.data( 'field-id' ); + + // Add a field to a specific location. + $fieldInPosition.before( $newField ); + $fieldOptions.find( `#wpforms-field-option-${ fieldInPositionId }` ).before( $newOptions ); + + return; + } + + // Something is wrong. Add the field. This should never occur. + $baseFieldsContainer.append( $newField ); + $fieldOptions.append( $newOptions ); + }, + + /** + * Scroll the preview panel to the desired field. + * + * @since 1.7.7 + * + * @param {number} fieldId Field ID. + */ + scrollPreviewToField( fieldId ) { + const $field = $( `#wpforms-field-${ fieldId }` ), + scrollTop = elements.$fieldsPreviewWrap.scrollTop(), + $layoutField = $field.closest( '.wpforms-field-layout' ); + + let fieldPosition = $field.position().top; + + if ( $layoutField.length ) { + fieldPosition = $layoutField.position().top + fieldPosition + 20; + } + + const scrollAmount = fieldPosition > scrollTop ? fieldPosition - scrollTop : fieldPosition + scrollTop; + + elements.$fieldsPreviewWrap.scrollTop( scrollAmount ); + }, + + /** + * Update CAPTCHA form setting. + * + * @since 1.6.4 + * + * @return {Object} jqXHR. + */ + captchaUpdate() { + const data = { + action: 'wpforms_update_field_captcha', + id: s.formID, + nonce: wpforms_builder.nonce, + }; + + return $.post( wpforms_builder.ajax_url, data, function( res ) { + if ( res.success ) { + const args = { + title: false, + content: false, + icon: 'fa fa-exclamation-circle', + type: 'orange', + boxWidth: '450px', + buttons: { + confirm: { + text: wpforms_builder.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + }, + }, + }, + $enableCheckbox = $( '#wpforms-panel-field-settings-recaptcha' ); + let caseName = res.data.current; + + $enableCheckbox.data( 'provider', res.data.provider ); + + // Possible cases: + // + // not_configured - IF CAPTCHA is not configured in the WPForms plugin settings + // configured_not_enabled - IF CAPTCHA is configured in WPForms plugin settings, but wasn't set in form settings + // configured_enabled - IF CAPTCHA is configured in WPForms plugin and form settings + if ( 'configured_not_enabled' === caseName || 'configured_enabled' === caseName ) { + // Get a correct case name. + caseName = $enableCheckbox.prop( 'checked' ) ? 'configured_enabled' : 'configured_not_enabled'; + + // Check/uncheck a `CAPTCHA` checkbox in form setting. + args.buttons.confirm.action = function() { + $enableCheckbox.prop( 'checked', ( 'configured_not_enabled' === caseName ) ).trigger( 'change' ); + }; + } + + args.title = res.data.cases[ caseName ].title; + args.content = res.data.cases[ caseName ].content; + + // Do you need a Cancel button? + if ( res.data.cases[ caseName ].cancel ) { + args.buttons.cancel = { + text: wpforms_builder.cancel, + keys: [ 'esc' ], + }; + } + + // Call a Confirm modal. + $.confirm( args ); + } else { + // eslint-disable-next-line no-console + console.log( res ); + } + } ).fail( function( xhr ) { + // eslint-disable-next-line no-console + console.log( xhr.responseText ); + } ); + }, + + /** + * Disable drag & drop. + * + * @since 1.7.1 + * @since 1.7.7 Deprecated. + * + * @deprecated Use `WPForms.Admin.Builder.DragFields.disableDragAndDrop()` instead. + */ + disableDragAndDrop() { + // eslint-disable-next-line no-console + console.warn( 'WARNING! Function "WPFormsBuilder.disableDragAndDrop()" has been deprecated, please use the new "WPForms.Admin.Builder.DragFields.disableDragAndDrop()" function instead!' ); + + WPForms.Admin.Builder.DragFields.disableDragAndDrop(); + }, + + /** + * Enable drag & drop. + * + * @since 1.7.1 + * @since 1.7.7 Deprecated. + * + * @deprecated Use `WPForms.Admin.Builder.DragFields.enableDragAndDrop()` instead. + */ + enableDragAndDrop() { + // eslint-disable-next-line no-console + console.warn( 'WARNING! Function "WPFormsBuilder.enableDragAndDrop()" has been deprecated, please use the new "WPForms.Admin.Builder.DragFields.enableDragAndDrop()" function instead!' ); + + WPForms.Admin.Builder.DragFields.enableDragAndDrop(); + }, + + /** + * Disable Preview, Embed, Save form actions, and Form Builder exit button. + * + * @since 1.7.4 + */ + disableFormActions() { + $.each( + [ + elements.$previewButton, + elements.$embedButton, + elements.$saveButton, + elements.$exitButton, + ], + function( _index, button ) { + button.prop( 'disabled', true ).addClass( 'wpforms-disabled' ); + } + ); + }, + + /** + * Enable Preview, Embed, Save form actions, and Form Builder exit button. + * + * @since 1.7.4 + */ + enableFormActions() { + $.each( + [ + elements.$previewButton, + elements.$embedButton, + elements.$saveButton, + elements.$exitButton, + ], + function( _index, button ) { + button.prop( 'disabled', false ).removeClass( 'wpforms-disabled' ); + } + ); + }, + + /** + * Sortable fields in the builder form the preview area. + * + * @since 1.0.0 + * @since 1.7.7 Deprecated. + * + * @deprecated Use `WPForms.Admin.Builder.DragFields.initSortableFields()` instead. + */ + fieldSortable() { + // eslint-disable-next-line no-console + console.warn( 'WARNING! Function "WPFormsBuilder.fieldSortable()" has been deprecated, please use the new "WPForms.Admin.Builder.DragFields.initSortableFields()" function instead!' ); + + WPForms.Admin.Builder.DragFields.initSortableFields(); + }, + + /** + * Show a popup in case if the field is not draggable and cancel moving. + * + * @since 1.7.5 + * @since 1.7.6 The showPopUp parameter added. + * @since 1.7.7 Deprecated. + * + * @deprecated Use `WPForms.Admin.Builder.DragFields.fieldDragDisable()` instead. + * + * @param {jQuery} $field A field or list of fields. + * @param {boolean} showPopUp Whether the pop-up should be displayed on a dragging attempt. + */ + fieldDragDisable( $field, showPopUp = true ) { + // eslint-disable-next-line no-console + console.warn( 'WARNING! Function "WPFormsBuilder.fieldDragDisable()" has been deprecated, please use the new "WPForms.Admin.Builder.DragFields.fieldDragDisable()" function instead!' ); + + WPForms.Admin.Builder.DragFields.fieldDragDisable( $field, showPopUp ); + }, + + /** + * Allow field dragging. + * + * @since 1.7.5 + * @since 1.7.7 Deprecated. + * + * @deprecated Use `WPForms.Admin.Builder.DragFields.fieldDragEnable()` instead. + * + * @param {jQuery} $field A field or list of fields. + */ + fieldDragEnable( $field ) { + // eslint-disable-next-line no-console + console.warn( 'WARNING! Function "WPFormsBuilder.fieldDragEnable()" has been deprecated, please use the new "WPForms.Admin.Builder.DragFields.fieldDragEnable()" function instead!' ); + + WPForms.Admin.Builder.DragFields.fieldDragEnable( $field ); + }, + + /** + * Add a new field choice. + * + * @since 1.0.0 + * + * @param {Event} event Event. + * @param {Element} el Element. + */ + fieldChoiceAdd( event, el ) { + event.preventDefault(); + + const $this = $( el ), + $parent = $this.parent(), + checked = $parent.find( 'input.default' ).is( ':checked' ), + fieldID = $this.closest( '.wpforms-field-option-row-choices' ).data( 'field-id' ); + let id = $parent.parent().attr( 'data-next-id' ); + const type = $parent.parent().data( 'field-type' ), + $choice = $parent.clone().insertAfter( $parent ); + + $choice.attr( 'data-key', id ); + $choice.find( '.wpforms-icon-select .ic-fa-preview' ).removeClass().addClass( 'ic-fa-preview ic-fa-' + wpforms_builder.icon_choices.default_icon_style + ' ic-fa-' + wpforms_builder.icon_choices.default_icon ); + $choice.find( '.wpforms-icon-select .ic-fa-preview + span' ).text( wpforms_builder.icon_choices.default_icon ); + $choice.find( '.preview' ).empty(); + $choice.find( '.wpforms-image-upload-add' ).show(); + $choice.find( '.wpforms-money-input' ).trigger( 'focusout' ); + + $choice.find( 'input, select' ).each( function() { + const $field = $( this ), + type = $field.attr( 'type' ); + + $field.attr( 'name', $( this ).attr( 'name' ).replace( /\[choices]\[(\d+)]/g, `[choices][${ id }]` ) ); + + if ( type === 'radio' || type === 'checkbox' ) { + $field.prop( 'checked', false ); + } else { + $field.val( '' ); + } + } ); + + $choice.find( '.wpforms-icon-select input.source-icon' ).val( wpforms_builder.icon_choices.default_icon ); + $choice.find( '.wpforms-icon-select input.source-icon-style' ).val( wpforms_builder.icon_choices.default_icon_style ); + + if ( checked === true ) { + $parent.find( 'input.default' ).prop( 'checked', true ); + } + + id++; + + $parent.parent().attr( 'data-next-id', id ); + $builder.trigger( 'wpformsFieldChoiceAdd', [ fieldID ] ); + app.fieldChoiceUpdate( type, fieldID ); + }, + + /** + * Delete field choice. + * + * @since 1.0.0 + * + * @param {Event} e Event. + * @param {Element} el Element. + */ + fieldChoiceDelete( e, el ) { + e.preventDefault(); + + const $this = $( el ), + $list = $this.parent().parent(), + total = $list.find( 'li' ).not( '.wpforms-choice-other-option' ).length, + fieldData = { + id: $list.data( 'field-id' ), + choiceId: $this.closest( 'li' ).data( 'key' ), + message: '' + wpforms_builder.delete_choice_confirm + '', + trigger: false, + }; + + $builder.trigger( 'wpformsBeforeFieldDeleteAlert', [ fieldData ] ); + + if ( total === 1 ) { + app.fieldChoiceDeleteAlert(); + } else { + const deleteChoice = function() { + $this.parent().remove(); + app.fieldChoiceUpdate( $list.data( 'field-type' ), $list.data( 'field-id' ) ); + $builder.trigger( 'wpformsFieldChoiceDelete', [ $list.data( 'field-id' ) ] ); + }; + + if ( ! fieldData.trigger ) { + deleteChoice(); + + return; + } + + $.confirm( { + title: false, + content: fieldData.message, + icon: 'fa fa-exclamation-circle', + type: 'orange', + buttons: { + confirm: { + text: wpforms_builder.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + action() { + deleteChoice(); + }, + }, + cancel: { + text: wpforms_builder.cancel, + }, + }, + } ); + } + }, + + /** + * Field choice delete error alert. + * + * @since 1.6.7 + */ + fieldChoiceDeleteAlert() { + $.alert( { + title: false, + content: wpforms_builder.error_choice, + icon: 'fa fa-info-circle', + type: 'blue', + buttons: { + confirm: { + text: wpforms_builder.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + }, + }, + } ); + }, + + /** + * Make field choices sortable. + * Currently used for select, radio, and checkboxes field types. + * + * @since 1.0.0 + * + * @param {string} type Type. + * @param {string|undefined} selector Selector. + */ + fieldChoiceSortable( type, selector = undefined ) { + selector = typeof selector !== 'undefined' ? selector : '.wpforms-field-option-' + type + ' .wpforms-field-option-row-choices ul'; + + $( selector ).one( 'mouseenter', function() { // eslint-disable-line max-lines-per-function + $( this ).sortable( { + items: 'li:not(.not-draggable)', + axis: 'y', + delay: 100, + opacity: 0.6, + handle: '.move', + stop( e, ui ) { + const id = ui.item.parent().data( 'field-id' ); + app.fieldChoiceUpdate( type, id ); + $builder.trigger( 'wpformsFieldChoiceMove', ui ); + }, + update() { + }, + } ); + } ); + }, + + /** + * Generate Choice label. + * Used in a field preview template. + * + * @since 1.6.2 + * + * @param {Object} data Template data. + * @param {number} choiceID Choice ID. + * + * @return {string} Label. + */ + fieldChoiceLabel( data, choiceID ) { // eslint-disable-line complexity + const isPaymentChoice = [ 'payment-multiple', 'payment-checkbox' ].includes( data.settings.type ), + isIconImageChoice = data.settings.choices_icons || data.settings.choices_images, + isEmptyLabel = typeof data.settings.choices[ choiceID ].label === 'undefined' || data.settings.choices[ choiceID ].label.length === 0; + + // Do not set a placeholder for an empty label in Icon and Image choices except for payment fields. + if ( isEmptyLabel && ! isPaymentChoice && isIconImageChoice ) { + return ''; + } + + const placeholder = isPaymentChoice ? wpforms_builder.payment_choice_empty_label_tpl : wpforms_builder.choice_empty_label_tpl; + let label = ! isEmptyLabel + ? wpf.sanitizeHTML( data.settings.choices[ choiceID ].label, wpforms_builder.allowed_label_html_tags ) + : placeholder.replace( '{number}', choiceID ); + + if ( data.settings.show_price_after_labels ) { + label += ' - ' + wpf.amountFormatCurrency( data.settings.choices[ choiceID ].value ); + } + + return label; + }, + + /** + * Update field choices in the preview area for the Fields panel. + * + * Currently used for select, radio, and checkboxes field types. + * + * @param {string} type Field type. + * @param {string|number} id Field ID. + * @param {number} count Number of choices to show, -1 if not set. + * + * @since 1.0.0 + */ + fieldChoiceUpdate: ( type, id, count = -1 ) => { // eslint-disable-line complexity, max-lines-per-function + const isDynamicChoices = app.dropdownField.helpers.isDynamicChoices( id ); + + if ( app.replaceChoicesWithTemplate( type, id, isDynamicChoices ) ) { + return; + } + + if ( count === -1 ) { + count = app.settings.choicesLimitLong; + } + + // Dropdown payment choices are of a select type. + if ( 'payment-select' === type ) { + type = 'select'; + } + + const $primary = $( '#wpforms-field-' + id + ' .primary-input' ); + + let newChoice = ''; + + if ( 'select' === type ) { + if ( ! isDynamicChoices ) { + newChoice = ''; + $primary.find( 'option' ).not( '.placeholder' ).remove(); + } + } else if ( 'radio' === type || 'checkbox' === type || 'gdpr-checkbox' === type ) { + type = 'gdpr-checkbox' === type ? 'checkbox' : type; + $primary.find( 'li' ).remove(); + newChoice = '
  • {label}
  • '; + } + + // Building an inner content for the Primary field. + const $choicesList = $( `#wpforms-field-option-row-${ id }-choices .choices-list` ), + $choicesToRender = $choicesList.find( 'li' ).slice( 0, count ), + hasDefaults = !! $choicesList.find( 'input.default:checked' ).length, + modernSelectChoices = [], + showPriceAfterLabels = $( '#wpforms-field-option-' + id + '-show_price_after_labels' ).prop( 'checked' ), + isModernSelect = app.dropdownField.helpers.isModernSelect( $primary ); + + $choicesToRender.get().forEach( function( item ) {// eslint-disable-line complexity + const $this = $( item ), + value = $this.find( 'input.value' ).val(), + choiceID = $this.data( 'key' ); + + let label = wpf.sanitizeHTML( $this.find( 'input.label' ).val().trim(), wpforms_builder.allowed_label_html_tags ), + $choice; + + label = label !== '' ? label : wpforms_builder.choice_empty_label_tpl.replace( '{number}', choiceID ); + label += ( showPriceAfterLabels && value ) ? ' - ' + wpf.amountFormatCurrency( value ) : ''; + + // Append a new choice. + if ( ! isModernSelect ) { + if ( ! isDynamicChoices ) { + $choice = $( newChoice.replace( /{label}/g, label ) ); + $primary.append( $choice ); + } + } else { + modernSelectChoices.push( + { + value: label, + label, + } + ); + } + + const selected = $this.find( 'input.default' ).is( ':checked' ); + + if ( true === selected ) { + switch ( type ) { + case 'select': + + if ( ! isModernSelect ) { + app.setClassicSelectedChoice( $choice ); + } else { + modernSelectChoices[ modernSelectChoices.length - 1 ].selected = true; + } + break; + case 'radio': + case 'checkbox': + $choice.find( 'input' ).prop( 'checked', 'true' ); + break; + } + } + } ); + + if ( isModernSelect ) { + const placeholderClass = $primary.prop( 'multiple' ) ? 'input.choices__input' : '.choices__inner .choices__placeholder', + choicesjsInstance = app.dropdownField.helpers.getInstance( $primary ); + + if ( ! isDynamicChoices ) { + choicesjsInstance.removeActiveItems(); + } + + choicesjsInstance.setChoices( modernSelectChoices, 'value', 'label', true ); + + // Re-initialize the modern dropdown to properly determine and update the placeholder. + app.dropdownField.helpers.update( id, isDynamicChoices ); + + // Hide/show a placeholder for Modern select if it has or not default choices. + $primary + .closest( '.choices' ) + .find( placeholderClass ) + .toggleClass( 'wpforms-hidden', hasDefaults ); + } + }, + + /** + * Generate Choice label. + * Used in a field preview template. + * + * @since 1.8.6 + * + * @param {string} type Field type. + * @param {number} id Field ID. + * @param {boolean} isDynamicChoices Whether the field has dynamic choices. + * + * @return {boolean} True if the template was used. + */ + replaceChoicesWithTemplate: ( type, id, isDynamicChoices ) => { // eslint-disable-line complexity + // Radio, Checkbox, and Payment Multiple/Checkbox use _ template. + if ( 'radio' !== type && 'checkbox' !== type && 'payment-multiple' !== type && 'payment-checkbox' !== type ) { + return false; + } + + const order = wpf.getChoicesOrder( id ), + tmpl = wp.template( 'wpforms-field-preview-checkbox-radio-payment-multiple' ); + + const fieldSettings = wpf.getField( id ), + slicedChoices = {}, + slicedOrder = order.slice( 0, app.settings.choicesLimit ), + data = { + settings: fieldSettings, + order: slicedOrder, + type: 'radio', + }; + + // If Icon Choices is on, get the valid color. + if ( fieldSettings.choices_icons ) { + // eslint-disable-next-line camelcase + data.settings.choices_icons_color = app.getValidColorPickerValue( $( '#wpforms-field-option-' + id + '-choices_icons_color' ) ); + } + + // Slice choices for preview. + slicedOrder.forEach( function( entry ) { + slicedChoices[ entry ] = fieldSettings.choices[ entry ]; + } ); + + fieldSettings.choices = slicedChoices; + + if ( 'checkbox' === type || 'payment-checkbox' === type ) { + data.type = 'checkbox'; + } + + if ( ! isDynamicChoices ) { + $( '#wpforms-field-' + id ).find( 'ul.primary-input' ).replaceWith( tmpl( data ) ); + } + + // Toggle limit choices alert message. + app.firstNChoicesAlert( id, order.length ); + + return true; + }, + + /** + * Set the classic selected choice. + * + * @since 1.8.2.3 + * + * @param {jQuery|undefined} $choice Choice option. + */ + setClassicSelectedChoice( $choice ) { + if ( $choice === undefined ) { + return; + } + + $choice.prop( 'selected', 'true' ); + }, + + /** + * Field choice bulk add toggling. + * + * @since 1.3.7 + * + * @param {Object} el jQuery object. + */ + fieldChoiceBulkAddToggle( el ) { + const /** @type {JQ|jQuery} */ $this = $( el ), + /** @type {JQ|jQuery} */ $label = $this.closest( 'label' ); + + if ( $this.hasClass( 'bulk-add-showing' ) ) { + // "Import details" is showing, so hide/remove it. + const $selector = $label.next( '.bulk-add-display' ); + + $selector.slideUp( 400, function() { + $selector.remove(); + } ); + + $this.find( 'span' ).text( wpforms_builder.bulk_add_show ); + } else { + let importOptions = '
    '; + + importOptions += '

    ' + wpforms_builder.bulk_add_heading + ' ' + wpforms_builder.bulk_add_presets_show + '

    '; + importOptions += ''; + importOptions += ''; + importOptions += ''; + importOptions += '
    '; + + $label.after( importOptions ); + $label.next( '.bulk-add-display' ).slideDown( 400, function() { + $( this ).find( 'textarea' ).trigger( 'focus' ); + } ); + $this.find( 'span' ).text( wpforms_builder.bulk_add_hide ); + } + + $this.toggleClass( 'bulk-add-showing' ); + }, + + /** + * Field choice bulk insert the new choices. + * + * @since 1.3.7 + * + * @param {Object} el DOM element. + */ + fieldChoiceBulkAddInsert( el ) { + const $this = $( el ), + $container = $this.closest( '.wpforms-field-option-row' ), + $textarea = $container.find( 'textarea' ), + $list = $container.find( '.choices-list' ), + $choice = $list.find( 'li:first-of-type' ).clone().wrap( '
    ' ).parent(); + let choice = ''; + const fieldID = $container.data( 'field-id' ), + type = $list.data( 'field-type' ); + let nextID = Number( $list.attr( 'data-next-id' ) ); + const newValues = $textarea.val().split( '\n' ); + let newChoices = ''; + + $this.prop( 'disabled', true ).html( $this.html() + ' ' + s.spinner ); + $choice.find( 'input.value,input.label' ).attr( 'value', '' ); + $choice.find( 'input.default' ).attr( 'checked', false ); + $choice.find( 'input.source-icon' ).attr( 'value', wpforms_builder.icon_choices.default_icon ); + $choice.find( 'input.source-icon-style' ).attr( 'value', wpforms_builder.icon_choices.default_icon_style ); + $choice.find( '.ic-fa-preview' ).removeClass().addClass( `ic-fa-preview ic-fa-${ wpforms_builder.icon_choices.default_icon_style } ic-fa-${ wpforms_builder.icon_choices.default_icon }` ); + $choice.find( '.ic-fa-preview + span' ).text( wpforms_builder.icon_choices.default_icon ); + choice = $choice.html(); + + for ( const key in newValues ) { + if ( ! newValues.hasOwnProperty( key ) ) { + continue; + } + + const value = wpf.sanitizeHTML( newValues[ key ] ).trim().replace( /"/g, '"' ); + let newChoice = choice; + + newChoice = newChoice.replace( /\[choices]\[(\d+)]/g, '[choices][' + nextID + ']' ); + newChoice = newChoice.replace( /data-key="(\d+)"/g, 'data-key="' + nextID + '"' ); + newChoice = newChoice.replace( /value="" class="label"/g, 'value="' + value + '" class="label"' ); + + // For some reason, IE has its own attribute order. + newChoice = newChoice.replace( /class="label" type="text" value=""/g, 'class="label" type="text" value="' + value + '"' ); + newChoices += newChoice; + nextID++; + } + + $list.attr( 'data-next-id', nextID ); + + // Ensure the "Other" choice remains the last item in the list. + const $other = $list.find( 'li.wpforms-choice-other-option' ).first(); + if ( $other.length ) { + $other.before( newChoices ); + } else { + $list.append( newChoices ); + } + + app.fieldChoiceUpdate( type, fieldID, nextID ); + $builder.trigger( 'wpformsFieldChoiceAdd' ); + app.fieldChoiceBulkAddToggle( $container.find( '.toggle-bulk-add-display' ) ); + }, + + /** + * Trigger $builder event. + * + * @since 1.9.1 + * + * @param {string} event Event name. + */ + triggerBuilderEvent( event ) { + $builder.trigger( event ); + }, + + /** + * Toggle fields tabs (Add Fields, Field Options). + * + * @since 1.0.0 + * + * @param {number|string} id Field ID or `add-fields` or `field-options`. + * + * @return {false|void} False if event is prevented. + */ + fieldTabToggle( id ) { + const event = WPFormsUtils.triggerEvent( $builder, 'wpformsFieldTabToggle', [ id ] ); + + // Allow callbacks on `wpformsFieldTabToggle` to cancel tab toggle by triggering `event.preventDefault()`. + if ( event.isDefaultPrevented() ) { + return false; + } + + $( '.wpforms-tab a' ).removeClass( 'active' ); + $( '.wpforms-field, .wpforms-title-desc' ).removeClass( 'active' ); + + if ( id === 'add-fields' ) { + elements.$addFieldsTab.addClass( 'active' ); + $( '.wpforms-field-options' ).hide(); + $( '.wpforms-add-fields' ).show(); + } else { + $( '#field-options a' ).addClass( 'active' ); + + if ( id === 'field-options' ) { + const $field = $( '.wpforms-field' ).first(); + + $field.addClass( 'active' ); + id = $field.data( 'field-id' ); + } else { + $( '#wpforms-field-' + id ).addClass( 'active' ); + } + + $( '.wpforms-field-option' ).hide(); + $( '#wpforms-field-option-' + id ).show(); + $( '.wpforms-add-fields' ).hide(); + $( '.wpforms-field-options' ).show(); + + $builder.trigger( 'wpformsFieldOptionTabToggle', [ id ] ); + } + }, + + /** + * Watches fields being added and listens for a pagebreak field. + * + * If a pagebreak field is added, and it's the first one, then we + * automatically add the top and bottom pagebreak elements to the + * builder. + * + * @param {Object} event Current DOM event. + * @param {number} id Field ID. + * @param {string} type Field type. + * + * @since 1.2.1 + */ + fieldPagebreakAdd( event, id, type ) { + /* eslint-disable camelcase */ + + if ( 'pagebreak' !== type ) { + return; + } + + let options; + + if ( ! s.pagebreakTop ) { + s.pagebreakTop = true; + options = { + position: 'top', + scroll: false, + defaults: { + position: 'top', + nav_align: 'left', + }, + }; + + app.fieldAdd( 'pagebreak', options ).done( function( res ) { + s.pagebreakTop = res.data.field.id; + + const $preview = $( '#wpforms-field-' + res.data.field.id ), + $options = $( '#wpforms-field-option-' + res.data.field.id ); + + $options.find( '.wpforms-field-option-group' ).addClass( 'wpforms-pagebreak-top' ); + $preview.addClass( 'wpforms-field-stick wpforms-pagebreak-top' ); + } ); + } else if ( ! s.pagebreakBottom ) { + s.pagebreakBottom = true; + options = { + position: 'bottom', + scroll: false, + defaults: { + position: 'bottom', + }, + }; + app.fieldAdd( 'pagebreak', options ).done( function( res ) { + s.pagebreakBottom = res.data.field.id; + + const $preview = $( '#wpforms-field-' + res.data.field.id ), + $options = $( '#wpforms-field-option-' + res.data.field.id ); + + $options.find( '.wpforms-field-option-group' ).addClass( 'wpforms-pagebreak-bottom' ); + $preview.addClass( 'wpforms-field-stick wpforms-pagebreak-bottom' ); + } ); + } + }, + + /** + * Watches fields being deleted and listens for a pagebreak field. + * + * If a pagebreak field is added, and it's the first one, then we + * automatically add the top and bottom pagebreak elements to the + * builder. + * + * @param {Object} event Current DOM event. + * @param {number} id Field ID. + * @param {string} type Field type. + * + * @since 1.2.1 + */ + fieldPagebreakDelete( event, id, type ) { + if ( 'pagebreak' !== type ) { + return; + } + + const pagebreaksRemaining = $( '#wpforms-panel-fields .wpforms-field-pagebreak' ).not( '.wpforms-pagebreak-top, .wpforms-pagebreak-bottom' ).length; + + if ( pagebreaksRemaining ) { + return; + } + + // All pagebreaks, excluding top/bottom, are gone. + // So we need to remove the top and bottom pagebreak. + const $preview = $( '#wpforms-panel-fields .wpforms-preview-wrap' ), + $top = $preview.find( '.wpforms-pagebreak-top' ), + topID = $top.data( 'field-id' ), + $bottom = $preview.find( '.wpforms-pagebreak-bottom' ), + bottomID = $bottom.data( 'field-id' ); + + $top.remove(); + $( '#wpforms-field-option-' + topID ).remove(); + s.pagebreakTop = false; + $bottom.remove(); + $( '#wpforms-field-option-' + bottomID ).remove(); + s.pagebreakBottom = false; + }, + + /** + * Init Display Previous option for Pagebreak field. + * + * @since 1.5.8 + * + * @param {jQuery} $field Page Break field jQuery object. + */ + fieldPageBreakInitDisplayPrevious( $field ) { + const id = $field.data( 'field-id' ), + $prevToggle = $( '#wpforms-field-option-row-' + id + '-prev_toggle' ), + $prev = $( '#wpforms-field-option-row-' + id + '-prev' ), + $prevBtn = $field.find( '.wpforms-pagebreak-prev' ); + + if ( $field.prevAll( '.wpforms-field-pagebreak.wpforms-pagebreak-normal' ).length > 0 ) { + $prevToggle.removeClass( 'hidden' ); + $prev.removeClass( 'hidden' ); + if ( $prevToggle.find( 'input' ).is( ':checked' ) ) { + $prevBtn.removeClass( 'wpforms-hidden' ).text( $prev.find( 'input' ).val() ); + } + } else { + $prevToggle.addClass( 'hidden' ); + $prev.addClass( 'hidden' ); + $prevBtn.addClass( 'wpforms-hidden' ); + } + }, + + /** + * Field Dynamic Choice toggle. + * + * @since 1.2.8 + * + * @param {Element} el Element. + */ + fieldDynamicChoiceToggle( el ) { // eslint-disable-line complexity, max-lines-per-function + let optionHTML; + const $this = $( el ), + $thisOption = $this.parent(), + value = $this.val(), + id = $thisOption.data( 'field-id' ); + const $choices = $( '#wpforms-field-option-row-' + id + '-choices' ), + $images = $( '#wpforms-field-option-' + id + '-choices_images' ), + $icons = $( '#wpforms-field-option-' + id + '-choices_icons' ), + $otherOption = $( '#wpforms-field-option-' + id + '-choices_other' ), + $basicOptions = $( `#wpforms-field-option-basic-${ id }` ); + + // Hide image and icon choices if "dynamic choices" is not off. + app.fieldDynamicChoiceToggleImageChoices(); + app.fieldDynamicChoiceToggleIconChoices(); + app.fieldDynamicChoiceToggleOtherOption(); + + // Fire an event when a field's dynamic choices option was changed. + $builder.trigger( 'wpformsFieldDynamicChoiceToggle', [ id ] ); + + // Loading + wpf.fieldOptionLoading( $thisOption ); + + // Remove previous dynamic post-type or taxonomy source options. + $( '#wpforms-field-option-row-' + id + '-dynamic_post_type' ).remove(); + $( '#wpforms-field-option-row-' + id + '-dynamic_taxonomy' ).remove(); + + /* + * Post type- or Taxonomy-based dynamic populating. + */ + if ( '' !== value ) { + // Hide choice images and icons options, not applicable. + $images.addClass( 'wpforms-hidden' ); + $icons.addClass( 'wpforms-hidden' ); + $otherOption.addClass( 'wpforms-hidden' ); + + // Hide `Bulk Add` toggle. + $choices.find( '.toggle-bulk-add-display' ).addClass( 'wpforms-hidden' ); + + // Hide the AI Choices button. + $basicOptions.find( '.wpforms-ai-choices-button' ).addClass( 'wpforms-hidden' ); + + // Hide tooltip. + $choices.find( '.wpforms-help-tooltip' ).addClass( 'wpforms-hidden' ); + + const data = { + type: value, + field_id: id, // eslint-disable-line camelcase + action: 'wpforms_builder_dynamic_choices', + nonce: wpforms_builder.nonce, + }; + + $.post( wpforms_builder.ajax_url, data, function( res ) { + if ( res.success ) { + // New option markup. + $thisOption.after( res.data.markup ); + } else { + // eslint-disable-next-line no-console + console.log( res ); + } + + // Hide the loading indicator. + wpf.fieldOptionLoading( $thisOption, true ); + + // Re-init tooltips for a new field. + wpf.initTooltips(); + + // Trigger Dynamic source updates. + const $dynamicValue = $( '#wpforms-field-option-' + id + '-dynamic_' + value ); + + $dynamicValue.find( 'option' ).first().prop( 'selected', true ); + $dynamicValue.trigger( 'change' ); + } ).fail( function( xhr ) { + // eslint-disable-next-line no-console + console.log( xhr.responseText ); + } ); + + return; // Nothing more for dynamic populating. + } + + /* + * "Off" - no dynamic populating. + */ + + let type = $( '#wpforms-field-option-' + id ).find( '.wpforms-field-option-hidden-type' ).val(); + + // Show choice images and icon options. + $images.removeClass( 'wpforms-hidden' ); + $icons.removeClass( 'wpforms-hidden' ); + $otherOption.removeClass( 'wpforms-hidden' ); + + // Show `Bulk Add` toggle. + $choices.find( '.toggle-bulk-add-display' ).removeClass( 'wpforms-hidden' ); + + // Show the AI Choices button. + $basicOptions.find( '.wpforms-ai-choices-button' ).removeClass( 'wpforms-hidden' ); + + // Show tooltip. + $choices.find( '.wpforms-help-tooltip' ).removeClass( 'wpforms-hidden' ); + + const $wpformsField = $( '#wpforms-field-' + id ); + + $wpformsField.find( '.wpforms-alert' ).remove(); + + if ( [ 'checkbox', 'radio', 'payment-multiple', 'payment-checkbox' ].indexOf( type ) > -1 ) { + app.fieldChoiceUpdate( type, id ); + + // Toggle elements and hide the loading indicator. + $choices.find( 'ul' ).removeClass( 'wpforms-hidden' ); + $choices.find( '.wpforms-alert' ).addClass( 'wpforms-hidden' ); + + wpf.fieldOptionLoading( $thisOption, true ); + + return; // Nothing more for those types. + } + + // Get original field choices. + const $field = $wpformsField; + + const choices = [], + $primary = $field.find( '.primary-input' ); + let key; + + $( `#wpforms-field-option-row-${ id }-choices li` ).each( function() { + const $this = $( this ); + + choices.push( { + label: wpf.sanitizeHTML( $this.find( '.label' ).val() ), + selected: $this.find( '.default' ).is( ':checked' ), + } ); + } ); + + // Restore field to display original field choices. + if ( $field.hasClass( 'wpforms-field-select' ) ) { + const isModernSelect = app.dropdownField.helpers.isModernSelect( $primary ); + + let selected = false; + + // Remove previous items. + $primary.find( 'option' ).not( '.placeholder' ).remove(); + + // Update Modern Dropdown. + if ( isModernSelect && choices.length ) { + app.dropdownField.helpers.update( id, false ); + } else { + // Update Classic select field. + for ( key in choices ) { + selected = choices[ key ].selected; + + optionHTML = '' : '>'; + optionHTML += choices[ key ].label + ''; + + $primary.append( optionHTML ); + } + } + } else { + type = 'radio'; + + if ( $field.hasClass( 'wpforms-field-checkbox' ) ) { + type = 'checkbox'; + } + + // Remove previous items. + $primary.empty(); + + // Add new items to the radio or checkbox field. + for ( key in choices ) { + optionHTML = '
  • ' : '>'; + optionHTML += choices[ key ].label + '
  • '; + + $primary.append( optionHTML ); + } + } + + // Toggle elements and hide the loading indicator. + $choices.find( 'ul' ).removeClass( 'wpforms-hidden' ); + $choices.find( '.wpforms-alert' ).addClass( 'wpforms-hidden' ); + $primary.removeClass( 'wpforms-hidden' ); + + wpf.fieldOptionLoading( $thisOption, true ); + }, + + /** + * Field Dynamic Choice Source toggle. + * + * @since 1.2.8 + * + * @param {Element} el Element. + */ + fieldDynamicChoiceSource( el ) { // eslint-disable-line max-lines-per-function + /* eslint-disable camelcase */ + const $this = $( el ), + $thisOption = $this.parent(), + value = $this.val(), + id = $thisOption.data( 'field-id' ), + form_id = $( '#wpforms-builder-form' ).data( 'id' ), + $choices = $( '#wpforms-field-option-row-' + id + '-choices' ), + $field = $( '#wpforms-field-' + id ), + type = $( `#wpforms-field-option-${ id }-dynamic_choices option:selected` ).val(); + let limit = 20; + + // Loading. + wpf.fieldOptionLoading( $thisOption ); + + const data = { + type, + source: value, + field_id: id, + form_id, + action: 'wpforms_builder_dynamic_source', + nonce: wpforms_builder.nonce, + }; + + /** + * @typedef {Object} DynamicSourceResponse + * @property {boolean} success Success flag. + * @property {{ source_name: string, type_name: string }} data Response data. + */ + + /** + * @param {DynamicSourceResponse} res + */ + $.post( wpforms_builder.ajax_url, data, function( res ) { + if ( ! res.success ) { + // eslint-disable-next-line no-console + console.log( res ); + + // Toggle elements and hide the loading indicator. + wpf.fieldOptionLoading( $thisOption, true ); + return; + } + + // Update the info box and remove old choices. + $choices.find( '.dynamic-name' ).text( res.data.source_name ); + $choices.find( '.dynamic-type' ).text( res.data.type_name ); + $choices.find( 'ul' ).addClass( 'wpforms-hidden' ); + $choices.find( '.wpforms-alert' ).removeClass( 'wpforms-hidden' ); + + // Update items. + app.fieldDynamicChoiceSourceItems( $field, res.data.items ); + + if ( $field.hasClass( 'wpforms-field-select' ) ) { + limit = 200; + } + + // Remove any previous empty message. + $field.find( '.wpforms-notice-dynamic-empty' ).remove(); + + // If the source has more items than the field type can + // ideally handle alert the user. + if ( Number( res.data.total ) > limit ) { + let msg = wpforms_builder.dynamic_choices.limit_message; + + msg = msg.replace( '{source}', res.data.source_name ); + msg = msg.replace( '{type}', res.data.type_name ); + msg = msg.replace( '{limit}', limit ); + msg = msg.replace( '{total}', res.data.total ); + + $.alert( { + title: wpforms_builder.heads_up, + content: msg, + icon: 'fa fa-info-circle', + type: 'blue', + buttons: { + confirm: { + text: wpforms_builder.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + }, + }, + } ); + } + + // Toggle limit choices alert message. + app.firstNChoicesAlert( id, res.data.total ); + + // Toggle empty choices to notice a message. + if ( Number( res.data.total ) === 0 ) { + app.emptyChoicesNotice( id, res.data.source_name, res.data.type ); + } + + // Toggle elements and hide the loading indicator. + wpf.fieldOptionLoading( $thisOption, true ); + } ).fail( function( xhr ) { + // eslint-disable-next-line no-console + console.log( xhr.responseText ); + } ); + }, + + /** + * Update a Field Items when `Dynamic Choice` Source is toggled. + * + * @since 1.6.1 + * + * @param {Object} $field jQuery selector for current field. + * @param {Object} items Items collection. + */ + fieldDynamicChoiceSourceItems( $field, items ) { + const $primary = $field.find( '.primary-input' ); + let key = 0; + + if ( $field.hasClass( 'wpforms-field-select' ) ) { + const isModernSelect = app.dropdownField.helpers.isModernSelect( $primary ); + + if ( isModernSelect ) { + app.fieldDynamicChoiceSourceForModernSelect( $primary, items ); + } else { + app.fieldDynamicChoiceSourceForClassicSelect( $primary, items ); + } + } else { + let type = 'radio'; + + if ( $field.hasClass( 'wpforms-field-checkbox' ) ) { + type = 'checkbox'; + } + + // Remove previous items. + $primary.empty(); + + // Add new items to the radio or checkbox field. + for ( key in items ) { + $primary.append( '
  • ' + wpf.sanitizeHTML( items[ key ] ) + '
  • ' ); + } + } + }, + + /** + * Update options for Modern style select when `Dynamic Choice` Source is toggled. + * + * @since 1.6.1 + * + * @param {Object} $jquerySelector jQuery selector for primary input. + * @param {Object} items Items collection. + */ + fieldDynamicChoiceSourceForModernSelect( $jquerySelector, items ) { + const instance = app.dropdownField.helpers.getInstance( $jquerySelector ), + fieldId = $jquerySelector.closest( '.wpforms-field' ).data().fieldId; + + // Destroy the instance of Choices.js. + instance.destroy(); + + // Update a placeholder. + app.dropdownField.helpers.updatePlaceholderChoice( instance, fieldId ); + + // Update options. + app.fieldDynamicChoiceSourceForClassicSelect( $jquerySelector, items ); + + // Choices.js init. + app.dropdownField.events.choicesInit( $jquerySelector ); + }, + + /** + * Update options for Classic style select when `Dynamic Choice` Source is toggled. + * + * @since 1.6.1 + * + * @param {Object} $jquerySelector jQuery selector for primary input. + * @param {Object} items Items collection. + */ + fieldDynamicChoiceSourceForClassicSelect( $jquerySelector, items ) { + let index = 0; + const itemsSize = items.length; + + // Clear. + $jquerySelector.find( 'option' ).not( '.placeholder' ).remove(); + + // Add options (items) to a single `, + nameError = '

    ' + wpforms_builder[ blockType + '_error' ] + '

    ', + modalContent = namePrompt + nameField + nameError; + + const modal = $.confirm( { + container: $builder, + title: false, + content: modalContent, + icon: 'fa fa-info-circle', + type: 'blue', + buttons: { + confirm: { + text: wpforms_builder.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + action() { // eslint-disable-line complexity, max-lines-per-function + const settingsBlockName = this.$content.find( 'input#settings-block-name' ).val().toString().trim(), + error = this.$content.find( '.error' ); + + if ( settingsBlockName === '' ) { + error.show(); + return false; + } + + const $firstSettingsBlock = $el.closest( '.wpforms-panel-content-section' ).find( '.wpforms-builder-settings-block' ).first(); + + // Restore tooltips before cloning. + wpf.restoreTooltips( $firstSettingsBlock ); + + // Check if we have a template for this block type. + const templateSelector = '#wpforms-' + blockType + '-template-block'; + const $template = $( templateSelector ); + + let $newSettingsBlock; + let blockID; + + // If we have a template and no existing blocks to clone from. + if ( $template.length ) { + // Get the template HTML + let templateHTML = $template.text(); + + // Replace variables in the template. + templateHTML = templateHTML + .replace( /{CLONE}/g, nextID ) + .replace( /CLONE/g, nextID ); + + // Create a new jQuery object from the template. + $newSettingsBlock = $( templateHTML ); + blockID = nextID; + } else { + // Use the regular clone approach when no template exists. + $newSettingsBlock = $firstSettingsBlock.clone(); + blockID = $firstSettingsBlock.data( 'block-id' ); + } + + let newSettingsBlock; + + $newSettingsBlock.attr( 'data-block-id', nextID ); + $newSettingsBlock.find( '.wpforms-builder-settings-block-name-holder span' ).text( settingsBlockName ); + + /** + * Fires to reset settings block elements on adding a new settings block. + * + * @param {jQuery} $element jQuery object of an element. + */ + const resetFormElement = function( $element ) { + if ( $element.attr( 'name' ) ) { + $element.val( '' ).attr( 'name', $element.attr( 'name' ).replace( /\[(\d+)]/, '[' + nextID + ']' ) ); + if ( $element.is( 'select' ) ) { + $element.find( 'option' ).prop( 'selected', false ).attr( 'selected', false ); + $element.find( 'option' ).first().prop( 'selected', true ).attr( 'selected', 'selected' ); + } else if ( $element.attr( 'type' ) === 'checkbox' ) { + const isChecked = $element.closest( '.wpforms-panel-field' ).hasClass( 'js-wpforms-enabled-notification' ); + + $element.prop( 'checked', isChecked ).attr( 'checked', isChecked ).val( '1' ); + } else { + $element.val( '' ).attr( 'value', '' ); + } + } + }; + + $newSettingsBlock.find( 'input, textarea, select' ).each( function() { + const $this = $( this ); + const $parent = $this.parent(); + + if ( $this.hasClass( 'wpforms-disabled' ) && ( $parent.hasClass( 'from-name' ) || $parent.hasClass( 'from-email' ) ) ) { + return; + } + + if ( $parent.hasClass( 'wpforms-pdf-file-name' ) ) { + return; + } + + resetFormElement( $this ); + } ); + + // Update elements IDs. + const idPrefixPanel = 'wpforms-panel-field-' + panelID + '-', + idPrefixBlock = idPrefixPanel + blockID; + $newSettingsBlock.find( '[id^="' + idPrefixBlock + '"], [for^="' + idPrefixBlock + '"]' ).each( function() { + const $el = $( this ), + attr = $el.prop( 'tagName' ) === 'LABEL' ? 'for' : 'id', + elID = $el.attr( attr ).replace( new RegExp( idPrefixBlock, 'g' ), idPrefixPanel + nextID ); + + $el.attr( attr, elID ); + } ); + + // Update `notification by status` checkboxes. + const radioGroup = blockID + '-notification-by-status'; + $newSettingsBlock.find( '[data-radio-group="' + radioGroup + '"]' ).each( function() { + $( this ) + .removeClass( 'wpforms-radio-group-' + radioGroup ) + .addClass( 'wpforms-radio-group-' + nextID + '-notification-by-status' ) + .attr( 'data-radio-group', nextID + '-notification-by-status' ); + } ); + + $newSettingsBlock.find( '.wpforms-builder-settings-block-name-holder input' ).val( settingsBlockName ).attr( 'value', settingsBlockName ); + + if ( blockType === 'notification' ) { + $newSettingsBlock.find( '.email-msg textarea' ).val( '{all_fields}' ).text( '{all_fields}' ).attr( 'value', '{all_fields}' ); + $newSettingsBlock.find( '.email-recipient input' ).val( '{admin_email}' ).attr( 'value', '{admin_email}' ); + } + + $newSettingsBlock.removeClass( 'wpforms-builder-settings-block-default' ); + + if ( blockType === 'confirmation' ) { + $newSettingsBlock.find( '.wpforms-panel-field-tinymce' ).remove(); + if ( typeof WPForms !== 'undefined' ) { + $newSettingsBlock.find( '.wpforms-panel-field-confirmations-type-wrap' ) + .after( WPForms.Admin.Builder.Templates + .get( 'wpforms-builder-confirmations-message-field' )( { + id: nextID, + } ) + ); + } + } + + // Conditional logic, if present + const $conditionalLogic = $newSettingsBlock.find( '.wpforms-conditional-block' ); + if ( $conditionalLogic.length && typeof WPForms !== 'undefined' ) { + $conditionalLogic + .html( WPForms.Admin.Builder.Templates + .get( 'wpforms-builder-conditional-logic-toggle-field' )( { + id: nextID, + type: blockType, + actions: JSON.stringify( $newSettingsBlock.find( '.wpforms-panel-field-conditional_logic-checkbox' ).data( 'actions' ) ), + actionDesc: $newSettingsBlock.find( '.wpforms-panel-field-conditional_logic-checkbox' ).data( 'action-desc' ), + reference: $newSettingsBlock.find( '.wpforms-panel-field-conditional_logic-checkbox' ).data( 'reference' ), + } ) + ); + } + + // Fields Map Table, if present. + const $fieldsMapTable = $newSettingsBlock.find( '.wpforms-field-map-table' ); + if ( $fieldsMapTable.length ) { + $fieldsMapTable.each( function( index, el ) { + const $table = $( el ); + + // Clean table fields. + $table.find( 'tr:not(:first-child)' ).remove(); + + const $input = $table.find( '.key input' ), + $select = $table.find( '.field select' ), + name = $select.data( 'name' ); + + $input.attr( 'value', '' ); + $select + .attr( 'name', '' ) + .attr( 'data-name', name.replace( /\[(\d+)]/, '[' + nextID + ']' ) ); + } ); + } + + newSettingsBlock = $newSettingsBlock.wrap( '
    ' ).parent().html(); + newSettingsBlock = newSettingsBlock.replace( /\[conditionals]\[(\d+)]\[(\d+)]/g, '[conditionals][0][0]' ); + + // If there are no existing blocks, we need to add the new block to the section + if ( $firstSettingsBlock.length === 0 ) { + const $section = $el.closest( '.wpforms-panel-content-section' ); + $section.append( newSettingsBlock ); + } else { + // Otherwise, add it before the first block + $firstSettingsBlock.before( newSettingsBlock ); + } + + // Get the newly added block - it's either the first or the last block in the section. + const $addedSettingBlock = $firstSettingsBlock.length === 0 ? $el.closest( '.wpforms-panel-content-section' ).find( '.wpforms-builder-settings-block' ).first() : $firstSettingsBlock.prev(); + + // Reset the confirmation type to the 1st one. + if ( blockType === 'confirmation' ) { + app.prepareChoicesJSField( $addedSettingBlock, nextID ); + app.confirmationFieldsToggle( $( '.wpforms-panel-field-confirmations-type' ).first() ); + } + + // Init the WP Editor. + if ( typeof tinymce !== 'undefined' && typeof wp.editor !== 'undefined' && blockType === 'confirmation' ) { + wp.editor.initialize( 'wpforms-panel-field-confirmations-message-' + nextID, s.tinymceDefaults ); + } + + // Init tooltips for a new section. + wpf.initTooltips(); + + $builder.trigger( 'wpformsSettingsBlockAdded', [ $addedSettingBlock ] ); + + $el.attr( 'data-next-id', nextID + 1 ); + }, + }, + cancel: { + text: wpforms_builder.cancel, + }, + }, + } ); + + // We need to process this event here because we need a confirmation modal object defined, + // so we can intrude into it. + // Pressing Enter will click the Ok button. + $builder.on( 'keypress', '#settings-block-name', function( e ) { + if ( e.keyCode === 13 ) { + $( modal.buttons.confirm.el ).trigger( 'click' ); + } + } ); + }, + + /** + * Reset the 'Select Page' field to it's initial state then + * re-initialize ChoicesJS on it. + * + * @since 1.7.9 + * + * @param {jQuery} $addedSettingBlock Newly added Settings Block jQuery object. + * @param {number} addedSettingBlockID Number ID used when `$addedSettingBlock` was created. + */ + prepareChoicesJSField( $addedSettingBlock, addedSettingBlockID ) { + const $addedConfirmationWrap = $addedSettingBlock.find( `#wpforms-panel-field-confirmations-${ addedSettingBlockID }-page-wrap` ); + if ( $addedConfirmationWrap.length <= 0 ) { + return; + } + + const $confirmationSelectPageField = $addedConfirmationWrap.find( `#wpforms-panel-field-confirmations-${ addedSettingBlockID }-page` ); + if ( $confirmationSelectPageField.length <= 0 && ! $confirmationSelectPageField.hasClass( 'choicesjs-select' ) ) { + return; + } + + const $choicesWrapper = $addedConfirmationWrap.find( '.choices' ); + if ( $choicesWrapper.length <= 0 ) { + return; + } + + // Remove ChoicesJS-related attr. + const $selectPageField = $confirmationSelectPageField.first(); + $selectPageField.removeAttr( 'data-choice' ); + $selectPageField.removeAttr( 'hidden' ); + $selectPageField.removeClass( 'choices__input' ); + + // Move the select page field to it's initial location in the DOM. + $( $selectPageField ).appendTo( $addedConfirmationWrap.first() ); + + // Remove the `.choices` wrapper. + $choicesWrapper.first().remove(); + + // Re-init ChoicesJS. + app.dropdownField.events.choicesInit( $selectPageField ); + }, + + /** + * Show settings block editing interface. + * + * @since 1.4.8 + * + * @param {jQuery} $el Element. + */ + settingsBlockNameEditingShow( $el ) { + const headerHolder = $el.parents( '.wpforms-builder-settings-block-name-holder' ), + nameHolder = headerHolder.find( '.wpforms-builder-settings-block-name' ); + + nameHolder + .addClass( 'editing' ) + .hide(); + + // Make the editing interface active and in focus + headerHolder.find( '.wpforms-builder-settings-block-name-edit' ).addClass( 'active' ); + wpf.focusCaretToEnd( headerHolder.find( 'input' ) ); + }, + + /** + * Update settings block name and hide editing interface. + * + * @since 1.4.8 + * + * @param {jQuery} $el Element. + */ + settingsBlockNameEditingHide( $el ) { + const headerHolder = $el.parents( '.wpforms-builder-settings-block-header' ), + nameHolder = headerHolder.find( '.wpforms-builder-settings-block-name' ), + editHolder = headerHolder.find( '.wpforms-builder-settings-block-name-edit' ); + let currentName = editHolder.find( 'input' ).val().trim(); + const blockType = $el.data( 'block-type' ) || $el.closest( '.wpforms-builder-settings-block' ).data( 'block-type' ); + + // Provide a default value for the empty settings block name. + if ( ! currentName.length ) { + currentName = wpforms_builder[ blockType + '_def_name' ]; + } + + // This is done for sanitizing. + editHolder.find( 'input' ).val( currentName ); + nameHolder.text( currentName ); + + // Editing should be hidden, displaying - active. + nameHolder + .removeClass( 'editing' ) + .show(); + editHolder.removeClass( 'active' ); + }, + + /** + * Clone the Notification block with all of its content and events. + * Put the newly created clone above the target. + * + * @since 1.6.5 + * @since 1.7.7 Registered `wpformsSettingsBlockCloned` trigger. + * + * @param {Object} $el Clone icon DOM element. + */ + settingsBlockPanelClone( $el ) { // eslint-disable-line max-lines-per-function + const $panel = $el.closest( '.wpforms-panel-content-section' ), + $addNewSettingButton = $panel.find( '.wpforms-builder-settings-block-add' ), + $settingsBlock = $el.closest( '.wpforms-builder-settings-block' ), + $settingBlockContent = $settingsBlock.find( '.wpforms-builder-settings-block-content' ), + settingsBlockId = parseInt( $addNewSettingButton.attr( 'data-next-id' ), 10 ), + settingsBlockType = $settingsBlock.data( 'block-type' ), + settingsBlockName = $settingsBlock.find( '.wpforms-builder-settings-block-name' ).text().trim() + wpforms_builder[ settingsBlockType + '_clone' ], + isVisibleContent = $settingBlockContent.is( ':hidden' ); + + // Restore tooltips before cloning. + wpf.restoreTooltips( $settingsBlock ); + + const $clone = $settingsBlock.clone( false, true ); + + // Save the open / close state while cloning. + app.settingsBlockUpdateState( isVisibleContent, settingsBlockId, settingsBlockType ); + + // Change the cloned setting block ID and name. + $clone.data( 'block-id', settingsBlockId ).attr( 'data-block-id', settingsBlockId ); + $clone.find( '.wpforms-builder-settings-block-name-holder span' ).text( settingsBlockName ); + $clone.find( '.wpforms-builder-settings-block-name-holder input' ).val( settingsBlockName ); + $clone.removeClass( 'wpforms-builder-settings-block-default' ); + + // Change the Next Settings block ID for the "Add new" button. + $addNewSettingButton.attr( 'data-next-id', settingsBlockId + 1 ); + + // Change the name attribute. + $clone.find( 'input, textarea, select' ).each( function() { + const $this = $( this ); + + if ( $this.attr( 'name' ) ) { + $this.attr( 'name', $this.attr( 'name' ).replace( /\[(\d+)]/, '[' + settingsBlockId + ']' ) ); + } + if ( $this.data( 'name' ) ) { + $this.data( 'name', $this.data( 'name' ).replace( /\[(\d+)]/, '[' + settingsBlockId + ']' ) ); + } + if ( $this.attr( 'class' ) ) { + $this.attr( 'class', $this.attr( 'class' ).replace( /-(\d+)/, '-' + settingsBlockId ) ); + } + if ( $this.attr( 'data-radio-group' ) ) { + $this.attr( 'data-radio-group', $this.attr( 'data-radio-group' ).replace( /(\d+)-/, settingsBlockId + '-' ) ); + } + } ); + + // Change IDs/data-attributes in DOM elements. + $clone.find( '*' ).each( function() { + const $this = $( this ); + + if ( $this.attr( 'id' ) ) { + $this.attr( 'id', $this.attr( 'id' ).replace( /-(\d+)/, '-' + settingsBlockId ) ); + } + if ( $this.attr( 'for' ) ) { + $this.attr( 'for', $this.attr( 'for' ).replace( /-(\d+)-/, '-' + settingsBlockId + '-' ) ); + } + if ( $this.data( 'input-name' ) ) { + $this.data( 'input-name', $this.data( 'input-name' ).replace( /\[(\d+)]/, '[' + settingsBlockId + ']' ) ); + } + } ); + + // Transfer selected values to copy elements since jQuery doesn't clone the current selected state. + $settingsBlock.find( 'select' ).each( function() { + const baseSelectName = $( this ).attr( 'name' ), + clonedSelectName = $( this ).attr( 'name' ).replace( /\[(\d+)]/, '[' + settingsBlockId + ']' ); + + $clone.find( 'select[name="' + clonedSelectName + '"]' ).val( $( this ).attr( 'name', baseSelectName ).val() ); + } ); + + // Insert before the target settings block. + $clone + .css( 'display', 'none' ) + .insertBefore( $settingsBlock ) + .show( 'fast', function() { + // Init tooltips for a new section. + wpf.initTooltips(); + } ); + + $builder.trigger( 'wpformsSettingsBlockCloned', [ $clone, $settingsBlock.data( 'block-id' ) ] ); + }, + + /** + * Show or hide settings block panel content. + * + * @since 1.4.8 + * @since 1.9.6.1 Added `isShow` parameter. + * + * @param {Object} $el Toggle an icon DOM element. + * @param {boolean|null} isShow Force showing or hiding. If null - toggle (default), if true - show, if false - hide. + */ + settingsBlockPanelToggle( $el, isShow = null ) { + const $settingsBlock = $el.closest( '.wpforms-builder-settings-block' ), + settingsBlockId = $settingsBlock.data( 'block-id' ), + settingsBlockType = $settingsBlock.data( 'block-type' ), + $content = $settingsBlock.find( '.wpforms-builder-settings-block-content' ), + isVisible = $content.is( ':visible' ), + slideSettings = { + duration: 400, + start() { + // Send it early to save fast. + // It's an animation start, so we should save the state for the animation end (reversed). + app.settingsBlockUpdateState( isVisible, settingsBlockId, settingsBlockType ); + }, + always() { + if ( $content.is( ':visible' ) ) { + $el.html( '' ); + } else { + $el.html( '' ); + } + }, + }; + + $content.stop(); + + // Determine the action based on the force parameter. + if ( isShow === true ) { + $content.slideDown( slideSettings ); + + return; + } else if ( isShow === false ) { + $content.slideUp( slideSettings ); + + return; + } + + $content.slideToggle( slideSettings ); + }, + + /** + * Delete settings block. + * + * @since 1.4.8 + * @since 1.6.1.2 Registered `wpformsSettingsBlockDeleted` trigger. + * + * @param {jQuery} $el Delete button element. + */ + settingsBlockDelete( $el ) { + const $contentSection = $el.closest( '.wpforms-panel-content-section' ); + + // Skip if only one block persist. + // This condition should not be executed in normal circumstances. + if ( $contentSection.find( '.wpforms-builder-settings-block' ).length < 2 && $el.parents( '.wpforms-builder-settings-block' ).data( 'block-type' ) !== 'pdf' ) { + return; + } + + const $currentBlock = $el.closest( '.wpforms-builder-settings-block' ), + blockType = $currentBlock.data( 'block-type' ); + + $.confirm( { + title: false, + content: wpforms_builder[ blockType + '_delete' ], + icon: 'fa fa-exclamation-circle', + type: 'orange', + buttons: { + confirm: { + text: wpforms_builder.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + action() { + const settingsBlockId = $currentBlock.data( 'block-id' ), + settingsBlockType = $currentBlock.data( 'block-type' ); + + /* eslint-disable camelcase */ + $.post( wpforms_builder.ajax_url, { + action: 'wpforms_builder_settings_block_state_remove', + nonce: wpforms_builder.nonce, + block_id: settingsBlockId, + block_type: settingsBlockType, + form_id: s.formID, + } ); + /* eslint-enable */ + + $currentBlock.remove(); + + $builder.trigger( 'wpformsSettingsBlockDeleted', [ blockType, settingsBlockId ] ); + }, + }, + cancel: { + text: wpforms_builder.cancel, + }, + }, + } ); + }, + + /** + * Change the open / close state for setting block. + * + * @since 1.6.5 + * + * @param {boolean} isVisible State status. + * @param {number} settingsBlockId Block ID. + * @param {string} settingsBlockType Block type. + */ + settingsBlockUpdateState( isVisible, settingsBlockId, settingsBlockType ) { + /* eslint-disable camelcase */ + $.post( wpforms_builder.ajax_url, { + action: 'wpforms_builder_settings_block_state_save', + state: isVisible ? 'closed' : 'opened', + form_id: s.formID, + block_id: settingsBlockId, + block_type: settingsBlockType, + nonce: wpforms_builder.nonce, + } ); + }, + + /** + * Change visibility for notification elements, e.g., + * the Enable This Notification toggle and notification status. + * The elements are invisible when the form has only one notification, + * and customers can turn off all notifications instead. + * + * @since 1.9.2 + * @deprecated 1.9.5 Always visible. + */ + notificationsUpdateElementsVisibility() { + // eslint-disable-next-line no-console + console.warn( 'WARNING! Function "WPFormsBuilder.notificationsUpdateElementsVisibility()" has been deprecated.' ); + }, + + /** + * Update the notification status to display if the notification is active or inactive. + * + * @since 1.9.2 + * + * @since 1.9.2 + * + * @param {jQuery} $notification Notification element. + */ + notificationUpdateStatus( $notification ) { + const notificationId = $notification.data( 'block-id' ), + $notificationEnable = $( `#wpforms-panel-field-notifications-${ notificationId }-enable` ); + + const $status = $notification.find( '.wpforms-builder-settings-block-status' ); + + app.changeStatusButton( $status, $notificationEnable.val() !== '0' ); + + if ( ! $notificationEnable.val() ) { + $notificationEnable.val( '1' ); + } + }, + + /** + * Change the status of a notification. + * + * @since 1.9.5 + * + * @param {jQuery} $statusButton The status button element. + */ + notificationChangeStatus( $statusButton ) { + const $notification = $statusButton.closest( '.wpforms-notification' ), + notificationId = $notification.data( 'block-id' ), + $notificationEnable = $( `#wpforms-panel-field-notifications-${ notificationId }-enable` ), + isActive = $statusButton.data( 'active' ); + + app.changeStatusButton( $statusButton, ! isActive ); + + $notificationEnable.val( ! isActive ? '1' : '0' ); + }, + + /** + * Handles the toggle functionality of the status button, updating its state + * and reflecting the change in a corresponding hidden input field. + * + * @since 1.9.6.1 + * + * @param {jQuery} $statusButton The jQuery object for the status button being toggled. + */ + handleStatusButton( $statusButton ) { + const connectionId = $statusButton.data( 'connection-id' ), + isActive = $statusButton.data( 'active' ); + + app.changeStatusButton( $statusButton, ! isActive ); + + $( `#wpforms-connection-status-${ connectionId }` ).val( ! isActive ? '1' : '0' ); + }, + + /** + * Change the status of a button. + * + * @since 1.9.5 + * + * @param {jQuery} $button The button element. + * @param {boolean} isActive Whether the button is active. + */ + changeStatusButton( $button, isActive ) { + $button.removeClass( 'wpforms-badge-green wpforms-badge-silver' ); + + const $icon = $button.find( '.fa' ), + $label = $button.find( '.wpforms-status-label' ); + + $icon.removeClass( 'fa-check fa-times' ); + + if ( isActive ) { + $button.addClass( 'wpforms-badge-green' ); + $icon.addClass( 'fa-check' ); + $label.text( wpforms_builder.active ); + $button.attr( 'title', wpforms_builder.deactivate ); + } else { + $button.addClass( 'wpforms-badge-silver' ); + $icon.addClass( 'fa-times' ); + $label.text( wpforms_builder.inactive ); + $button.attr( 'title', wpforms_builder.activate ); + } + + $button.data( 'active', isActive ); + }, + + //--------------------------------------------------------------------// + // Revisions Panel + //--------------------------------------------------------------------// + + /** + * Element bindings for Revisions panel. + * + * @since 1.7.3 + */ + bindUIActionsRevisions() { + // Update a revisions panel when it becomes active. + $builder.on( 'wpformsPanelSwitched', function( event, panel ) { + if ( panel !== 'revisions' ) { + return; + } + + app.updateRevisionsList(); + app.updateRevisionPreview(); + } ); + + // Update the revision list when the form was saved with a revisions panel being active. + $builder.on( 'wpformsSaved', function() { + if ( wpf.getQueryString( 'view' ) !== 'revisions' ) { + return; + } + + app.updateRevisionsList(); + } ); + + // Switch to the Revisions panel when the link is clicked. + $builder.on( 'click', '.wpforms-panel-content-revisions-link', function( e ) { + e.preventDefault(); + app.panelSwitch( 'revisions' ); + } ); + }, + + /** + * Fetch and update a list of form revisions. + * + * @since 1.7.3 + */ + updateRevisionsList() { + const $revisionsButtonBadge = $( '.wpforms-panel-revisions-button .badge-exclamation' ); + + // Revisions' badge exists, send a request and remove the badge on successful response. + if ( $revisionsButtonBadge.length ) { + $.post( wpforms_builder.ajax_url, { + action: 'wpforms_mark_panel_viewed', + form_id: s.formID, // eslint-disable-line camelcase + nonce: wpforms_builder.nonce, + } ) + .done( function( response ) { + // eslint-disable-next-line no-unused-expressions + response.success ? $revisionsButtonBadge.remove() : wpf.debug( response ); + } ) + .fail( function( xhr, textStatus ) { + wpf.debug( xhr.responseText || textStatus || '' ); + } ); + } + + // Revisions are disabled, no need to fetch a list of revisions. + if ( ! $builder.hasClass( 'wpforms-revisions-enabled' ) ) { + return; + } + + const $revisionsList = $( '#wpforms-panel-revisions .wpforms-revisions-content' ); + + // Dim the list, send a request and replace the list on successful response. + $revisionsList.fadeTo( 250, 0.25, function() { + $.post( wpforms_builder.ajax_url, { + action: 'wpforms_get_form_revisions', + form_id: s.formID, // eslint-disable-line camelcase + revision_id: wpf.getQueryString( 'revision_id' ), // eslint-disable-line camelcase + nonce: wpforms_builder.nonce, + } ) + .done( function( response ) { + // eslint-disable-next-line no-unused-expressions + response.success ? $revisionsList.replaceWith( response.data.html ) : wpf.debug( response ); + } ) + .fail( function( xhr, textStatus ) { + wpf.debug( xhr.responseText || textStatus || '' ); + + // Undim the list to reset the UI. + $revisionsList.fadeTo( 250, 1 ); + } ); + } ); + }, + + /** + * Clone form preview from Fields panel. + * + * @since 1.7.3 + */ + updateRevisionPreview() { + // Clone preview DOM from a Fields panel. + const $preview = elements.$formPreview.clone(); + + // Clean up the cloned preview, remove unnecessary elements, set states, etc. + $preview + .find( '.wpforms-field-duplicate, .wpforms-field-delete, .wpforms-field-helper, .wpforms-debug' ) + .remove() + .end(); + $preview + .find( '.wpforms-field-wrap' ) + .removeClass( 'ui-sortable' ) + .addClass( 'ui-sortable-disabled' ); + $preview + .find( '.wpforms-field' ) + .removeClass( 'ui-sortable-handle ui-draggable ui-draggable-handle active' ) + .removeAttr( 'id data-field-id data-field-type' ) + .removeData(); + $preview + .find( '.wpforms-field-submit-button' ) + .prop( 'disabled', true ); + + // Put the cleaned-up clone into a Preview panel. + if ( elements.$revisionPreview.hasClass( 'has-preview' ) ) { + elements + .$revisionPreview + .find( '.wpforms-preview-wrap' ) + .replaceWith( $preview ); + } else { + elements + .$revisionPreview + .append( $preview ) + .addClass( 'has-preview' ); + } + }, + + /** + * Inform the user about making this version the default if the revision is currently loaded, and it was modified. + * + * @since 1.7.3 + */ + confirmSaveRevision() { + $.confirm( { + title: wpforms_builder.heads_up, + content: wpforms_builder.revision_update_confirm, + icon: 'fa fa-exclamation-circle', + type: 'orange', + closeIcon: false, + buttons: { + + confirm: { + text: wpforms_builder.save, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + action() { + // Put the Form Builder into "saving state". + $builder.addClass( 'wpforms-revision-is-saving' ); + + // Save the revision as the current version and reload the Form Builder. + WPFormsBuilder.formSave( false ).done( app.revisionSavedReload ); + }, + }, + + cancel: { + text: wpforms_builder.cancel, + action() { + WPFormsBuilder.setCloseConfirmation( true ); + }, + }, + }, + } ); + }, + + /** + * When a modified revision was saved as a current version, reload the Form Builder with the current tab active. + * + * @since 1.7.3 + */ + revisionSavedReload() { + wpf.updateQueryString( 'view', wpf.getQueryString( 'view' ) ); + wpf.removeQueryParam( 'revision_id' ); + + window.location.reload(); + }, + + //--------------------------------------------------------------------// + // Save and Exit + //--------------------------------------------------------------------// + + /** + * Element bindings for Embed and Save/Exit items. + * + * @since 1.0.0 + * @since 1.5.8 Added trigger on `wpformsSaved` event to remove a `newform` URL-parameter. + */ + bindUIActionsSaveExit() { + // Embed form. + $builder.on( 'click', '#wpforms-embed', function( e ) { + e.preventDefault(); + + if ( $( this ).hasClass( 'wpforms-disabled' ) || $( this ).hasClass( 'wpforms-btn-light-grey-disabled' ) ) { + return; + } + + WPFormsFormEmbedWizard.openPopup(); + } ); + + // Save form. + $builder.on( 'click', '#wpforms-save', function( e ) { + e.preventDefault(); + app.formSave( false ); + } ); + + // Exit builder. + $builder.on( 'click', '#wpforms-exit', function( e ) { + e.preventDefault(); + app.formExit(); + } ); + + // After form save. + $builder.on( 'wpformsSaved', function() { + /** + * Remove the `newform` parameter if it's in URL, otherwise we can get a "race condition". + * E.g., form settings will be updated before some provider connection is loaded. + */ + wpf.removeQueryParam( 'newform' ); + } ); + }, + + // eslint-disable-next-line jsdoc/require-returns + /** + * Save form. + * + * @since 1.0.0 + * @since 1.7.5 Added `wpformsBeforeSave` trigger. + * + * @param {boolean} redirect Whether to redirect after save. + */ + formSave( redirect ) { // eslint-disable-line max-lines-per-function + // Saving a revision directly is not allowed. We need to notify the user that it will overwrite the current version. + if ( $builder.hasClass( 'wpforms-is-revision' ) && ! $builder.hasClass( 'wpforms-revision-is-saving' ) ) { + app.confirmSaveRevision(); + + return; + } + + if ( typeof tinyMCE !== 'undefined' ) { + tinyMCE.triggerSave(); + } + + const event = WPFormsUtils.triggerEvent( $builder, 'wpformsBeforeSave' ); + + // Allow callbacks on `wpformsBeforeSave` to cancel form submission by triggering `event.preventDefault()`. + if ( event.isDefaultPrevented() ) { + return; + } + + const $saveBtn = elements.$saveButton, + $icon = $saveBtn.find( 'i.fa-check' ), + $spinner = $saveBtn.find( 'i.wpforms-loading-spinner' ), + $label = $saveBtn.find( 'span' ), + text = $label.text(); + + $label.text( wpforms_builder.saving ); + $saveBtn.prop( 'disabled', true ); + $icon.addClass( 'wpforms-hidden' ); + $spinner.removeClass( 'wpforms-hidden' ); + + const data = { + action: 'wpforms_save_form', + data: JSON.stringify( app.serializeAllData( $( '#wpforms-builder-form' ) ) ), + id: s.formID, + nonce: wpforms_builder.nonce, + }; + + const onSaveFormFail = function( xhr ) { + wpf.debug( xhr ); + let errorMessage = ''; + + if ( xhr.status === 403 ) { + errorMessage = wpforms_builder.error_save_form_forbidden; + } + + app.formSaveError( errorMessage ); + }; + + return $.post( wpforms_builder.ajax_url, data, function( response ) { + if ( response.success ) { + wpf.initialSave = false; + + // We need to save the form next tick to ensure that JS fields are already initialized. + setTimeout( () => { + wpf._updateFormState(); + + $builder.trigger( 'wpformsSaved', response.data ); + + if ( redirect !== true ) { + return; + } + + if ( app.isBuilderInPopup() ) { + app.builderInPopupClose( 'saved' ); + return; + } + + window.location.href = wpforms_builder.exit_url; + }, 0 ); + } else { + wpf.debug( response ); + app.formSaveError( response.data ); + } + } ).fail( onSaveFormFail ).always( function() { + $label.text( text ); + $saveBtn.prop( 'disabled', false ); + $spinner.addClass( 'wpforms-hidden' ); + $icon.removeClass( 'wpforms-hidden' ); + } ); + }, + + /** + * Serialize all form data including checkboxes that are not checked. + * + * @since 1.9.0 + * + * @param {Object} $form Form jQuery object. + * + * @return {Array} Form data. + */ + serializeAllData( $form ) { + const formData = $form.serializeArray(); + + $form.find( '.wpforms-field-option-layout .wpforms-field-option-row-label_hide input[type=checkbox]' ).each( function() { + const $checkbox = $( this ); + const name = $checkbox.attr( 'name' ); + const value = $checkbox.is( ':checked' ) ? '1' : ''; + + if ( ! value ) { + formData.push( { name, value } ); + } + } ); + + return formData; + }, + + /** + * Form save error. + * + * @since 1.6.3 + * + * @param {string} error Error message. + */ + formSaveError( error = '' ) { + // Default error message. + if ( wpf.empty( error ) ) { + error = wpforms_builder.error_save_form; + } + + // Display error in a modal window. + $.confirm( { + title: wpforms_builder.heads_up, + content: '

    ' + error + '

    ' + wpforms_builder.error_contact_support + '

    ', + icon: 'fa fa-exclamation-circle', + type: 'orange', + buttons: { + confirm: { + text: wpforms_builder.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + }, + }, + } ); + }, + + /** + * Exit form builder. + * + * @since 1.0.0 + */ + formExit() { + if ( app.isBuilderInPopup() && app.formIsSaved() ) { + app.builderInPopupClose( 'saved' ); + return; + } + + if ( app.formIsSaved() ) { + window.location.href = wpforms_builder.exit_url; + } else { + $.confirm( { + title: false, + content: wpforms_builder.exit_confirm, + icon: 'fa fa-exclamation-circle', + type: 'orange', + closeIcon: true, + buttons: { + confirm: { + text: wpforms_builder.save_exit, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + action() { + app.formSave( true ); + }, + }, + cancel: { + text: wpforms_builder.exit, + action() { + closeConfirmation = false; + + if ( app.isBuilderInPopup() ) { + app.builderInPopupClose( 'canceled' ); + return; + } + + window.location.href = wpforms_builder.exit_url; + }, + }, + }, + } ); + } + }, + + /** + * Close confirmation setter. + * + * @since 1.6.2 + * + * @param {boolean} confirm Close confirmation flag value. + */ + setCloseConfirmation( confirm ) { + closeConfirmation = !! confirm; + }, + + /** + * Check the current form state. + * + * @since 1.0.0 + * + * @return {boolean} True if the form is saved. + */ + formIsSaved() { // eslint-disable-line complexity + if ( typeof wpf.savedFormState !== 'object' || Object.keys( wpf.savedFormState ).length === 0 ) { + return false; + } + + const isDebugEnabled = wpf.isDebug(); + const differences = {}; + const currentState = wpf._getCurrentFormState(); + + // Compare current state with saved state + for ( const key in currentState ) { + if ( currentState[ key ] !== wpf.savedFormState[ key ] ) { + if ( ! isDebugEnabled ) { + return false; + } + + differences[ key ] = { + old: wpf.savedFormState[ key ], + new: currentState[ key ], + }; + } + } + + // Check for deleted fields + for ( const key in wpf.savedFormState ) { + if ( ! ( key in currentState ) ) { + if ( ! isDebugEnabled ) { + return false; + } + + differences[ key ] = { + old: wpf.savedFormState[ key ], + new: undefined, + }; + } + } + + if ( ! Object.keys( differences ).length ) { + return true; + } + + wpf.debug( 'Form state differences:', differences ); + + return false; + }, + + /** + * Check if the builder opened in the popup (iframe). + * + * @since 1.6.2 + * + * @return {boolean} True if builder opened in the popup. + */ + isBuilderInPopup() { + return window.self !== window.parent && window.self.frameElement.id === 'wpforms-builder-iframe'; + }, + + /** + * Close popup with the form builder. + * + * @since 1.6.2 + * + * @param {string} action Performed action: saved or canceled. + */ + builderInPopupClose( action ) { + const $popup = window.parent.jQuery( '.wpforms-builder-popup' ); + const $title = $( '.wpforms-center-form-name' ).text(); + + $popup.find( '#wpforms-builder-iframe' ).attr( 'src', 'about:blank' ); + $popup.fadeOut(); + + $popup.trigger( 'wpformsBuilderInPopupClose', [ action, s.formID, $title ] ); + }, + + //--------------------------------------------------------------------// + // General / global + //--------------------------------------------------------------------// + + /** + * Element bindings for general and global items. + * + * @since 1.2.0 + */ + bindUIActionsGeneral() { // eslint-disable-line max-lines-per-function + // Toggle Smart Tags + $builder.on( 'click', '.toggle-smart-tag-display', app.smartTagToggle ); + + $builder.on( 'click', '.smart-tags-list-display a', app.smartTagInsert ); + + // Toggle unfoldable group of fields + $builder.on( 'click', '.wpforms-panel-fields-group.unfoldable .wpforms-panel-fields-group-title', app.toggleUnfoldableGroup ); + + // Hide the field preview helper box. + $builder.on( 'click', '.wpforms-field-helper-hide ', app.hideFieldHelper ); + + // Restrict user money input fields + $builder.on( 'input', '.wpforms-money-input', function() { + const $this = $( this ), + amount = $this.val(), + start = $this[ 0 ].selectionStart, + end = $this[ 0 ].selectionEnd; + + $this.val( amount.replace( /[^0-9.,]/g, '' ) ); + $this[ 0 ].setSelectionRange( start, end ); + } ); + + // Format user money input fields + $builder.on( 'focusout', '.wpforms-money-input', function() { + const $this = $( this ), + amount = $this.val(); + + if ( ! amount ) { + return amount; + } + + const sanitized = wpf.amountSanitize( amount ), + formatted = wpf.amountFormat( sanitized ); + + $this.val( formatted ); + } ); + + // Show/hide a group of options. + $builder.on( 'change', '.wpforms-panel-field-toggle', function() { + const $input = $( this ); + + if ( $input.prop( 'disabled' ) ) { + return; + } + + $input.prop( 'disabled', true ); + app.toggleOptionsGroup( $input ); + } ); + + // Upload or add an image. + $builder.on( 'click', '.wpforms-image-upload-add', function( event ) { + event.preventDefault(); + + const $this = $( this ); + const $container = $this.parent(); + + const mediaFrame = wpf.initMediaLibrary( { + title: wpforms_builder.upload_image_title, + extensions: wpforms_builder.upload_image_extensions, + extensionsError: wpforms_builder.upload_image_extensions_error, + buttonText: wpforms_builder.upload_image_button, + } ); + + mediaFrame.on( 'select', function() { + const mediaAttachment = mediaFrame.state().get( 'selection' ).first().toJSON(); + const $preview = $container.find( '.preview' ); + + $container.find( '.source' ).val( mediaAttachment.url ); + $preview.empty(); + $preview.prepend( '' ); + + if ( $this.data( 'after-upload' ) === 'hide' ) { + $this.hide(); + } + + $builder.trigger( 'wpformsImageUploadAdd', [ $this, $container ] ); + } ).on( 'close', function() { + mediaFrame.off( 'library:selection:add' ); + } ); + + // Now that everything has been set, let's open up the frame. + mediaFrame.open(); + } ); + + // Remove and uploaded image. + $builder.on( 'click', '.wpforms-image-upload-remove', function( event ) { + event.preventDefault(); + + const $container = $( this ).parent().parent(); + + $container.find( '.preview' ).empty(); + $container.find( '.wpforms-image-upload-add' ).show(); + $container.find( '.source' ).val( '' ); + + $builder.trigger( 'wpformsImageUploadRemove', [ $( this ), $container ] ); + } ); + + // Validate email smart tags in Notifications fields. + $builder.on( 'blur', '.wpforms-notification .wpforms-panel-field-text input:not([type="search"])', function() { + app.validateEmailSmartTags( $( this ) ); + } ); + $builder.on( 'blur', '.wpforms-notification .wpforms-panel-field-textarea textarea', function() { + app.validateEmailSmartTags( $( this ) ); + } ); + + // Validate From Email in Notification settings. + $builder.on( 'focusout', '.wpforms-notification .wpforms-panel-field.js-wpforms-from-email-validation input:not([type="search"])', app.validateFromEmail ); + $builder.on( 'wpformsPanelSectionSwitch', app.notificationsPanelSectionSwitch ); + + // Mobile notice primary button / close icon click. + $builder.on( 'click', '#wpforms-builder-mobile-notice .wpforms-fullscreen-notice-button-primary, #wpforms-builder-mobile-notice .close', function() { + window.location.href = wpforms_builder.exit_url; + } ); + + // Mobile notice secondary button click. + $builder.on( 'click', '#wpforms-builder-mobile-notice .wpforms-fullscreen-notice-button-secondary', function() { + window.location.href = wpf.updateQueryString( 'force_desktop_view', 1, window.location.href ); + } ); + + // License Alert close button click. + $( '#wpforms-builder-license-alert .close' ).on( 'click', function() { + window.location.href = wpforms_builder.exit_url; + } ); + + // License Alert dismiss button click. + $( '#wpforms-builder-license-alert .dismiss' ).on( 'click', function( event ) { + event.preventDefault(); + $( '#wpforms-builder-license-alert' ).remove(); + wpCookies.set( 'wpforms-builder-license-alert', 'true', 3600 ); + } ); + + // Don't allow the Akismet setting to be enabled if the Akismet plugin isn't available. + $builder.on( 'change', '#wpforms-panel-field-settings-akismet.wpforms-akismet-disabled', function() { + const $this = $( this ), + akismetStatus = $this.data( 'akismet-status' ); + + if ( $this.prop( 'checked' ) ) { + $.alert( { + title: wpforms_builder.heads_up, + content: wpforms_builder[ akismetStatus ], + icon: 'fa fa-exclamation-circle', + type: 'orange', + buttons: { + confirm: { + text: wpforms_builder.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + }, + }, + onClose() { + $this.prop( 'checked', false ); + }, + } ); + } + } ); + + // Re-init the Show More button for multiselect instances when it's visible. + $builder.on( 'wpformsPanelSectionSwitch wpformsPanelSwitched', function() { + wpf.reInitShowMoreChoices( $( '#wpforms-panel-providers, #wpforms-panel-settings' ) ); + } ); + }, + + /** + * Notification section switch event handler. + * + * @since 1.8.2.3 + * + * @param {Object} e Event object. + * @param {string} panel Panel name. + */ + notificationsPanelSectionSwitch( e, panel ) { + if ( panel !== 'notifications' ) { + return; + } + + $( '.wpforms-notification .wpforms-panel-field.js-wpforms-from-email-validation input' ).trigger( 'focusout' ); + }, + + /** + * Check if one of the payment addons payments enabled. + * + * @since 1.7.5 + * + * @return {boolean} True if one of the payment addons payment enabled. + */ + isPaymentsEnabled() { + let paymentEnabled = false; + + $( app.getPaymentsTogglesSelector() ).each( function() { + if ( $( this ).prop( 'checked' ) ) { + paymentEnabled = true; + + return false; + } + } ); + + return paymentEnabled; + }, + + /** + * Get Payments toggles selector. + * + * @since 1.7.5 + * + * @return {string} List of selectors. + */ + getPaymentsTogglesSelector() { + return `.wpforms-panel-content-section-payment-toggle-one-time input, + .wpforms-panel-content-section-payment-toggle-recurring input, + #wpforms-panel-field-stripe-enable, + #wpforms-panel-field-paypal_standard-enable, + #wpforms-panel-field-authorize_net-enable, + #wpforms-panel-field-square-enable`; + }, + + /** + * Toggle an options group. + * + * @since 1.6.3 + * + * @param {Object} $input Toggled field. + */ + toggleOptionsGroup( $input ) { + const name = $input.attr( 'name' ); + let value = ''; + const $body = $( '.wpforms-panel-field-toggle-body[data-toggle="' + name + '"]' ), + enableInput = function() { + $input.prop( 'disabled', false ); + }; + + app.toggleProviderActiveIcon( $input ); + + if ( $body.length === 0 ) { + enableInput(); + + return; + } + + const type = $input.attr( 'type' ); + + if ( 'checkbox' === type || 'radio' === type ) { + value = $input.prop( 'checked' ) ? $input.val() : '0'; + } else { + value = $input.val(); + } + + $body.each( function() { + /** @type {JQ|jQuery} */ + const $this = $( this ); + + // eslint-disable-next-line no-unused-expressions + $this.attr( 'data-toggle-value' ).toString() === value.toString() + ? $this.slideDown( 150, enableInput ) + : $this.slideUp( 150, enableInput ); + } ); + }, + + /** + * Toggle Provider Active icon. + * + * @since 1.9.3 + * + * @param {Object} $input Toggled field. + */ + toggleProviderActiveIcon( $input ) { + const provider = $input.closest( '.wpforms-panel-content-section' ).data( 'provider' ); + + const wrappers = [ + 'wpforms-panel-field-' + provider + '-enable-wrap', + 'wpforms-panel-field-' + provider + '-enable_one_time-wrap', + 'wpforms-panel-field-' + provider + '-enable_recurring-wrap', + ]; + + if ( ! provider || ! wrappers.includes( $input.attr( 'id' ) ) ) { + return; + } + + let isActive = false; + + wrappers.forEach( ( wrapper ) => { + const $wrapper = $( '#' + wrapper ); + + if ( $wrapper.length && $wrapper.find( 'input' ).is( ':checked' ) ) { + isActive = true; + } + } ); + + const $sidebar = $( `.wpforms-panel-sidebar-section[data-section=${ provider }]` ), + $check_icon = $sidebar.find( '.fa-check-circle-o' ); + + $check_icon.toggleClass( 'wpforms-hidden', ! isActive ); + }, + + /** + * Toggle all option groups. + * + * @since 1.6.3 + * + * @param {jQuery} $context Context container jQuery object. + */ + toggleAllOptionGroups( $context ) { + $context = $context || $builder || $( '#wpforms-builder' ) || $( 'body' ); + + if ( ! $context ) { + return; + } + + // Show a toggled body. + $context.find( '.wpforms-panel-field-toggle' ).each( function() { + const $input = $( this ); + + $input.prop( 'disabled', true ); + app.toggleOptionsGroup( $input ); + } ); + }, + + /** + * Toggle unfoldable group of fields. + * + * @since 1.6.8 + * + * @param {Object} e Event object. + */ + toggleUnfoldableGroup( e ) { + e.preventDefault(); + + const /** @type {JQ|jQuery} */ $title = $( e.target ), + $group = $title.closest( '.wpforms-panel-fields-group' ), + $inner = $group.find( '.wpforms-panel-fields-group-inner' ), + cookieName = 'wpforms_fields_group_' + $group.data( 'group' ); + + if ( $group.hasClass( 'opened' ) ) { + wpCookies.remove( cookieName ); + $inner.stop().slideUp( 150, function() { + $group.removeClass( 'opened' ); + } ); + } else { + wpCookies.set( cookieName, 'true', 2592000 ); // 1 month. + $group.addClass( 'opened' ); + $inner.stop().slideDown( 150 ); + } + }, + + /** + * Hide the field preview helper box. + * + * @since 1.7.1 + * + * @param {Object} e Event object. + */ + hideFieldHelper( e ) { + e.preventDefault(); + e.stopPropagation(); + + const $helpers = $( '.wpforms-field-helper' ), + cookieName = 'wpforms_field_helper_hide'; + + wpCookies.set( cookieName, 'true', 30 * 24 * 60 * 60 ); // 1 month. + $helpers.hide(); + }, + + /** + * Smart Tag toggling. + * + * @since 1.0.1 + * @since 1.6.9 Simplify method. + * @since 1.9.5 Deprecated. + * + * @param {Event} e Event. + */ + smartTagToggle( e ) { + // eslint-disable-next-line no-console + console.warn( 'WARNING! Function "WPFormsBuilder.smartTagToggle()" has been deprecated.' ); + + e.preventDefault(); + + // Prevent ajax to validate the default email queued on focusout event. + elements.$focusOutTarget = null; + + const $this = $( this ), + $wrapper = $this.closest( '.wpforms-panel-field,.wpforms-field-option-row' ); + + if ( $wrapper.hasClass( 'smart-tags-toggling' ) ) { + return; + } + + $wrapper.addClass( 'smart-tags-toggling' ); + + if ( $this.hasClass( 'smart-tag-showing' ) ) { + app.removeSmartTagsList( $this ); + + return; + } + + app.insertSmartTagsList( $this ); + }, + + /** + * Remove a Smart Tag list. + * + * @since 1.6.9 + * @since 1.9.5 Deprecated. + * + * @param {JQ|jQuery} $el Toggle element. + */ + removeSmartTagsList( $el ) { + // eslint-disable-next-line no-console + console.warn( 'WARNING! Function "WPFormsBuilder.removeSmartTagsList()" has been deprecated.' ); + + const $wrapper = $el.closest( '.wpforms-panel-field,.wpforms-field-option-row' ), + $list = $wrapper.find( '.smart-tags-list-display' ); + + $el.find( 'span' ).text( wpforms_builder.smart_tags_show ); + + $list.slideUp( '', function() { + $list.remove(); + $el.removeClass( 'smart-tag-showing' ); + $wrapper.removeClass( 'smart-tags-toggling' ); + } ); + }, + + /** + * Insert Smart Tag list. + * + * @since 1.6.9 + * @since 1.9.5 Deprecated. + * + * @param {JQ|jQuery} $el Toggle element. + */ + insertSmartTagsList( $el ) { + // eslint-disable-next-line no-console + console.warn( 'WARNING! Function "WPFormsBuilder.insertSmartTagsList()" has been deprecated.' ); + + const $wrapper = $el.closest( '.wpforms-panel-field,.wpforms-field-option-row' ); + let $label = $el.closest( 'label' ), + insideLabel = true; + + if ( ! $label.length ) { + $label = $wrapper.find( 'label' ); + insideLabel = false; + } + + const smartTagList = app.getSmartTagsList( $el, $label.attr( 'for' ).indexOf( 'wpforms-field-option-' ) !== -1 ); + + // eslint-disable-next-line no-unused-expressions + insideLabel + ? $label.after( smartTagList ) + : $el.after( smartTagList ); + + $el.find( 'span' ).text( wpforms_builder.smart_tags_hide ); + + $wrapper.find( '.smart-tags-list-display' ).slideDown( '', function() { + $el.addClass( 'smart-tag-showing' ); + $wrapper.removeClass( 'smart-tags-toggling' ); + } ); + }, + + /** + * Get Smart Tag list markup. + * + * @since 1.6.9 + * @since 1.9.5 Deprecated. + * + * @param {jQuery} $el Toggle element. + * @param {boolean} isFieldOption Is a field option. + * + * @return {string} Smart Tags list markup. + */ + getSmartTagsList( $el, isFieldOption ) { + // eslint-disable-next-line no-console + console.warn( 'WARNING! Function "WPFormsBuilder.getSmartTagsList()" has been deprecated.' ); + + let smartTagList; + + smartTagList = '
      '; + smartTagList += app.getSmartTagsListFieldsElements( $el ); + smartTagList += app.getSmartTagsListOtherElements( $el, isFieldOption ); + smartTagList += '
    '; + + return smartTagList; + }, + + /** + * Get Smart Tag fields elements markup. + * + * @since 1.6.9 + * @since 1.9.5 Deprecated. + * + * @param {jQuery} $el Toggle element. + * + * @return {string} Smart Tags list elements markup. + */ + getSmartTagsListFieldsElements( $el ) { + // eslint-disable-next-line no-console + console.warn( 'WARNING! Function "WPFormsBuilder.getSmartTagsListFieldsElements()" has been deprecated.' ); + + const type = $el.data( 'type' ); + + if ( ! [ 'fields', 'all' ].includes( type ) ) { + return ''; + } + + const fields = app.getSmartTagsFields( $el ); + + if ( ! fields ) { + return '
  • ' + wpforms_builder.fields_unavailable + '
  • '; + } + + let smartTagListElements = ''; + + smartTagListElements += '
  • ' + wpforms_builder.fields_available + '
  • '; + + for ( const fieldKey in fields ) { + smartTagListElements += app.getSmartTagsListFieldsElement( fields[ fieldKey ] ); + } + + return smartTagListElements; + }, + + /** + * Get fields that possible to create smart tag. + * + * @since 1.6.9 + * @since 1.9.5 Deprecated. + * + * @param {jQuery} $el Toggle element. + * + * @return {Array} Fields for smart tags. + */ + getSmartTagsFields( $el ) { + // eslint-disable-next-line no-console + console.warn( 'WARNING! Function "WPFormsBuilder.getSmartTagsFields()" has been deprecated.' ); + + const allowed = $el.data( 'fields' ); + const isAllowedRepeater = $el.data( 'allow-repeated-fields' ); + const allowedFields = allowed ? allowed.split( ',' ) : undefined; + + return wpf.getFields( allowedFields, true, isAllowedRepeater ); + }, + + /** + * Get field markup for the Smart Tags list. + * + * @since 1.6.9 + * @since 1.9.5 Deprecated. + * + * @param {Object} field A field. + * + * @return {string} Smart Tags field markup. + */ + getSmartTagsListFieldsElement( field ) { + // eslint-disable-next-line no-console + console.warn( 'WARNING! Function "WPFormsBuilder.getSmartTagsListFieldsElement()" has been deprecated.' ); + + const label = field.label + ? wpf.encodeHTMLEntities( wpf.sanitizeHTML( field.label ) ) + : wpforms_builder.field + ' #' + field.id; + + let html = `
  • ${ label }
  • `; + + const additionalTags = field.additional || []; + + // Add additional tags for `name`, `date/time` and `address` fields. + if ( additionalTags.length > 1 ) { + additionalTags.forEach( ( additionalTag ) => { + // Capitalize the first letter and add space before numbers. + const additionalTagLabel = additionalTag.charAt( 0 ).toUpperCase() + additionalTag.slice( 1 ).replace( /(\D)(\d)/g, '$1 $2' ); + html += `
  • ${ label } – ${ additionalTagLabel }
  • `; + } ); + } + + return html; + }, + + /** + * Get Smart Tag other elements' markup. + * + * @since 1.6.9 + * @since 1.9.5 Deprecated. + * + * @param {jQuery} $el Toggle element. + * @param {boolean} isFieldOption Is a field option. + * + * @return {string} Smart Tags list element markup. + */ + getSmartTagsListOtherElements( $el, isFieldOption ) {// eslint-disable-line complexity + // eslint-disable-next-line no-console + console.warn( 'WARNING! Function "WPFormsBuilder.getSmartTagsListOtherElements()" has been deprecated.' ); + + const type = $el.data( 'type' ); + let smartTagListElements; + + if ( type !== 'other' && type !== 'all' ) { + return ''; + } + + smartTagListElements = '
  • ' + wpforms_builder.other + '
  • '; + + for ( const smartTagKey in wpforms_builder.smart_tags ) { + if ( + ( isFieldOption && wpforms_builder.smart_tags_disabled_for_fields.includes( smartTagKey ) ) || + ( + $el.data( 'location' ) === 'confirmations' && + wpforms_builder.smart_tags_disabled_for_confirmations.includes( smartTagKey ) + ) + ) { + continue; + } + + smartTagListElements += '
  • ' + wpforms_builder.smart_tags[ smartTagKey ] + '
  • '; + } + + return smartTagListElements; + }, + + /** + * Smart Tag insert. + * + * @since 1.0.1 + * @since 1.6.9 TinyMCE compatibility. + * @since 1.9.5 Deprecated. + * + * @param {Event} e Event. + */ + smartTagInsert( e ) { // eslint-disable-line complexity + // eslint-disable-next-line no-console + console.warn( 'WARNING! Function "WPFormsBuilder.smartTagInsert()" has been deprecated.' ); + + e.preventDefault(); + + const /** @type {JQ|jQuery} */ $this = $( this ), + $list = $this.closest( '.smart-tags-list-display' ), + $wrapper = $list.closest( '.wpforms-panel-field,.wpforms-field-option-row' ), + $toggle = $wrapper.find( '.toggle-smart-tag-display' ), + $input = $wrapper.find( 'input[type=text], textarea' ), + meta = $this.data( 'meta' ), + additional = $this.data( 'additional' ) ? '|' + $this.data( 'additional' ) : '', + type = $this.data( 'type' ); + let smartTag = type === 'field' ? '{field_id="' + meta + additional + '"}' : '{' + meta + '}', + editor; + + if ( typeof tinyMCE !== 'undefined' ) { + editor = tinyMCE.get( $input.prop( 'id' ) ); + + if ( editor && ! editor.hasFocus() ) { + editor.focus( true ); + } + } + + if ( editor && ! editor.isHidden() ) { + editor.insertContent( smartTag ); + } else { + smartTag = ' ' + smartTag + ' '; + + $input.insertAtCaret( smartTag ); + + // Remove redundant spaces after wrapping smartTag into spaces. + $input.val( $input.val().trim().replace( ' ', ' ' ) ); + $input.trigger( 'focus' ).trigger( 'input' ); + } + + // Remove the list, all done! + $list.slideUp( '', function() { + $list.remove(); + } ); + + $toggle.find( 'span' ).text( wpforms_builder.smart_tags_show ); + $wrapper.find( '.toggle-smart-tag-display' ).removeClass( 'smart-tag-showing' ); + }, + + /** + * Validate email smart tags in Notifications fields. + * + * @since 1.4.9 + * @since 1.9.5 Deprecated. + * + * @param {Object} $el Input field to check the value for. + */ + validateEmailSmartTags( $el ) { + // eslint-disable-next-line no-console + console.warn( 'WARNING! Function "WPFormsBuilder.validateEmailSmartTags()" has been deprecated.' ); + + let val = $el.val(); + + if ( ! val ) { + return; + } + + // Turns '{email@domain.com}' into 'email@domain.com'. + // Email RegEx inspired by http://emailregex.com + val = val.replace( /{(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))}/g, function( x ) { + return x.slice( 1, -1 ); + } ); + + $el.val( val ); + }, + + /** + * Validate the Email field smart tag `{field_id="N"}` and return the error. + * + * @since 1.9.5 + * + * @param {string} value Input field value. + * + * @return {string|null} Error message or null in case the regexp pattern doesn't match. + */ + getEmailFieldSmartTagError( value ) { + // Detects `{field_id="N"}` smart tags. + const fieldSmartTagRegex = /\{field_id="(\d+)"}/g; + + if ( ! fieldSmartTagRegex.test( value ) ) { + return null; + } + + // Reset regex lastIndex to ensure we start from the beginning. + fieldSmartTagRegex.lastIndex = 0; + + // Extract the field ID from the smart tag. + const match = fieldSmartTagRegex.exec( value ); + const fieldId = match ? match[ 1 ] : null; + const fieldSettings = wpf.getField( fieldId ); + + if ( fieldSettings && fieldSettings.type === 'email' ) { + return ''; + } + + return wpforms_builder.allow_only_email_fields; + }, + + /** + * Validate From Email in the Notification block. + * + * @since 1.8.1 + */ + validateFromEmail() { + // Detect repeated execution. + if ( wpf.isRepeatedCall( 'validateFromEmail' ) ) { + return; + } + + const $field = $( this ); + const value = $field.val(); + + if ( $field.data( 'value' ) === value ) { + return; + } + + $field.data( 'value', value ); + + const $fieldWrapper = $field.parent(); + const warningClass = 'wpforms-panel-field-warning'; + const blockedSymbolsRegex = /[\s,;]/g; + + if ( blockedSymbolsRegex.test( value.trim() ) ) { + $fieldWrapper.addClass( warningClass ); + app.printNotice( wpforms_builder.allow_only_one_email, $fieldWrapper ); + + return; + } + + if ( ! app.shouldCallAjaxValidation( value, $fieldWrapper, warningClass ) ) { + return; + } + + app.ajaxValidation( value, $fieldWrapper, warningClass ); + }, + + /** + * Whether we should call Ajax validation. + * + * @since 1.9.5 + * + * @param {*} value Field value. + * @param {jQuery} $fieldWrapper Field wrapper. + * @param {string} warningClass Warning class. + * + * @return {boolean} True if Ajax validation should be performed, otherwise false. + */ + shouldCallAjaxValidation( value, $fieldWrapper, warningClass ) { + let error = ''; + let callAjaxValidation = true; + + // If the field is empty. + error = value === '' ? wpforms_builder.empty_email_address : ''; + + // If the field is not empty, check for the `{field_id}` smart tag. + if ( error === '' ) { + error = app.getEmailFieldSmartTagError( value ); + callAjaxValidation = error === null; + } + + // If there is an error, we don't need to make an AJAX request. + if ( error ) { + $fieldWrapper.addClass( warningClass ); + app.printNotice( error, $fieldWrapper, value === '' ); + + return false; + } + + if ( ! callAjaxValidation ) { + $fieldWrapper.removeClass( warningClass ); + app.removeNotice( $fieldWrapper ); + + return false; + } + + return true; + }, + + /** + * Whether we should call Ajax validation. + * + * @since 1.9.5 + * + * @param {*} value Field value. + * @param {jQuery} $fieldWrapper Field wrapper. + * @param {string} warningClass Warning class. + */ + ajaxValidation( value, $fieldWrapper, warningClass ) { + const data = { + form_id: s.formID, // eslint-disable-line camelcase + email: value, + nonce: wpforms_builder.nonce, + action: 'wpforms_builder_notification_from_email_validate', + }; + + // noinspection JSUnusedLocalSymbols + $.post( + wpforms_builder.ajax_url, data, function( res ) { + app.removeNotice( $fieldWrapper ); + + if ( res.success ) { + $fieldWrapper.removeClass( warningClass ); + + return; + } + + $fieldWrapper.addClass( warningClass ); + $fieldWrapper.append( res.data ); + } + ).fail( function( xhr ) { + // eslint-disable-next-line no-console + console.log( xhr.responseText ); + } ); + }, + + /** + * Disabled fields. + * Addon fields in Lite initialization. + * + * @since 1.9.4 + */ + disabledFields: { + init() { + app.disabledFields.initCouponsChoicesJS(); + app.disabledFields.initFileUploadChoicesJS(); + }, + + /** + * Initialize Choices.js for the Coupon field. + * + * @since 1.9.4 + */ + initCouponsChoicesJS() { + if ( typeof window.Choices !== 'function' || WPForms.Admin.Builder.Coupons ) { + return; + } + + $( '.wpforms-field-option-row-allowed_coupons select:not(.choices__input)' ).each( function() { + const $select = $( this ); + const choicesInstance = new Choices( + $select.get( 0 ), + { + shouldSort: false, + removeItemButton: true, + renderChoicesLimit: 5, + callbackOnInit() { + wpf.showMoreButtonForChoices( this.containerOuter.element ); + }, + } ); + + // Save the Choices.js instance for future access. + $select.data( 'choicesjs', choicesInstance ); + } ); + }, + + /** + * Initialize Choices.js for the File Upload field. + * + * @since 1.9.4 + */ + initFileUploadChoicesJS() { + if ( typeof window.Choices !== 'function' || WPForms.Admin.Builder.FieldFileUpload ) { + return; + } + + const $selects = $( '.wpforms-file-upload-user-roles-select, .wpforms-file-upload-user-names-select' ); + + $selects.each( function() { + new Choices( $( this )[ 0 ], { removeItemButton: true } ); + } ); + }, + }, + + //--------------------------------------------------------------------// + // Icon Choices + //--------------------------------------------------------------------// + + /** + * Icon Choices component. + * + * @since 1.7.9 + */ + iconChoices: { + + /** + * Runtime component cache. + * + * Field "toggle": "Use Icon Choices" toggle that initiated the installation. + * Field "previousModal": Last open modal that may need to be closed. + * + * @since 1.7.9 + */ + cache: {}, + + /** + * Component configuration settings. + * + * @since 1.7.9 + */ + config: { + colorPropertyName: '--wpforms-icon-choices-color', + }, + + /** + * Initialize the component. + * + * @since 1.7.9 + */ + init() { + // Extend jquery-confirm plugin with max-height support for the content area. + app.iconChoices.extendJqueryConfirm(); + + $builder.on( 'wpformsBuilderReady', function( event ) { + // If there are Icon Choices fields but the library is not installed - force install prompt. + if ( wpforms_builder.icon_choices.is_active && ! wpforms_builder.icon_choices.is_installed ) { + app.iconChoices.openInstallPromptModal( true ); + + // Prevent the Form Builder from getting ready (hold the loading state). + event.preventDefault(); + } + } ); + + // Toggle Icon Choices on or off. + $builder.on( 'change', '.wpforms-field-option-row-choices_icons input', app.iconChoices.toggleIconChoices ); + + // Change accent color. + $builder.on( 'change', '.wpforms-field-option-row-choices_icons_color .wpforms-color-picker', app.iconChoices.changeIconsColor ); + + // Update field preview when option value is changed (style, size). + $builder.on( 'change', '.wpforms-field-option-row-choices_icons_style select, .wpforms-field-option-row-choices_icons_size select', function() { + const fieldID = $( this ).parent().data( 'field-id' ), + fieldType = $( '#wpforms-field-option-' + fieldID ).find( '.wpforms-field-option-hidden-type' ).val(); + + app.fieldChoiceUpdate( fieldType, fieldID ); + } ); + + // Open Icon Picker modal. + $builder.on( 'click', '.wpforms-field-option-row-choices .choices-list .wpforms-icon-select', app.iconChoices.openIconPickerModal ); + }, + + /** + * Turn the feature on or off. + * + * @since 1.7.9 + */ + toggleIconChoices() { // eslint-disable-line complexity + const $this = $( this ), + checked = $this.is( ':checked' ); + + // Check if a required icon library is installed. + if ( checked && ! wpforms_builder.icon_choices.is_installed ) { + app.iconChoices.cache.toggle = $this; + app.iconChoices.openInstallPromptModal(); + + return; + } + + const fieldID = $this.closest( '.wpforms-field-option-row' ).data( 'field-id' ); + const $fieldOptions = $( `#wpforms-field-option-${ fieldID }` ), + $imageChoices = $fieldOptions.find( `#wpforms-field-option-${ fieldID }-choices_images` ), + $choicesList = $fieldOptions.find( `#wpforms-field-option-row-${ fieldID }-choices ul` ); + + // Turn Image Choice off. + if ( checked && $imageChoices.is( ':checked' ) ) { + $imageChoices.prop( 'checked', false ).trigger( 'change' ); + } + + // Toggle Advanced > Dynamic Choices on or off. + $fieldOptions.find( `#wpforms-field-option-row-${ fieldID }-dynamic_choices` ).toggleClass( 'wpforms-hidden', checked ); + + // Toggle subfields. + $fieldOptions.find( `#wpforms-field-option-row-${ fieldID }-choices_icons_color` ).toggleClass( 'wpforms-hidden' ); + $fieldOptions.find( `#wpforms-field-option-row-${ fieldID }-choices_icons_size` ).toggleClass( 'wpforms-hidden' ); + $fieldOptions.find( `#wpforms-field-option-row-${ fieldID }-choices_icons_style` ).toggleClass( 'wpforms-hidden' ); + + const $colorOption = $fieldOptions.find( `#wpforms-field-option-${ fieldID }-choices_icons_color` ), + colorValue = _.isEmpty( $colorOption.val() ) ? wpforms_builder.icon_choices.default_color : $colorOption.val(); + + // Set accent color for all choices. + $choicesList.prop( 'style', `${ app.iconChoices.config.colorPropertyName }: ${ colorValue };` ); + + // Toggle icon selectors with previews for all choices. + $choicesList.toggleClass( 'show-icons', checked ); + + // Set the layout to inline on activation, revert to one column on deactivation. + $fieldOptions.find( `#wpforms-field-option-${ fieldID }-input_columns` ).val( checked ? 'inline' : '' ).trigger( 'change' ); + + $( `#wpforms-field-option-row-${ fieldID }-choices_icons_hide` ).toggleClass( 'wpforms-hidden', ! checked ); + + // Finally, update the preview. + app.fieldChoiceUpdate( $fieldOptions.find( '.wpforms-field-option-hidden-type' ).val(), fieldID ); + }, + + /** + * Change accent color and update previews. + * + * @since 1.7.9 + */ + changeIconsColor() { + const $this = $( this ), + fieldID = $this.parents( '.wpforms-field-option-row' ).data( 'field-id' ), + $field = $( '#wpforms-field-option-' + fieldID ), + type = $field.find( '.wpforms-field-option-hidden-type' ).val(), + $choicesList = $field.find( '.wpforms-field-option-row-choices .choices-list' ), + colorValue = app.getValidColorPickerValue( $this ); + + // Update icons color in options panel. + $choicesList.prop( 'style', `${ app.iconChoices.config.colorPropertyName }: ${ colorValue };` ); + + // Update preview. + app.fieldChoiceUpdate( type, fieldID ); + }, + + /** + * Open a modal prompting to install the icon library for Icon Choices. + * + * @since 1.7.9 + * + * @param {boolean} force Whether it's a normal installation procedure or forced if the library is necessary but is missing. + */ + openInstallPromptModal( force = false ) { + const content = force + ? wpforms_builder.icon_choices.strings.reinstall_prompt_content + : wpforms_builder.icon_choices.strings.install_prompt_content; + + const modal = $.confirm( { + title: wpforms_builder.heads_up, + content, + icon: 'fa fa-info-circle', + type: 'orange', + buttons: { + continue: { + text: wpforms_builder.continue, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + action() { + this.setIcon( 'fa fa-cloud-download' ); + this.setTitle( wpforms_builder.icon_choices.strings.install_title ); + this.setContent( wpforms_builder.icon_choices.strings.install_content ); + + $.each( this.buttons, function( _index, button ) { + button.hide(); + } ); + + app.iconChoices.installIconLibrary(); + + // Do not close the modal. + return false; + }, + }, + }, + onOpen() { + // Turn the toggle off during normal installation. + if ( ! force && app.iconChoices.cache.toggle ) { + app.iconChoices.cache.toggle.prop( 'checked', false ); + } + + app.iconChoices.cache.previousModal = this; + }, + } ); + + // Add a Cancel button for normal installation routine only. + if ( ! force ) { + modal.buttons.cancel = { + text: wpforms_builder.cancel, + keys: [ 'esc' ], + action() { + app.iconChoices.cache.toggle.prop( 'checked', false ); + }, + }; + } + }, + + /** + * Silently download and install the icon library on the server. + * + * @since 1.7.9 + */ + installIconLibrary() { + const data = { + // eslint-disable-next-line camelcase + _wp_http_referer: wpf.updateQueryString( '_wp_http_referer', null ), + nonce: wpforms_builder.nonce, + action: 'wpforms_icon_choices_install', + }; + + $.ajaxSetup( { + type: 'POST', + timeout: 120000, // 2 minutes. + } ); + + $.post( wpforms_builder.ajax_url, data, function( response ) { + // eslint-disable-next-line no-unused-expressions + response.success + ? app.iconChoices.openInstallSuccessModal() + : app.iconChoices.openInstallErrorModal( response ); + } ).fail( function( jqXHR ) { + app.iconChoices.openInstallErrorModal( jqXHR ); + } ); + }, + + /** + * Open a modal on icon library installation success. + * + * @since 1.7.9 + */ + openInstallSuccessModal() { + $.confirm( { + title: wpforms_builder.done, + content: wpforms_builder.icon_choices.strings.install_success_content, + icon: 'fa fa-check-circle', + type: 'green', + buttons: { + confirm: { + text: wpforms_builder.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + action() { + if ( app.iconChoices.cache.toggle ) { + app.iconChoices.cache.toggle.prop( 'checked', true ); + + const fieldId = app.iconChoices.cache.toggle.parents( '.wpforms-field-option-row' ).data( 'field-id' ); + const $imageChoices = $builder.find( `#wpforms-field-option-${ fieldId }-choices_images` ); + + // Turn Image Choice off, if needed, without triggering change event. + if ( $imageChoices.is( ':checked' ) ) { + $imageChoices.prop( 'checked', false ); + } + } + + wpforms_builder.exit_url = window.location.href; + + app.formSave( true ); + }, + }, + }, + onOpen() { + if ( app.iconChoices.cache.toggle ) { + const fieldId = app.iconChoices.cache.toggle.parents( '.wpforms-field-option-row-choices_icons' ).data( 'field-id' ); + + $builder.find( `#wpforms-field-option-${ fieldId }-input_columns` ).val( 'inline' ); + } + + app.iconChoices.cache.previousModal.close(); + }, + } ); + }, + + /** + * Open a modal on icon library installation failure. + * + * @since 1.7.9 + * + * @param {Object} errorData Unsuccessful ajax JSON response or jqXHR object. + */ + openInstallErrorModal( errorData ) { + $.confirm( { + title: wpforms_builder.uh_oh, + content: wpforms_builder.icon_choices.strings.install_error_content, + icon: 'fa fa-exclamation-circle', + type: 'red', + buttons: { + confirm: { + text: wpforms_builder.ok, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + action() { + if ( app.iconChoices.cache.toggle ) { + app.iconChoices.cache.toggle.prop( 'checked', false ); + } else { + app.formSaveError(); + } + }, + }, + }, + onOpen() { + wpf.debug( errorData ); + app.iconChoices.cache.previousModal.close(); + }, + onDestroy() { + // Clean up the cache, we're done. + delete app.iconChoices.cache.previousModal; + delete app.iconChoices.cache.toggle; + }, + } ); + }, + + /** + * Extend jquery-confirm plugin with support of max-height for the content area. + * + * @since 1.7.9 + */ + extendJqueryConfirm() { + // Extend a method of global instance. + // noinspection JSUnusedGlobalSymbols + window.Jconfirm.prototype._updateContentMaxHeight = function() { + // noinspection JSUnresolvedReference + const height = + $( window ).height() - + ( this.$jconfirmBox.outerHeight() - this.$contentPane.outerHeight() ) - + ( this.offsetTop + this.offsetBottom ); + + // Custom property, if set via jquery-confirm options. + // noinspection JSUnresolvedReference + const maxHeight = this.contentMaxHeight || height; + + // noinspection JSUnresolvedReference + this.$contentPane.css( { + 'max-height': Math.min( maxHeight, height ) + 'px', + } ); + }; + }, + + /** + * Open Icon Picker modal. + * + * @since 1.7.9 + */ + openIconPickerModal() { + const $this = $( this ); + + const data = { + fieldId: $this.parents( '.wpforms-field-option-row' ).data( 'field-id' ), + choiceId: $this.parent().data( 'key' ), + selectedIcon: $this.find( '.source-icon' ).val(), + selectedIconStyle: $this.find( '.source-icon-style' ).val(), + }; + + const title = ` + ${ wpforms_builder.icon_choices.strings.icon_picker_title } + ${ wpforms_builder.icon_choices.strings.icon_picker_description } + + `; + + const content = ` +
    +
      +
        +

        +

        `; + + $.confirm( { + title, + titleClass: 'wpforms-icon-picker-title', + content, + icon: false, + closeIcon: true, + type: 'orange', + backgroundDismiss: true, + boxWidth: 800, + contentMaxHeight: 368, // Custom property, see app.iconChoices.extendJqueryConfirm(). + smoothContent: false, + buttons: false, + onOpenBefore() { + // Add custom classes to target various elements. + this.$body.addClass( 'wpforms-icon-picker-jconfirm-box' ); + this.$contentPane.addClass( 'wpforms-icon-picker-jconfirm-content-pane' ); + }, + onContentReady() { + /** @type {Modal} */ + const modal = this; + + // Initialize the list of icons with List.js and display the 1st page. + app.iconChoices.initIconsList( data ); + + // Focus the search input. + modal.$title.find( '.search' ).focus(); + + // Listen for clicks on icons to select them. + modal.$content.find( '.wpforms-icon-picker-icons' ).on( 'click', 'li', function() { + app.iconChoices.selectIcon( modal, $( this ) ); + } ); + }, + } ); + }, + + /** + * Initialize List.js in the Icon Selector modal on demand and cache it. + * + * @since 1.7.9 + * + * @param {Object} data Source option data - field and choice IDs, selected icon name and style. + */ + initIconsList( data ) { + const options = { + valueNames: [ 'name' ], + listClass: 'wpforms-icon-picker-icons', + page: wpforms_builder.icon_choices.icons_per_page, + pagination: { + paginationClass: 'wpforms-icon-picker-pagination', + }, + item( values ) { + const maybeSelectedClass = ( values.icon === data.selectedIcon && values.style === data.selectedIconStyle ) ? 'class="selected"' : ''; + + return ` +
      • + + ${ values.icon } +
      • `; + }, + indexAsync: true, + }; + + // Initialize List.js instance. + const iconsList = new List( 'wpforms-icon-picker-icons', options, wpforms_builder.icon_choices.icons ); + + // Initialize infinite scroll pagination on the list instance. + app.iconChoices.infiniteScrollPagination( iconsList ); + + // Bind search to custom input. + $( '#wpforms-icon-picker-search' ).on( 'keyup', function() { + // Custom partial match search. + iconsList.search( $( this ).val(), [ 'name' ], function( searchString ) { + for ( let index = 0, length = iconsList.items.length; index < length; index++ ) { + iconsList.items[ index ].found = ( new RegExp( searchString ) ).test( iconsList.items[ index ].values().icon ); + } + } ); + } ); + + // Show a "nothing found" message if the search returned no results. + iconsList.on( 'searchComplete', function() { + const $element = $( '.wpforms-icon-picker-not-found' ); + + $element.html( $element.data( 'message' ).replace( '{keyword}', $( '#wpforms-icon-picker-search' ).val() ) ); + $element.toggleClass( 'wpforms-hidden', ! _.isEmpty( iconsList.matchingItems ) ); + } ); + }, + + /** + * Handle infinite scroll on the list of icons. + * + * @since 1.7.9 + * + * @param {Object} list List.js instance. + */ + infiniteScrollPagination( list ) { + let page = 1; + + const options = { + root: document.querySelector( '.wpforms-icon-picker-jconfirm-content-pane' ), + rootMargin: '600px', // 5 rows of icons. Formula: 20 + ( (96 + 20) * rows ). + }; + + const observer = new IntersectionObserver( function( entries ) { + if ( ! entries[ 0 ].isIntersecting ) { + return; + } + + page++; + list.show( 0, page * wpforms_builder.icon_choices.icons_per_page ); + }, options ); + + observer.observe( document.querySelector( '.wpforms-icon-picker-pagination' ) ); + }, + + /** + * When an icon is selected, update the choice and the field preview. + * + * @since 1.7.9 + * + * @param {Object} modal Current jQuery Confirm modal instance. + * @param {jQuery} $this The list item (icon) that was clicked. + */ + selectIcon( modal, $this ) { + const fieldId = $this.parent().data( 'field-id' ); + const choiceId = $this.parent().data( 'choice-id' ); + const icon = $this.data( 'icon' ); + const iconStyle = $this.data( 'icon-style' ); + const $choice = $( `#wpforms-field-option-row-${ fieldId }-choices ul li[data-key=${ choiceId }]` ); + const fieldType = $( `#wpforms-field-option-row-${ fieldId }-choices ul` ).data( 'field-type' ); + + $this.addClass( 'selected' ); + $this.siblings( '.selected' ).removeClass( 'selected' ); + + $choice.find( '.wpforms-icon-select span' ).text( icon ); + $choice.find( '.wpforms-icon-select .ic-fa-preview' ).removeClass().addClass( `ic-fa-preview ic-fa-${ iconStyle } ic-fa-${ icon }` ); + $choice.find( '.wpforms-icon-select .source-icon' ).val( icon ); + $choice.find( '.wpforms-icon-select .source-icon-style' ).val( iconStyle ); + + app.fieldChoiceUpdate( fieldType, fieldId ); + + modal.close(); + }, + }, + + //--------------------------------------------------------------------// + // Alerts (notices). + //--------------------------------------------------------------------// + + /** + * Click on the Dismiss notice button. + * + * @since 1.6.7 + */ + dismissNotice() { + $builder.on( 'click', '.wpforms-alert-field-not-available .wpforms-dismiss-button', function( e ) { + e.preventDefault(); + + const $button = $( this ), + $alert = $button.closest( '.wpforms-alert' ), + fieldId = $button.data( 'field-id' ); + + $alert.addClass( 'out' ); + setTimeout( function() { + $alert.remove(); + }, 250 ); + + if ( fieldId ) { + $( '#wpforms-field-option-' + fieldId ).remove(); + } + } ); + }, + + //--------------------------------------------------------------------// + // Other functions. + //--------------------------------------------------------------------// + + /** + * Trim long form titles. + * + * @since 1.0.0 + */ + trimFormTitle() { + const $title = $( '.wpforms-center-form-name' ); + + if ( $title.text().length > 38 ) { + const shortTitle = $title.text().trim().substring( 0, 38 ).split( ' ' ).slice( 0, -1 ).join( ' ' ) + '...'; + + $title.text( shortTitle ); + } + }, + + /** + * Load or refresh the color picker. + * + * @since 1.2.1 + * @since 1.7.9 Added default value support. + * @since 1.9.7 Added `$context` and `options` parameters. + * + * @param {jQuery|null} $context Container to search for color picker elements. + * @param {Object|null} options Color picker options. + */ + loadColorPickers( $context = null, options = null ) { + $context = $context || $builder; + options = options || {}; + + $context.find( '.wpforms-color-picker' ).each( function() { + const $input = $( this ); + const $minicolors = $input.closest( '.minicolors' ); + + // Skip the focused (active) color picker. + if ( $minicolors.hasClass( 'minicolors-focus' ) && options.skipFocused ) { + return; + } + + // If it appears to be already initialized, reset. This is necessary when duplicating fields with color pickers. + if ( $input.hasClass( 'minicolors-input' ) ) { + $input.minicolors( 'destroy' ); + } + + const pickerOptions = { + defaultValue: $input.data( 'fallback-color' ) || '', + ...options, + }; + + $input.minicolors( pickerOptions ); + } ); + }, + + /** + * Get a valid color value from the color picker or a default one. + * + * @since 1.7.9 + * + * @param {Object} $colorPicker Current field. + * + * @return {string} Always valid color value. + */ + getValidColorPickerValue( $colorPicker ) { + const color = $colorPicker.minicolors( 'value' ); + + // jQuery MiniColors returns a "black" RGB object if the color value is invalid. + const isInvalid = _.isEqual( $colorPicker.minicolors( 'rgbObject' ), { r: 0, g: 0, b: 0 } ); + const isBlack = _.includes( [ '#000', '#000000' ], color ); + + // If default value isn't provided via the data attribute, use black. + const defaultValue = $colorPicker.data( 'fallback-color' ) || '#000000'; + + return isInvalid && ! isBlack ? defaultValue : color; + }, + + /** + * Hotkeys: + * Ctrl+H - Help. + * Ctrl+P - Preview. + * Ctrl+B - Embed. + * Ctrl+E - Entries. + * Ctrl+S - Save. + * Ctrl+Q - Exit. + * Ctrl+/ - Keyboard Shortcuts modal. + * Ctrl+F - Focus search fields input. + * Ctrl+T - Toggle sidebar (Alt+S on Windows and Linux). + * + * @since 1.2.4 + */ + builderHotkeys() { + $( document ).on( 'keydown', function( e ) { // eslint-disable-line complexity + // Toggle sidebar on Alt+S (on Windows and Linux). + if ( ( browser.isLinux || browser.isWindows ) && e.altKey && e.keyCode === 83 ) { + $( elements.$sidebarToggle, $builder ).trigger( 'click' ); + + return; + } + + if ( ! e.ctrlKey ) { + return; + } + + switch ( e.keyCode ) { + case 72: // Open the Help screen on Ctrl+H. + $( elements.$helpButton, $builder ).trigger( 'click' ); + break; + + case 80: // Open the Form Preview tab on Ctrl+P. + window.open( wpforms_builder.preview_url ); + break; + + case 66: // Trigger the Embed modal on Ctrl+B. + $( elements.$embedButton, $builder ).trigger( 'click' ); + break; + + case 69: // Open the Entries tab on Ctrl+E. + window.open( wpforms_builder.entries_url ); + break; + + case 83: // Trigger the Builder save on Ctrl+S. + $( elements.$saveButton, $builder ).trigger( 'click' ); + break; + + case 81: // Trigger the Exit on Ctrl+Q. + $( elements.$exitButton, $builder ).trigger( 'click' ); + break; + + case 191: // Keyboard shortcuts modal on Ctrl+/. + app.openKeyboardShortcutsModal(); + break; + + case 84: // Toggle sidebar on Ctrl+T. + $( elements.$sidebarToggle, $builder ).trigger( 'click' ); + break; + + case 70: // Focus search fields input on Ctrl+F. + elements.$addFieldsTab.trigger( 'click' ); + elements.$fieldsSidebar.scrollTop( 0 ); + elements.$searchInput.focus(); + break; + + default: + return; + } + + return false; + } ); + }, + + /** + * Open Keyboard Shortcuts modal. + * + * @since 1.6.9 + */ + openKeyboardShortcutsModal() { + // Close the already opened instance. + if ( $( '.wpforms-builder-keyboard-shortcuts' ).length ) { + jconfirm.instances[ jconfirm.instances.length - 1 ].close(); + + return; + } + + $.alert( { + title: wpforms_builder.shortcuts_modal_title, + content: wpforms_builder.shortcuts_modal_msg + wp.template( 'wpforms-builder-keyboard-shortcuts' )(), + icon: 'fa fa-keyboard-o', + type: 'blue', + boxWidth: '550px', + smoothContent: false, + buttons: { + confirm: { + text: wpforms_builder.close, + btnClass: 'btn-confirm', + keys: [ 'enter' ], + }, + }, + onOpenBefore() { + this.$body.addClass( 'wpforms-builder-keyboard-shortcuts' ); + // Dynamically change the shortcut key documentation on Windows/Linux. + if ( browser.isLinux || browser.isWindows ) { + this.$body.find( '.shortcut-key.shortcut-key-ctrl-t' ).html( 'alts' ); + } + }, + } ); + }, + + /** + * Register JS templates for various elements. + * + * @since 1.4.8 + */ + registerTemplates() { + if ( typeof WPForms === 'undefined' ) { + return; + } + + WPForms.Admin.Builder.Templates.add( [ + 'wpforms-builder-confirmations-message-field', + 'wpforms-builder-conditional-logic-toggle-field', + ] ); + }, + + /** + * Exit builder. + * + * @since 1.5.7 + * @since 1.7.8 Deprecated. + */ + exitBack() { + // eslint-disable-next-line no-console + console.warn( 'WARNING! Function "WPFormsBuilder.exitBack()" has been deprecated.' ); + }, + + /** + * Update select field placeholder. + * + * Updates the select field placeholder to be "--- Select Choice". + * First checks if the field has required to be toggled on and if this is not a multiple selection field. + * Does not update the placeholder if it is already set. + * + * @since 1.9.6 + * + * @param {number} id Field id. + * @param {jQuery} $preview Field preview. + */ + onUpdateSelectPlaceholder( id, $preview ) { // eslint-disable-line complexity + if ( + ! [ 'select', 'payment-select' ].includes( $preview.data( 'field-type' ) ) || + ! $preview.hasClass( 'required' ) || + $( `#wpforms-field-option-${ id }-multiple` ).prop( 'checked' ) + ) { + return; + } + + // Check if this field has a preselected default value. + if ( app.dropdownField.helpers.hasDefaults( id ) ) { + return; + } + + app.updateSelectPlaceholder( id ); + }, + + /** + * Update the selected placeholder if it does not have value already. + * + * @since 1.9.6 + * + * @param {number} fieldId Field id. + */ + updateSelectPlaceholder( fieldId ) { + const $placeholder = $( `#wpforms-field-option-${ fieldId }-placeholder` ); + + if ( ! $placeholder.val() ) { + $placeholder.val( wpforms_builder.select_choice ).trigger( 'input' ); + } + }, + + /** + * Acts when user deselects default choice on dropdown. + * + * @since 1.9.6 + * + * @param {number} fieldId Field id. + */ + maybeUpdateRequiredPlaceholder( fieldId ) { + const isRequired = $( `#wpforms-field-option-${ fieldId }-required` ).is( ':checked' ); + + if ( ! isRequired ) { + return; + } + + app.updateSelectPlaceholder( fieldId ); + }, + }; + + // Provide access to public functions/properties. + return app; +}( document, window, jQuery ) ); + +WPFormsBuilder.init(); diff --git a/wp-content/plugins/wpforms-lite/assets/js/admin/builder/admin-builder.min.js b/wp-content/plugins/wpforms-lite/assets/js/admin/builder/admin-builder.min.js new file mode 100755 index 00000000..c4ba9519 --- /dev/null +++ b/wp-content/plugins/wpforms-lite/assets/js/admin/builder/admin-builder.min.js @@ -0,0 +1,25 @@ +var WPFormsBuilder=window.WPFormsBuilder||((r,a,v)=>{let m,y,C={},i={},o=!0,n=!1,t=null,k={settings:{spinner:'',spinnerInline:'',tinymceDefaults:{tinymce:{toolbar1:"bold,italic,underline,blockquote,strikethrough,bullist,numlist,alignleft,aligncenter,alignright,undo,redo,link"},quicktags:!0},pagebreakTop:!1,pagebreakBottom:!1,upload_img_modal:!1,choicesLimit:20,choicesLimitLong:250},init(){let e=this;wpforms_panel_switch=!0,m=this.settings,v(k.ready),v(a).on("load",function(){"function"==typeof v.ready.then?v.ready.then(k.load):k.load()}),v(a).on("beforeunload",function(){if(!e.formIsSaved()&&o)return wpforms_builder.are_you_sure_to_close})},load(){if(wpf.getQueryString("newform")&&k.formSave(!1),"revisions"===v("#wpforms-panels-toggle .active").data("panel")&&k.updateRevisionPreview(),WPFormsUtils.triggerEvent(y,"wpformsBuilderReady").isDefaultPrevented())return!1;k.hideLoadingOverlay(),k.determineActiveSections(),k.confirmationsSetup(),WPFormsUtils.triggerEvent(y,"wpformsBuilderConfirmationsReady"),k.loadMsWinCSS(),"1"==wpforms_builder.template_modal_display&&"fields"===wpf.getQueryString("view")&&v.alert({title:wpforms_builder.template_modal_title,content:wpforms_builder.template_modal_msg,icon:"fa fa-info-circle",type:"blue",buttons:{confirm:{text:wpforms_builder.close,btnClass:"btn-confirm",keys:["enter"]}}}),wpf._updateFormState()},initElementsCache(){y=v("#wpforms-builder"),i.isWindows=/Win/.test(navigator.userAgent),i.isLinux=/Linux/.test(navigator.userAgent),i.isMac=/Mac/.test(navigator.userAgent),C.$helpButton=v(".js-wpforms-help"),C.$previewButton=v("#wpforms-preview-btn"),C.$embedButton=v("#wpforms-embed"),C.$saveButton=v("#wpforms-save"),C.$exitButton=v("#wpforms-exit"),C.$noFieldsOptions=v("#wpforms-panel-fields .wpforms-no-fields-holder .no-fields"),C.$noFieldsPreview=v("#wpforms-panel-fields .wpforms-no-fields-holder .no-fields-preview"),C.$formPreview=v("#wpforms-panel-fields .wpforms-preview-wrap"),C.$revisionPreview=v("#wpforms-panel-revisions .wpforms-panel-content"),C.defaultEmailSelector=".wpforms-field-option-email .wpforms-field-option-row-default_value input",C.$defaultEmail=v(C.defaultEmailSelector),C.$focusOutTarget=null,C.$nextFieldId=v("#wpforms-field-id"),C.$addFieldsTab=v("#add-fields a"),C.$fieldOptions=v("#wpforms-field-options"),C.$fieldsPreviewWrap=v("#wpforms-panel-fields .wpforms-panel-content-wrap"),C.$sortableFieldsWrap=v("#wpforms-panel-fields .wpforms-field-wrap"),C.$addFieldsButtons=v(".wpforms-add-fields-button").not(".not-draggable").not(".warning-modal").not(".education-modal"),C.$fieldsSidebar=v("#wpforms-panel-fields .wpforms-add-fields"),C.$searchInput=v("#wpforms-search-fields-input"),C.$sidebarToggle=v(".wpforms-panels .wpforms-panel-sidebar-content .wpforms-panel-sidebar-toggle")},ready(){k.isVisitedViaBackButton()?location.reload():(k.initElementsCache(),v.ajaxSetup({data:{_wp_http_referer:wpf.updateQueryString("_wp_http_referer",null)}}),k.isBuilderInPopup()&&(C.$embedButton.remove(),C.$previewButton.addClass("wpforms-alone")),k.bindUIActions(),m.formID=v("#wpforms-builder-form").data("id"),m.pagebreakTop=v(".wpforms-pagebreak-top").length,m.pagebreakBottom=v(".wpforms-pagebreak-bottom").length,y.on("keypress","#wpforms-builder-form :input:not(textarea)",function(e){13===e.keyCode&&e.preventDefault()}),k.loadEntryPreviewFields(),k.fieldChoiceSortable("select"),k.fieldChoiceSortable("radio"),k.fieldChoiceSortable("checkbox"),k.fieldChoiceSortable("payment-multiple"),k.fieldChoiceSortable("payment-checkbox"),k.fieldChoiceSortable("payment-select"),v(".wpforms-add-fields-group").each(function(){k.fieldGroupToggle(v(this),"load")}),k.registerTemplates(),k.trimFormTitle(),wpf.initTooltips(),k.loadColorPickers(),k.captchaToggle(),k.notificationToggle(),k.notificationsByStatusAlerts(),k.builderHotkeys(),jconfirm.defaults={closeIcon:!1,backgroundDismiss:!1,escapeKey:!0,animationBounce:1,useBootstrap:!1,theme:"modern",boxWidth:"400px",animateFromElement:!1,content:wpforms_builder.something_went_wrong},k.dropdownField.init(),k.iconChoices.init(),k.disabledFields.init(),k.checkEmptyDynamicChoices(),k.initSomeFieldOptions(),k.dismissNotice(),wpf.initializeChoicesEventHandlers())},checkEmptyDynamicChoices(){var e=wpf.orders.choices||{};Object.keys(e).length&&wpf.orders.fields.forEach(function(i){if(k.dropdownField.helpers.isDynamicChoices(i)){var o=v("#wpforms-field-"+i),t=k.dropdownField.helpers.getDynamicChoicesOptionType(i),r=k.dropdownField.helpers.getDynamicChoicesOptionSource(i),s=k.dropdownField.helpers.isDynamicChoicesOptionModern(i);let e=s?o.find(".has-no-choices").length:0===o.find(".primary-input option:not(.placeholder), .primary-input li").length;s&&!e&&(o=v("#wpforms-field-option-"+i+"-placeholder").val(),s=k.dropdownField.helpers.getInitialChoices(i),e=1===s.length&&s[0].label===o&&!0===s[0].placeholder),e&&k.emptyChoicesNotice(i,r,t)}})},loadMsWinCSS(){i.isMac||v("").appendTo("head").attr({type:"text/css",rel:"stylesheet",href:wpforms_builder.scrollbars_css_url})},isVisitedViaBackButton(){if(!performance)return!1;let i=!1;return performance.getEntriesByType("navigation").forEach(function(e){"back_forward"===e.type&&(i=!0)}),i},hideLoadingOverlay(){let e=v("#wpforms-builder-overlay");e.addClass("fade-out"),setTimeout(function(){e.hide()},250)},showLoadingOverlay(){var e=v("#wpforms-builder-overlay");e.removeClass("fade-out"),e.show()},initSomeFieldOptions(){k.toggleAllOptionGroups(y),y.find(".wpforms-field-option-row-date .type select").trigger("change"),y.find(".wpforms-field-option-row-read_only input:checked").trigger("change")},dropdownField:{config:{modernClass:"choicesjs-select",args:{searchEnabled:!1,searchChoices:!1,renderChoiceLimit:1,shouldSort:!1,callbackOnInit(){var e=v(this.containerOuter.element),i=e.closest(".wpforms-field").find("select");e.hasClass("is-disabled")&&e.removeClass("is-disabled"),i.is("[readonly]")&&(this.disable(),i.prop("disabled",!1)),this.passedElement.element.multiple&&this.getValue(!0).length&&v(this.input.element).addClass("choices__input--hidden"),e.find(".choices__item--selectable").each(function(){var e=v(this),i=wpf.decodeAllowedHTMLEntities(e.text());e.text(i)})}}},init(){y.find("."+k.dropdownField.config.modernClass).each(function(){k.dropdownField.events.choicesInit(v(this))}),y.on("change",".wpforms-field-option-select .wpforms-field-option-row-multiple input",k.dropdownField.events.multiple),y.on("change",".wpforms-field-option-select .wpforms-field-option-row-style select, .wpforms-field-option-payment-select .wpforms-field-option-row-style select",k.dropdownField.events.applyStyle),y.on("click",".choices",function(e){var i=v(this),o=i.find("select").data("choicesjs");o&&i.hasClass("is-open")&&e.target.classList.contains("choices__inner")&&o.hideDropdown()})},events:{choicesInit(e){var i=1===e.data("choicesjs-use-ajax");let o;o="select_pages"===e.data("choicesjs-callback-fn")?WPForms.Admin.Builder.WPFormsChoicesJS.setup(e[0],k.dropdownField.config.args,{action:"wpforms_ajax_search_pages_for_dropdown",nonce:i?wpforms_builder.nonce:null}):new Choices(e[0],k.dropdownField.config.args),k.dropdownField.helpers.setInstance(e,o),k.dropdownField.helpers.addPlaceholderChoice(e,o),e.closest(".choices").toggleClass("wpforms-hidden",!o.config.choices.length)},multiple(e){var i=v(this).closest(".wpforms-field-option-row-multiple").data().fieldId,o=k.dropdownField.helpers.getPrimarySelector(i),t=v(`#wpforms-field-option-row-${i}-choices input.default`),r=o.find(".placeholder"),s=k.dropdownField.helpers.isDynamicChoices(i),e=e.target.checked,l=e?"checkbox":"radio",l=(o.prop("multiple",e),t.prop("type",l),s&&o.find("option:selected").prop("selected",!1),t.filter(":checked"));!e&&l.length&&(t.prop("checked",!1),v(l.get(0)).prop("checked",!0)),r.length&&r.prop("selected",!e),k.dropdownField.helpers.update(i,s)},applyStyle(){var e=v(this),i=e.closest(".wpforms-field-option-row-style").data().fieldId;"modern"===e.val()?k.dropdownField.helpers.convertClassicToModern(i):k.dropdownField.helpers.convertModernToClassic(i)}},helpers:{convertModernToClassic:e=>{var i=k.dropdownField.helpers.getPrimarySelector(e),o=k.dropdownField.helpers.isDynamicChoices(e),i=k.dropdownField.helpers.getInstance(i),t=v("#wpforms-field-option-row-"+e+"-choices").find(".choices-list").find("li").length;i&&"function"==typeof i.destroy&&(i.destroy(),k.dropdownField.helpers.updatePlaceholderChoice(i,e)),o||k.fieldChoiceUpdate("select",e,t)},getInitialChoices(e){e=k.dropdownField.helpers.getPrimarySelector(e);return k.dropdownField.helpers.getInstance(e).config.choices},convertClassicToModern(e){var i=k.dropdownField.helpers.getPrimarySelector(e);k.dropdownField.helpers.isDynamicChoices(e)||k.fieldChoiceUpdate("select",e),k.dropdownField.events.choicesInit(i)},update(e,i){var o=k.dropdownField.helpers.getPrimarySelector(e);k.dropdownField.helpers.isModernSelect(o)?(k.dropdownField.helpers.convertModernToClassic(e),i||k.dropdownField.events.choicesInit(o)):i||k.fieldChoiceUpdate("select",e)},addPlaceholderChoice(e,i){e=e.closest(".wpforms-field");if(e.length<=0)return!1;var o,t,r,e=e.data().fieldId;let s=k.dropdownField.helpers.hasDefaults(e);return k.dropdownField.helpers.isDynamicChoices(e)&&(s=!1),!1===k.dropdownField.helpers.searchPlaceholderChoice(i)&&!!i.config.choices.length&&(e=v("#wpforms-field-option-"+e+"-placeholder").val(),o=wpf.decodeAllowedHTMLEntities(e),r=!((t=v(i.passedElement.element).prop("multiple"))||s),i.setChoices([{value:"",label:o,selected:r,placeholder:!0}],"value","label",!1),t&&v(i.input.element).prop("placeholder",e),!0)},searchPlaceholderChoice(e){let o=!1;return e.config.choices.forEach(function(e,i){if(void 0!==e.placeholder&&!0===e.placeholder)return!(o={key:i,item:e})}),o},updatePlaceholderChoice(e,i){var o=v(e.passedElement.element),i=wpf.sanitizeHTML(v("#wpforms-field-option-"+i+"-placeholder").val()),e=k.dropdownField.helpers.searchPlaceholderChoice(e);let t={};"object"==typeof e&&(t=v(o.find("option").get(e.key))),""!==i?!v.isEmptyObject(t)&&t.length?t.addClass("placeholder").text(i):o.prepend('"):t.length&&t.remove()},isModernSelect(e){e=k.dropdownField.helpers.getInstance(e);return"object"==typeof e&&!v.isEmptyObject(e)&&e.initialised},setInstance(e,i){e.data("choicesjs",i)},getInstance(e){return e.data("choicesjs")},getDynamicChoicesOption(e){e=v("#wpforms-field-option-"+e+"-dynamic_choices");return!!e.length&&e},isDynamicChoices(e){e=k.dropdownField.helpers.getDynamicChoicesOption(e);return!!e.length&&""!==e.val()},isDynamicChoicesOptionModern(e){e=v("#wpforms-field-option-"+e+"-style");return!!e.length&&"modern"===e.val()},getDynamicChoicesOptionType(e){e=k.dropdownField.helpers.getDynamicChoicesOption(e);return!!e.length&&e.val()},getDynamicChoicesOptionSource(e){var i=k.dropdownField.helpers.getDynamicChoicesOptionType(e),e=v("#wpforms-field-option-"+e+"-dynamic_"+i);return!!e.length&&e.find("option:selected").text()},hasDefaults(e){return!!v(`#wpforms-field-option-row-${e}-choices .choices-list`).find("input.default:checked").length},getPrimarySelector(e){return v("#wpforms-field-"+e+" .primary-input")}}},numberSliderEvents(e){e.on("focusout",".wpforms-field-option-row-min_max .wpforms-input-row .wpforms-number-slider-min",k.fieldNumberSliderUpdateMin),e.on("focusout",".wpforms-field-option-row-min_max .wpforms-input-row .wpforms-number-slider-max",k.fieldNumberSliderUpdateMax),e.on("input",".wpforms-number-slider-default-value",_.debounce(k.changeNumberSliderDefaultValue,500)),e.on("focusout",".wpforms-number-slider-default-value",k.changeNumberSliderEmptyDefaultValue),e.find(".wpforms-number-slider-default-value").trigger("input"),e.on("input",".wpforms-number-slider-step",_.debounce(k.changeNumberSliderStep,500)),e.on("focusout",".wpforms-number-slider-step",k.checkNumberSliderStep),e.on("input",".wpforms-number-slider-value-display",_.debounce(k.changeNumberSliderValueDisplay,500)),e.on("input",".wpforms-number-slider-min",_.debounce(k.changeNumberSliderMin,500)),e.on("input",".wpforms-number-slider-max",_.debounce(k.changeNumberSliderMax,500))},changeNumberSliderMin(e){var i=parseFloat(e.target.value);isNaN(i)||(i=v(e.target).parents(".wpforms-field-option-row").data("fieldId"),k.updateNumberSliderDefaultValueAttr(i,e.target.value,"min"))},changeNumberSliderMax(e){var i=parseFloat(e.target.value);isNaN(i)||(i=v(e.target).parents(".wpforms-field-option-row").data("fieldId"),k.updateNumberSliderDefaultValueAttr(i,e.target.value,"max").updateNumberSliderStepValueMaxAttr(i,e.target.value))},changeNumberSliderValueDisplay(e){var i=e.target.value,e=v(e.target).parents(".wpforms-field-option-row").data("fieldId"),o=r.getElementById("wpforms-field-option-"+e+"-default_value");o&&k.updateNumberSliderHintStr(e,i).updateNumberSliderHint(e,o.value)},changeNumberSliderStep(e){var i,o,t,r=v(this),s=parseFloat(r.val());isNaN(s)||s<=0||(o=v(r).closest(".wpforms-field-option"),(t=((i=parseFloat(o.find(".wpforms-number-slider-max").val()))-(o=parseFloat(o.find(".wpforms-number-slider-min").val()))).toFixed(2))e%1==0?e.toString():e.toFixed(2))(i),(o=r(o))===(r=r(t))||o===i||r===i?k.removeNotice(e):(t=wpforms_builder.number_slider_error_valid_default_value.replace("{from}",o).replace("{to}",r),k.printNotice(t,e))),this},calculateClosestMultiples(e,i,o,t){let r=o+Math.floor((e-o)/i)*i,s=o+Math.ceil((e-o)/i)*i;return e===(s=e===r&&e!==o?r+i:s)&&e!==t&&(r=s-i),e===o&&(s=o+i),e===t&&(r=t-i),r=Math.max(r,o),s=Math.min(s,t),{closestSmallerMultiple:r,closestLargerMultiple:s}},printNotice(e,i,o=!1){i.length&&(this.removeNotice(i),i.append(`

        ${e}

        `))},removeNotice(e){e.length&&e.find(".wpforms-alert").length&&e.find(".wpforms-alert").remove()},checkNumberSliderStep(e){e=parseFloat(e.target.value);if(isNaN(e)||!(0"+i+"")),this},fieldNumberSliderUpdateMin(e){var i,o,t=parseFloat(e.target.value);isNaN(t)||(i=v(e.target).parents(".wpforms-field-option-row-min_max"),(o=parseFloat(i.find(".wpforms-number-slider-max").val()))<=t?(e.preventDefault(),this.value=o):(e=i.data("field-id"),y.find("#wpforms-field-"+e+' input[type="range"]').attr("min",t)))},fieldNumberSliderUpdateMax(e){var i,o,t=parseFloat(e.target.value);isNaN(t)||(i=v(e.target).parents(".wpforms-field-option-row-min_max"),t<=(o=parseFloat(i.find(".wpforms-number-slider-min").val()))?(e.preventDefault(),this.value=o):(e=i.data("field-id"),y.find("#wpforms-field-"+e+' input[type="range"]').attr("max",t)))},updateNumberSliderStepValueMaxAttr(e,i){var o,e=r.getElementById("wpforms-field-option-"+e+"-step");return e&&(o=parseFloat(e.value),e.setAttribute("max",i),(i=parseFloat(i)) .label-title .text").text(t)}),y.on("input",".wpforms-field-option-row-description textarea",function(){var e=v(this),i=wpf.sanitizeHTML(e.val()),o=e.parent().data("field-id"),t=v(`#wpforms-field-${o} > .description, + #wpforms-field-${o} .format-selected-single > .description, + #wpforms-field-${o} .wpforms-field-internal-information-row-description`);k.updateDescription(t,i),e.trigger("wpformsDescriptionFieldUpdated",{id:o,descField:t,value:i})}),y.on("change",".wpforms-field-option-row-required input",function(){var e=v(this).closest(".wpforms-field-option-row").data("field-id"),i=v("#wpforms-field-"+e);i.toggleClass("required"),k.onUpdateSelectPlaceholder(e,i)}),y.on("click",".choices-list input.default",function(){var e=v(this),i=e.closest(".choices-list").data("field-id");e.is(":checked")||k.maybeUpdateRequiredPlaceholder(i),y.trigger("wpformsChoicesSetDefault",[this])}),y.on("change",".wpforms-field-option-row-summary input",function(){var e=v(this),i=e.closest(".wpforms-field-option-row").data("field-id");v("#wpforms-field-"+i).toggleClass("wpforms-summary-enabled"),e.closest(".wpforms-field-option-group-inner").find(".wpforms-total-summary-alert").toggleClass("wpforms-hidden")}),y.on("change",".wpforms-field-option-row-confirmation input",function(){var e=v(this).closest(".wpforms-field-option-row").data("field-id");v("#wpforms-field-"+e).find(".wpforms-confirm").toggleClass("wpforms-confirm-enabled wpforms-confirm-disabled"),v("#wpforms-field-option-"+e).toggleClass("wpforms-confirm-enabled wpforms-confirm-disabled")}),y.on("change",".wpforms-field-option-row-filter_type select",function(){var e=v(this).parent().data("field-id"),e=v("#wpforms-field-option-"+e);v(this).val()?(e.removeClass("wpforms-filter-allowlist"),e.removeClass("wpforms-filter-denylist"),e.addClass("wpforms-filter-"+v(this).val())):(e.removeClass("wpforms-filter-allowlist"),e.removeClass("wpforms-filter-denylist"))}),y.on("focusout",".wpforms-field-option-row-allowlist textarea,.wpforms-field-option-row-denylist textarea",function(){let o=v(this),e="allow";var i,t;o.next(".wpforms-alert").remove(),""!==o.val()&&(i=v(".wpforms-field-option-row-allowlist textarea"),t=v(".wpforms-field-option-row-denylist textarea"),o.is(t)&&(e="deny"),v.get(wpforms_builder.ajax_url,{nonce:wpforms_builder.nonce,content:JSON.stringify({allow:i.val(),deny:t.val(),current:e}),action:"wpforms_sanitize_restricted_rules"},function(e){var i;e.success&&(o.val(e.data.currentField),0!==(i=e.data.intersect).length&&(i="

        "+wpforms_builder.allow_deny_lists_intersect+'

        '+i+"

        ",v.alert({title:wpforms_builder.heads_up,content:i,icon:"fa fa-exclamation-circle",type:"red",buttons:{confirm:{text:wpforms_builder.ok,btnClass:"btn-confirm",keys:["enter"]}}})),e.data.restricted||0)&&o.after('

        '+wpforms_builder.restricted_rules+"

        ")}))}),y.on("focusout",C.defaultEmailSelector,function(){C.$focusOutTarget=v(this),k.focusOutEvent()}),y.on("change",".wpforms-field-option-row-size select",function(){var e=v(this),i=e.val(),e=e.parent().data("field-id");v("#wpforms-field-"+e).removeClass("size-small size-medium size-large").addClass("size-"+i)}),y.on("input",".wpforms-field-option-row-placeholder input",function(){var e=v(this),i=e.parent().data("field-id"),o=v("#wpforms-field-"+i),t=o.find(".primary-input");let r=wpf.sanitizeHTML(e.val());"payment-single"===o.data("field-type")&&""===r&&(r=v("#wpforms-field-option-"+i+"-price").prop("placeholder")),t.is("select")?k.dropdownField.helpers.isModernSelect(t)?(e=k.dropdownField.helpers.getInstance(t),t.prop("multiple")?v(e.input.element).prop("placeholder",r):(e.setChoiceByValue(""),t.closest(".choices").find(".choices__inner .choices__placeholder").text(r),o=v("#wpforms-field-option-"+i+"-dynamic_choices").val(),k.dropdownField.helpers.update(i,o))):(e=t.find(".placeholder"),!r.length&&e.length?e.remove():(e.length?e.text(r):t.prepend('"),t.find(".placeholder").prop("selected",!t.prop("multiple")))):t.prop("placeholder",r)}),y.on("input",".wpforms-field-option-row-confirmation_placeholder input",function(){var e=v(this),i=e.val(),e=e.parent().data("field-id");v("#wpforms-field-"+e).find(".secondary-input").attr("placeholder",i)}),y.on("input",".wpforms-field-option .format-selected input.placeholder",function(){var e=v(this),i=e.val(),e=e.closest(".wpforms-field-option-row"),o=e.data("field-id"),e=e.data("subfield");v("#wpforms-field-"+o).find(".wpforms-"+e+" input").attr("placeholder",i)}),y.on("input",".wpforms-field-option-address input.placeholder",function(){var e=v(this),i=e.closest(".wpforms-field-option-row"),o=i.data("field-id"),t=i.data("subfield"),r=v("#wpforms-field-"+o+" .wpforms-"+t).find("input, select"),i=i.find("#wpforms-field-option-"+o+"-"+t+"_default");let s=i.val(),l=i.find("option:selected").text(),a=e.val();r.each(function(){var e,i,o=v(this);o.is("select")?(e=o.find(".placeholder"),i=""===s&&""!==a?a:l,e.text(i)):o.attr("placeholder",a)})}),y.on("input",'.wpforms-field-option-row-default_value input:not([type="search"])',function(){var e=v(this),i=wpf.sanitizeHTML(e.val()),e=e.closest(".wpforms-field-option-row").data("field-id");v("#wpforms-field-"+e+" .primary-input").val(i)}),y.on("input",".wpforms-field-options-column input.default",function(){var e=v(this),i=wpf.sanitizeHTML(e.val()),e=e.closest(".wpforms-field-option-row"),o=e.data("field-id"),e=e.data("subfield");v("#wpforms-field-"+o+" .wpforms-"+e+" input").val(i)}),y.on("change",".wpforms-field-option-address select.default",function(){var e=v(this),i=e.val(),o=e.find("option:selected").text(),e=e.closest(".wpforms-field-option-row"),t=e.data("field-id"),r=e.data("subfield"),s=v("#wpforms-field-option-"+t+"-scheme").val(),e=e.find("#wpforms-field-option-"+t+"-"+r+"_placeholder").val(),t=v("#wpforms-field-"+t+" .wpforms-address-scheme-"+s+" .wpforms-"+r+" .placeholder");""===i&&0parseInt(i.val(),10))}),y.on("change",".wpforms-field-option-row-format select",function(){var e,i,o,t,r,s=v(this),l=s.val(),s=s.parent().data("field-id"),a=v("#wpforms-field-option-row-"+s+"-sublabel_hide"),n=v("#wpforms-field-"+s);n.find(".format-selected").removeClass().addClass("format-selected format-selected-"+l),v("#wpforms-field-option-"+s).find(".format-selected").removeClass().addClass("format-selected format-selected-"+l),["date-time","first-last","first-middle-last"].includes(l)?a.removeClass("wpforms-hidden"):a.addClass("wpforms-hidden"),v(`#wpforms-field-option-row-${s}-price_label`).toggleClass("wpforms-hidden","single"!==l),["single","user","hidden"].includes(l)&&(a="user"===l,e="single"===l,l="hidden"===l,i=v("#wpforms-field-option-"+s+"-enable_quantity").is(":checked"),t=v("#wpforms-field-option-"+s+"-min_price"),t=(o=wpf.amountSanitize(t.val()))>=t.data("minimum-price"),r=v("#wpforms-field-option-row-"+s+"-min_price"),v("#wpforms-field-option-row-"+s+"-placeholder").toggleClass("wpforms-hidden",!a),v("#wpforms-field-option-row-"+s+"-enable_quantity").toggleClass("wpforms-hidden",!e),v("#wpforms-field-option-row-"+s+"-quantities_alert").toggleClass("wpforms-hidden",!e),v("#wpforms-field-option-row-"+s+"-quantity").toggleClass("wpforms-hidden",!e||!i),n.find(".quantity-input").toggleClass("wpforms-hidden",!e||!i),r.toggleClass("wpforms-hidden",!a),r.find(".wpforms-item-minimum-price-alert").toggleClass("wpforms-hidden",t),n.find(".item-min-price").toggleClass("wpforms-hidden",a&&o<=0),n.toggleClass("min-price-warning",!t),n.find(".fa-exclamation-triangle").toggleClass("wpforms-hidden",t),v(`#wpforms-field-${s} .item-price-single`).toggleClass("wpforms-hidden",!e),v(`#wpforms-field-${s} .item-price-hidden`).toggleClass("wpforms-hidden",!l))}),y.on("change",".wpforms-field-option-row-scheme select",function(){var e=v(this),i=e.val(),e=e.parent().data("field-id"),o=v("#wpforms-field-"+e),t=v(`#wpforms-field-option-row-${e}-state`),e=v(`#wpforms-field-option-row-${e}-country`),o=(o.find(".wpforms-address-scheme").addClass("wpforms-hide"),o.find(".wpforms-address-scheme-"+i).removeClass("wpforms-hide"),o.find(`.wpforms-address-scheme-${i} .wpforms-country select, .wpforms-address-scheme-${i} .wpforms-country input`)),o=(0===o.length?e.addClass("wpforms-hidden"):e.removeClass("wpforms-hidden"),t.find(".default .default").not(".wpforms-hidden-strict")),t=t.find(`.default [data-scheme="${i}"]`),r=e.find(".default .default").not(".wpforms-hidden-strict"),e=e.find(`.default [data-scheme="${i}"]`);t.attr({id:o.attr("id"),name:o.attr("name")}).removeClass("wpforms-hidden-strict"),o.attr({id:"",name:""}).addClass("wpforms-hidden-strict"),e.attr({id:r.attr("id"),name:r.attr("name")}).removeClass("wpforms-hidden-strict"),r.attr({id:"",name:""}).addClass("wpforms-hidden-strict")}),y.on("change",".wpforms-field-option-row-date .type select",function(){var e=v(this),i=e.val(),o=v(this).closest(".wpforms-field-option-row").data("field-id"),t="datepicker"===i?"wpforms-date-type-datepicker":"wpforms-date-type-dropdown",r="datepicker"===i?"wpforms-date-type-dropdown":"wpforms-date-type-datepicker",t=(v("#wpforms-field-"+o).find(".wpforms-date").addClass(t).removeClass(r),v("#wpforms-field-option-"+o).addClass(t).removeClass(r),e.closest(".wpforms-field-option-group-advanced").find(".wpforms-field-option-row-date_limit_days, .wpforms-field-option-row-date_limit_days_options, .wpforms-field-option-row-date_disable_past_dates")),r=v("#wpforms-field-option-row-"+o+"-date_limit_days_options");"dropdown"===i?((e=v("#wpforms-field-option-"+o+"-date_format")).find("option:selected").hasClass("datepicker-only")&&e.prop("selectedIndex",0).trigger("change"),t.hide()):(t.show(),v("#wpforms-field-option-"+o+"-date_limit_days").is(":checked")?r.show():r.hide())}),y.on("change",".wpforms-field-option-row-date .format select",function(){var e=v(this).val(),i=v(this).closest(".wpforms-field-option-row").data("field-id"),i=v("#wpforms-field-"+i);"m/d/Y"===e||"m.d.Y"===e?(i.find(".wpforms-date-dropdown .first option").text(wpforms_builder.date_select_month),i.find(".wpforms-date-dropdown .second option").text(wpforms_builder.date_select_day),i.find(".wpforms-date-dropdown .third option").text(wpforms_builder.date_select_year)):"d/m/Y"===e||"d.m.Y"===e?(i.find(".wpforms-date-dropdown .first option").text(wpforms_builder.date_select_day),i.find(".wpforms-date-dropdown .second option").text(wpforms_builder.date_select_month),i.find(".wpforms-date-dropdown .third option").text(wpforms_builder.date_select_year)):"Y/m/d"!==e&&"Y.m.d"!==e||(i.find(".wpforms-date-dropdown .first option").text(wpforms_builder.date_select_year),i.find(".wpforms-date-dropdown .second option").text(wpforms_builder.date_select_month),i.find(".wpforms-date-dropdown .third option").text(wpforms_builder.date_select_day))}),y.on("change",".wpforms-field-option-row-time .format select",function(){let e=v(this),r=e.closest(".wpforms-field-option-row").data("field-id"),s="",i,l=e.val().match(/[gh]/)?12:24,o=12==l?1:0,t=12==l?13:24;for(let e=o;e{hh}'.replace(/{hh}/g,i);_.forEach(["start","end"],function(e){var i=y.find("#wpforms-field-option-"+r+"-time_limit_hours_"+e+"_hour"),e=y.find("#wpforms-field-option-"+r+"-time_limit_hours_"+e+"_ampm");let o=parseInt(i.val(),10),t=e.val();o=(o=24==l?"pm"===t?o+12:o:(t=12=e.data("minimum-price"),e=e.parent(),r=v("#wpforms-field-"+e.data("field-id"));e.find(".wpforms-item-minimum-price-alert").toggleClass("wpforms-hidden",o),r.find(".item-min-price").toggleClass("wpforms-hidden",t),r.toggleClass("min-price-warning",!o),r.find(".fa-exclamation-triangle").toggleClass("wpforms-hidden",o),t||r.find(".min-price").text(wpf.amountFormatCurrency(i))}),y.on("input",".wpforms-single-item-price-label-display",function(){var e=v(this),i=wpf.sanitizeHTML(e.val(),"<>"),o=e.parent().data("field-id"),t=v("#wpforms-field-"+o),o=wpf.amountFormatCurrency(v(`#wpforms-field-option-${o}-price`).val());i?t.find(".price-label").html(i.replaceAll("{price}",` ${o} `)):(e.val("{price}"),t.find(".price-label").html(` ${o} `))}),y.on("change",".wpforms-field-option-credit-card .payment-icons input",function(){var e=v(this),i=e.data("card"),e=e.parent().data("field-id");v("#wpforms-field-"+e).find("img.icon-"+i).toggleClass("card_hide")}),y.on("input",".wpforms-field-option input.placeholder-update",function(){var e=v(this),i=e.val(),o=e.data("field-id"),e=e.data("subfield");v("#wpforms-field-"+o).find(".wpforms-"+e+" input").attr("placeholder",i)}),y.on("change",".wpforms-field-option-row-input_columns select",function(){var e=v(this),i=e.val(),e=e.parent().data("field-id");let o="";"2"===i?o="wpforms-list-2-columns":"3"===i?o="wpforms-list-3-columns":"inline"===i&&(o="wpforms-list-inline"),v("#wpforms-field-"+e).removeClass("wpforms-list-2-columns wpforms-list-3-columns wpforms-list-inline").addClass(o)}),y.on("change",".wpforms-field-option-row .wpforms-toggle-control input",function(){var e=v(this),i=e.closest(".wpforms-toggle-control").find(".wpforms-toggle-control-status"),e=e.is(":checked")?"on":"off";i.html(i.data(e))}),y.on("change",".wpforms-field-option-row-dynamic_choices select",function(){k.fieldDynamicChoiceToggle(v(this))}),y.on("change",".wpforms-field-option-row-dynamic_taxonomy select, .wpforms-field-option-row-dynamic_post_type select",function(){k.fieldDynamicChoiceSource(v(this))}),y.on("click",".toggle-layout-selector-display",function(e){e.preventDefault(),k.fieldLayoutSelectorToggle(this)}),y.on("click",".layout-selector-display-layout",function(e){e.preventDefault(),k.fieldLayoutSelectorLayout(this)}),y.on("click",".layout-selector-display-columns span",function(e){e.preventDefault(),k.fieldLayoutSelectorInsert(this)}),v(r).on("change",".wpforms-field-option-row-scale select",function(){let e=v(this),i=e.val(),o=e.parent().data("field-id"),t=v("#wpforms-field-"+o+" .rating-icon"),r=1;t.each(function(){r<=i?v(this).show():v(this).hide(),r++})}),v(r).on("change",".wpforms-field-option-row-icon select",function(){var e=v(this),i=e.val(),e=e.parent().data("field-id"),e=v("#wpforms-field-"+e+" .rating-icon");let o="fa-star";"heart"===i?o="fa-heart":"thumb"===i?o="fa-thumbs-up":"smiley"===i&&(o="fa-smile-o"),e.removeClass("fa-star fa-heart fa-thumbs-up fa-smile-o").addClass(o)}),v(r).on("change",".wpforms-field-option-row-icon_size select",function(){var e=v(this),i=e.val(),e=e.parent().data("field-id"),e=v("#wpforms-field-"+e+" .rating-icon");let o="28";"small"===i?o="18":"large"===i&&(o="38"),e.css("font-size",o+"px")}),v(r).on("input",".wpforms-field-option-row-icon_color input.wpforms-color-picker",function(){var e=v(this),i=e.closest(".wpforms-field-option-row").data("field-id");v(`#wpforms-field-${i} .wpforms-rating-field-icons i.fa`).css("color",k.getValidColorPickerValue(e))}),v(r).on("change",".wpforms-field-option-row-disclaimer_format input",function(){var e=v(this).closest(".wpforms-field-option-row").data("field-id");v("#wpforms-field-"+e+" .description").toggleClass("disclaimer")}),y.on("change",".wpforms-field-option-row-limit_enabled input",function(e){k.updateTextFieldsLimitControls(v(e.target).closest(".wpforms-field-option-row-limit_enabled").data().fieldId,e.target.checked)}),y.on("change",".wpforms-field-option-row-date_disable_past_dates input",function(e){k.updateDisableTodaysDateControls(v(e.target).closest(".wpforms-field-option-row-date_disable_past_dates").data().fieldId,e.target?.checked)}),y.on("change",".wpforms-field-option-row-password-visibility input",k.togglePasswordEyeIcon),y.on("change",".wpforms-field-option-row-password-strength input",function(e){k.updatePasswordStrengthControls(v(e.target).parents(".wpforms-field-option-row-password-strength").data().fieldId,e.target.checked)}),y.on("change",".wpforms-field-option-richtext .wpforms-field-option-row-media_enabled input",k.updateRichTextMediaFieldsLimitControls),y.on("change",".wpforms-field-option-richtext .wpforms-field-option-row-style select",k.updateRichTextStylePreview),y.on("change",".wpforms-field-option-file-upload .wpforms-field-option-row-style select, .wpforms-field-option-file-upload .wpforms-field-option-row-max_file_number input, .wpforms-field-option-file-upload .wpforms-field-option-row-camera input",function(e){k.fieldFileUploadPreviewUpdate(e.target)}),k.numberSliderEvents(y),k.fieldDynamicChoiceToggleImageChoices(),k.fieldDynamicChoiceToggleIconChoices(),y.on("change",".wpforms-field-option-row-show_price_after_labels input",function(){var e=v(this).closest(".wpforms-field-option-group-basic").find(".wpforms-field-option-row-choices .choices-list");k.fieldChoiceUpdate(e.data("field-type"),e.data("field-id"))}),y.on("input",".wpforms-field-option-row-preview-notice textarea",k.updatePreviewNotice).on("change",".wpforms-field-option-row-preview-notice-enable input",k.toggleEntryPreviewNotice).on("wpformsFieldAdd",k.maybeLockEntryPreviewGroupOnAdd).on("wpformsFieldMove",k.maybeLockEntryPreviewGroupOnMove).on("click",".wpforms-entry-preview-block",k.entryPreviewBlockField),k.defaultStateEntryPreviewNotice()},fieldReadOnlyToggleChange(){var e=v(this),i=Number(e.closest(".wpforms-field-option-row").data("field-id")),e=e.is(":checked"),o=v(`#wpforms-field-option-row-${i}-required, #wpforms-field-option-row-${i}-unique_answer`),t=o.filter(".wpforms-field-option-row-required").find("input");k.fieldReadOnlyToggleDependentToggles(o,e),v("#wpforms-field-"+i).toggleClass("readonly",e).toggleClass("required",t.is(":checked"))},fieldReadOnlyToggleDependentToggles(e,s=!0){e.each(function(){var e=v(this),i=e.find(":input"),o=s?i.is(":checked"):null,t=!s&&i.data("enabled-state-checked"),r=s?wp.i18n.__("Disabled because this field is set to Read-Only in the Advanced tab.","wpforms"):"";e.toggleClass("wpforms-disabled",s).find(".wpforms-toggle-control").attr("title",r),i.data("enabled-state-checked",o).prop("checked",t).prop("disabled",s)})},focusOutEvent(){if(null!==C.$focusOutTarget){if(C.$defaultEmail.is(C.$focusOutTarget)){let i=C.$focusOutTarget;if(i.next(".wpforms-alert").remove(),""===i.val())return;v.get(wpforms_builder.ajax_url,{nonce:wpforms_builder.nonce,content:i.val(),action:"wpforms_sanitize_default_email"},function(e){e.success&&(i.val(e.data),i.trigger("input"),e.data||i.after('

        '+wpforms_builder.restricted_default_email+"

        "))})}C.$focusOutTarget=null}},isFieldPreviewActionsDisabled(e){return k.isFormPreviewActionsDisabled(e)||v(e).closest(".wpforms-field").hasClass("ui-sortable-disabled")},isFormPreviewActionsDisabled(e){return v(e).closest(".wpforms-field-wrap").hasClass("ui-sortable-disabled")},fieldGroupToggle(e,i){e=v(e);let o=e.next(".wpforms-add-fields-buttons"),t=o.parent(),r=e.find("i"),s=e.data("group"),l="wpforms_field_group_"+s;"click"===i?(t.hasClass("wpforms-closed")?wpCookies.remove(l):wpCookies.set(l,"true",2592e3),r.toggleClass("wpforms-angle-right"),o.stop().slideToggle("",function(){t.toggleClass("wpforms-closed")})):"load"===i&&(o=e.find(".wpforms-add-fields-buttons"),r=e.find(".wpforms-add-fields-heading i"),s=e.find(".wpforms-add-fields-heading").data("group"),"true"===wpCookies.get("wpforms_field_group_"+s))&&(r.toggleClass("wpforms-angle-right"),o.hide(),e.toggleClass("wpforms-closed"))},updateDescription(e,i){e.hasClass("nl2br")&&(i=i.replace(/\n/g,"
        ")),e.html(i)},defaultStateEntryPreviewNotice(){v(".wpforms-field-option-row-preview-notice-enable input").each(function(){v(this).trigger("change")})},updatePreviewNotice(){var e=v(this),i=wpf.sanitizeHTML(e.val()).trim(),e=e.parent().data("field-id"),e=v("#wpforms-field-"+e).find(".wpforms-entry-preview-notice"),i=i||wpforms_builder.entry_preview_default_notice;k.updateDescription(e,i)},toggleEntryPreviewNotice(){var e=v(this),i=e.closest(".wpforms-field-option").data("field-id"),o=v("#wpforms-field-"+i),i=v("#wpforms-field-option-"+i+" .wpforms-field-option-row-preview-notice"),t=o.find(".wpforms-entry-preview-notice"),o=o.find(".wpforms-alert-info");(e.is(":checked")?(o.hide(),t.show(),i):(i.hide(),t.hide(),o)).show()},fieldDelete(e){var i=v("#wpforms-field-"+e),o=i.data("field-type");"pagebreak"===o&&i.hasClass("wpforms-field-entry-preview-not-deleted")?k.youCantRemovePageBreakFieldPopup():i.hasClass("no-delete")?k.youCantRemoveFieldPopup():k.confirmFieldDeletion(e,o)},youCantRemovePageBreakFieldPopup(){v.alert({title:wpforms_builder.heads_up,content:wpforms_builder.entry_preview_require_page_break,icon:"fa fa-exclamation-circle",type:"red",buttons:{confirm:{text:wpforms_builder.ok,btnClass:"btn-confirm",keys:["enter"]}}})},youCantReorderFieldPopup(){console.warn('WARNING! Function "WPFormsBuilder.youCantReorderFieldPopup()" has been deprecated, please use the new "WPForms.Admin.Builder.DragFields.youCantReorderFieldPopup()" function instead!'),WPForms.Admin.Builder.DragFields.youCantReorderFieldPopup()},youCantRemoveFieldPopup(){v.alert({title:wpforms_builder.field_locked,content:wpforms_builder.field_locked_no_delete_msg,icon:"fa fa-info-circle",type:"blue",buttons:{confirm:{text:wpforms_builder.close,btnClass:"btn-confirm",keys:["enter"]}}})},validationErrorNotificationPopup(e){console.warn('WARNING! Function "WPFormsBuilder.validationErrorNotificationPopup()" has been deprecated.'),v.alert({title:wpforms_builder.heads_up,content:e,icon:"fa fa-exclamation-circle",type:"red",buttons:{confirm:{text:wpforms_builder.close,btnClass:"btn-confirm",keys:["enter"]}}})},confirmFieldDeletion(e,i){var o={id:e,message:wpforms_builder.delete_confirm};WPFormsUtils.triggerEvent(y,"wpformsBeforeFieldDeleteAlert",[o,i]).isDefaultPrevented()||v.confirm({title:!1,content:o.message,icon:"fa fa-exclamation-circle",type:"orange",buttons:{confirm:{text:wpforms_builder.ok,btnClass:"btn-confirm",keys:["enter"],action(){k.fieldDeleteById(e)}},cancel:{text:wpforms_builder.cancel}}})},fieldDeleteById(t,r="",e=400){v("#wpforms-field-"+t).fadeOut(e,function(){var e=v(this),i=e.parents(".wpforms-field-layout-columns"),e=(r=e.data("field-type"),y.trigger("wpformsBeforeFieldDelete",[t,r]),e.remove(),v("#wpforms-field-option-"+t).remove(),v(".wpforms-field, .wpforms-title-desc").removeClass("active"),k.fieldTabToggle("add-fields"),v(".wpforms-field-option")),o=y.find(".wpforms-field-submit");e.length<1&&(C.$sortableFieldsWrap.append(C.$noFieldsPreview.clone()),C.$fieldOptions.append(C.$noFieldsOptions.clone()),o.hide()),e.filter(":not(.wpforms-field-option-layout)").length||o.hide(),y.trigger("wpformsFieldDelete",[t,r,i])})},determineActiveSections(){let t=wpf.getQueryString("section");v(".wpforms-panel").each(function(){var e,i=v(this),o=(e=i,(!(o=t)||!e.hasClass("active")||0===(e=e.find(`.wpforms-panel-sidebar-section[data-section="${o}"]`)).length||e.hasClass("wpforms-panel-sidebar-section-no-access")?null:e)||(e=>{e=e.find(".wpforms-panel-sidebar-section.configured").first();return e.length?e:null})(i)||i.find(".wpforms-panel-sidebar-section:first-of-type"));e=i,(i=o)&&(o=i.data("section"),i.addClass("active"),(i=e.find(".wpforms-panel-content-section-"+o)).length?(i.show().addClass("active"),e.find(".wpforms-panel-content-section-default").toggle("default"===o)):e.find(".wpforms-panel-content-section-default").show().addClass("active"),WPFormsUtils.triggerEvent(y,"wpformsPanelSectionSwitch",o))})},loadEntryPreviewFields(){var e=v("#wpforms-panel-fields .wpforms-field-wrap .wpforms-field-entry-preview");e.length&&e.each(function(){k.lockEntryPreviewFieldsPosition(v(this).data("field-id"))})},fieldEntryPreviewDelete(e,i,o){"entry-preview"===o&&(i=(o=v("#wpforms-field-"+i)).prevAll(".wpforms-field-pagebreak").first(),o=o.nextAll(".wpforms-field-pagebreak").first().data("field-id"),o=v("#wpforms-field-option-"+o),i.removeClass("wpforms-field-not-draggable wpforms-field-entry-preview-not-deleted"),o.find(".wpforms-entry-preview-block").removeClass("wpforms-entry-preview-block"),y.trigger("wpformsFieldDragToggle",[i.data("field-id"),i.data("field-type")]))},maybeLockEntryPreviewGroupOnMove(e,i){i.item.hasClass("wpforms-field-pagebreak")&&k.maybeLockEntryPreviewGroupOnAdd(e,i.item.data("field-id"),"pagebreak")},maybeLockEntryPreviewGroupOnAdd(e,i,o){var t,r,s,l,a;"pagebreak"===o&&(r=(t=v("#wpforms-field-"+i)).prevAll(".wpforms-field-entry-preview,.wpforms-field-pagebreak").first(),a=t.nextAll(".wpforms-field-entry-preview,.wpforms-field-pagebreak").first(),r.hasClass("wpforms-field-entry-preview")||a.hasClass("wpforms-field-entry-preview"))&&(s=(l=v("#wpforms-field-option-"+i+" .wpforms-field-option-row-prev_toggle")).find("input"),a=v("#wpforms-field-option-"+a.data("field-id")+" .wpforms-field-option-row-prev_toggle"),r.hasClass("wpforms-field-entry-preview")?(s.attr("checked","checked").trigger("change"),l.addClass("wpforms-entry-preview-block"),a.removeClass("wpforms-entry-preview-block")):(s=r.data("field-id"),a=(l=v("#wpforms-field-option-"+s+" .wpforms-field-option-row-prev_toggle")).find("input"),t.addClass("wpforms-field-not-draggable wpforms-field-entry-preview-not-deleted"),y.trigger("wpformsFieldDragToggle",[i,o]),r.removeClass("wpforms-field-not-draggable wpforms-field-entry-preview-not-deleted"),y.trigger("wpformsFieldDragToggle",[s,r.data("field-type")]),r.prevAll(".wpforms-field-entry-preview,.wpforms-field-pagebreak").first().hasClass("wpforms-field-entry-preview")&&(a.attr("checked","checked").trigger("change"),l.addClass("wpforms-entry-preview-block"))))},entryPreviewBlockField(e){e.preventDefault(),v.alert({title:wpforms_builder.heads_up,content:wpforms_builder.entry_preview_require_previous_button,icon:"fa fa-exclamation-circle",type:"red",buttons:{confirm:{text:wpforms_builder.ok,btnClass:"btn-confirm",keys:["enter"]}}})},isUncheckedEntryPreviewField(e,i){return!("entry-preview"!==e||i&&i.passed)},addEntryPreviewField(e,i){var o,t,r,s=v("#wpforms-add-fields-entry-preview");s.hasClass("wpforms-entry-preview-adding")||(r=v("#wpforms-panel-fields .wpforms-field-wrap > .wpforms-field"),o=i?.position?i.position:r.length,t=k.isEntryPreviewFieldRequiresPageBreakBefore(r,o),r=k.isEntryPreviewFieldRequiresPageBreakAfter(r,o),s.addClass("wpforms-entry-preview-adding"),(i=i||{}).passed=!0,t||r?t?k.addPageBreakAndEntryPreviewFields(i,o):k.addEntryPreviewAndPageBreakFields(i,o):k.fieldAdd("entry-preview",i).done(function(e){k.lockEntryPreviewFieldsPosition(e.data.field.id)}))},addEntryPreviewFieldAfterPageBreak(e){let i=setInterval(function(){2===v("#wpforms-panel-fields .wpforms-field-wrap").find(".wpforms-pagebreak-bottom, .wpforms-pagebreak-top").length&&(k.fieldAdd("entry-preview",e).done(function(e){k.lockEntryPreviewFieldsPosition(e.data.field.id)}),clearInterval(i))},100)},addPageBreakAndEntryPreviewFields(i,o){let t=3<=v("#wpforms-panel-fields .wpforms-field-wrap > .wpforms-field-pagebreak").length;k.fieldAdd("pagebreak",{position:o}).done(function(e){i.position=t?o+1:o+2,k.addEntryPreviewFieldAfterPageBreak(i);e=v("#wpforms-field-option-"+e.data.field.id).find(".wpforms-field-option-row-prev_toggle");e.find("input").attr("checked","checked").trigger("change"),e.addClass("wpforms-entry-preview-block")})},fieldDuplicate(o){let t=v("#wpforms-field-"+o);t.hasClass("no-duplicate")?v.alert({title:wpforms_builder.field_locked,content:wpforms_builder.field_locked_no_duplicate_msg,icon:"fa fa-info-circle",type:"blue",buttons:{confirm:{text:wpforms_builder.close,btnClass:"btn-confirm",keys:["enter"]}}}):v.confirm({title:!1,content:wpforms_builder.duplicate_confirm,icon:"fa fa-exclamation-circle",type:"orange",buttons:{confirm:{text:wpforms_builder.ok,btnClass:"btn-confirm",keys:["enter"],action(){var e,i;this.$$confirm.prop("disabled",!0),WPFormsUtils.triggerEvent(y,"wpformsBeforeFieldDuplicate",[o,t]).isDefaultPrevented()||(e=k.fieldDuplicateRoutine(o,!0),i=v("#wpforms-field-"+e),k.increaseNextFieldIdAjaxRequest(),WPFormsUtils.triggerEvent(y,"wpformsFieldDuplicated",[o,t,e,i]))}},cancel:{text:wpforms_builder.cancel}}})},increaseNextFieldIdAjaxRequest(){v.post(wpforms_builder.ajax_url,{form_id:m.formID,field_id:C.$nextFieldId.val(),nonce:wpforms_builder.nonce,action:"wpforms_builder_increase_next_field_id"})},fieldDuplicateRoutine(e,i=!0){var o=v("#wpforms-field-"+e),t=v("#wpforms-field-option-"+e),r=C.$sortableFieldsWrap.find(">.active"),s=C.$fieldOptions.find(">:visible"),l=s.find(">.active"),a=o.data("field-type"),n=t.attr("class"),d=k.dropdownField.helpers.isModernSelect(o.find("> .choices .primary-input"));wpf.restoreTooltips(t),d&&k.dropdownField.helpers.convertModernToClassic(e);let p=t.html(),f=o.clone(),c=parseInt(C.$nextFieldId.val(),10),m=v(`#wpforms-field-option-${e}-label`),w=(m.length?m:v(`#wpforms-field-option-${e}-name`)).val(),u=c+1,h={};var g=""!==w?w+" "+wpforms_builder.duplicate_copy:wpforms_builder.field+` #${e} `+wpforms_builder.duplicate_copy;h.fieldOptionsID=new RegExp("ID #"+e,"g"),h.fieldID=new RegExp("fields\\["+e+"\\]","g"),h.dataFieldID=new RegExp('data-field-id="'+e+'"',"g"),h.referenceID=new RegExp('data-reference="'+e+'"',"g"),h.elementID=new RegExp('\\b(id|for)="wpforms-(.*?)'+e+'(.*?)"',"ig"),o.after(f),r.removeClass("active"),f.addClass("active").attr({id:"wpforms-field-"+c,"data-field-id":c}),h.elementIdReplace=function(e,i,o,t){return`${i}="wpforms-${o}${c}${t}"`},p=(p=(p=(p=(p=p.replace(h.fieldOptionsID,"ID #"+c)).replace(h.fieldID,`fields[${c}]`)).replace(h.dataFieldID,`data-field-id="${c}"`)).replace(h.referenceID,`data-reference="${c}"`)).replace(h.elementID,h.elementIdReplace),s.hide(),t.after(`
        ${p}
        `);let b=v("#wpforms-field-option-"+c);r.data("field-id")===e&&l.length&&(o=l.attr("class").match(/wpforms-field-option-group-\S*/i)[0],s=b.find(">."+o),b.find(">").removeClass("active"),s.addClass("active")),r.data("field-id")!==e&&l.length&&(b.find(">").removeClass("active"),b.find(">.wpforms-field-option-group-basic").addClass("active")),t.find(":input").each(function(){var e=v(this),i=e.attr("name");if(!i)return"continue";var i=i.replace(h.fieldID,`fields[${c}]`),o=e.attr("type");"checkbox"===o||"radio"===o?e.is(":checked")?b.find(`[name="${i}"]`).prop("checked",!0).attr("checked","checked"):b.find(`[name="${i}"]`).prop("checked",!1).attr("checked",!1):e.is("select")?e.find("option:selected").length&&(o=e.find("option:selected").val(),b.find(`[name="${i}"]`).find(`[value="${o}"]`).prop("selected",!0)):""===(o=e.val())&&e.hasClass("wpforms-money-input")?b.find(`[name="${i}"]`).val(wpf.numberFormat("0",wpforms_builder.currency_decimals,wpforms_builder.currency_decimal,wpforms_builder.currency_thousands)):b.find(`[name="${i}"]`).val(o)}),b.find(".wpforms-field-option-hidden-id").val(c),C.$nextFieldId.val(u);n=v("html"===a?`#wpforms-field-option-${c}-name`:`#wpforms-field-option-${c}-label`);return i&&n.val(g).trigger("input"),y.trigger("wpformsFieldAdd",[c,a]),wpf.initTooltips(),d&&(k.dropdownField.helpers.convertClassicToModern(e),k.dropdownField.helpers.convertClassicToModern(c)),k.fieldChoiceUpdate(f.data("field-type"),c),k.loadColorPickers(),c},addEntryPreviewAndPageBreakFields(e,o){k.fieldAdd("entry-preview",e).done(function(e){let i=e.data.field.id;k.fieldAdd("pagebreak",{position:o+1}).done(function(e){k.lockEntryPreviewFieldsPosition(i);e=v("#wpforms-field-"+e.data.field.id).nextAll(".wpforms-field-pagebreak, .wpforms-field-entry-preview").first();e.hasClass("wpforms-field-entry-preview")&&k.lockEntryPreviewFieldsPosition(e.data("field-id"))})})},lockEntryPreviewFieldsPosition(e){var i=v("#wpforms-field-"+e),o=i.prevAll(".wpforms-field-pagebreak:not(.wpforms-pagebreak-bottom)").first(),t=i.nextAll(".wpforms-field-pagebreak").first().data("field-id"),t=v("#wpforms-field-option-"+t).find(".wpforms-field-option-row-prev_toggle"),r=t.find("input");i.addClass("wpforms-field-not-draggable"),o.addClass("wpforms-field-not-draggable wpforms-field-entry-preview-not-deleted"),r.prop("checked","checked").trigger("change"),t.addClass("wpforms-entry-preview-block"),v("#wpforms-add-fields-entry-preview").removeClass("wpforms-entry-preview-adding"),y.trigger("wpformsFieldDragToggle",[e,i.data("field-type")]),y.trigger("wpformsFieldDragToggle",[o.data("field-id"),o.data("field-type")])},isEntryPreviewFieldRequiresPageBreakBefore(e,i){e=e.slice(0,i).filter(".wpforms-field-pagebreak,.wpforms-field-entry-preview");let o=!0;return e.length&&v(e.get().reverse()).each(function(){var e=v(this);return!e.hasClass("wpforms-field-entry-preview")&&(e.hasClass("wpforms-field-pagebreak")&&!e.hasClass("wpforms-field-stick")?o=!1:void 0)}),o},isEntryPreviewFieldRequiresPageBreakAfter(e,i){e=e.slice(i).filter(".wpforms-field-pagebreak,.wpforms-field-entry-preview");let o=Boolean(e.length);return e.length&&e.each(function(){var e=v(this);return!e.hasClass("wpforms-field-entry-preview")&&(e.hasClass("wpforms-field-pagebreak")?o=!1:void 0)}),o},fieldAdd(s,l){var e=v("#wpforms-add-fields-"+s);if(!(e.hasClass("upgrade-modal")||e.hasClass("education-modal")||e.hasClass("warning-modal")))if(["captcha_turnstile","captcha_hcaptcha","captcha_recaptcha","captcha_none"].includes(s))k.captchaUpdate();else{if(n=!0,WPForms.Admin.Builder.DragFields.disableDragAndDrop(),k.disableFormActions(),!k.isUncheckedEntryPreviewField(s,l))return l=v.extend({},{position:"bottom",$sortable:"base",placeholder:!1,scroll:!0,defaults:!1},l),e={action:"wpforms_new_field_"+s,id:m.formID,type:s,defaults:l.defaults,nonce:wpforms_builder.nonce},v.post(wpforms_builder.ajax_url,e,function(i){if(i.success){var o=C.$sortableFieldsWrap,t=v(i.data.preview),r=v(i.data.options);let e=l.$sortable;n=!1,t.css("display","none"),l.placeholder&&l.placeholder.remove(),"default"!==l.$sortable&&l.$sortable.length||(e=o.find(".wpforms-fields-sortable-default")),"base"!==l.$sortable&&e.length||(e=o);o=WPFormsUtils.triggerEvent(y,"wpformsBeforeFieldAddToDOM",[l,t,r,e]);o.isDefaultPrevented()||(o.skipAddFieldToBaseLevel||k.fieldAddToBaseLevel(l,t,r),t.fadeIn(),y.find(".no-fields, .no-fields-preview").remove(),v(".wpforms-field-option:not(.wpforms-field-option-layout)").length&&y.find(".wpforms-field-submit").show(),l.scroll&&l.position.length&&k.scrollPreviewToField(i.data.field.id),C.$nextFieldId.val(i.data.field.id+1),wpf.initTooltips(),k.loadColorPickers(),k.toggleAllOptionGroups(),y.trigger("wpformsFieldAdd",[i.data.field.id,s]))}else wpf.debug("Add field AJAX call is unsuccessful:",i)}).fail(function(e){n=!1,wpf.debug("Add field AJAX call failed:",e.responseText)}).always(function(){n||(WPForms.Admin.Builder.DragFields.enableDragAndDrop(),k.enableFormActions())});k.addEntryPreviewField(s,l)}},fieldAddToBaseLevel(e,i,o){var t,r=C.$sortableFieldsWrap,s=r.children(":not(.wpforms-field-drag-pending, .no-fields-preview)"),l=s.length,a=C.$fieldOptions;"top"===e.position?(r.prepend(i),a.prepend(o)):(t=s.last(),"bottom"!==e.position||t.length&&t.hasClass("wpforms-field-stick")?("bottom"===e.position&&(e.position=l),e.position===l&&t.length&&t.hasClass("wpforms-field-stick")?(l=t.data("field-id"),t.before(i),a.find("#wpforms-field-option-"+l).before(o)):(t=s.eq(e.position)).length?(l=t.data("field-id"),t.before(i),a.find("#wpforms-field-option-"+l).before(o)):(r.append(i),a.append(o))):(r.append(i),a.append(o)))},scrollPreviewToField(e){var e=v("#wpforms-field-"+e),i=C.$fieldsPreviewWrap.scrollTop(),o=e.closest(".wpforms-field-layout");let t=e.position().top;e=(t=o.length?o.position().top+t+20:t)>i?t-i:t+i;C.$fieldsPreviewWrap.scrollTop(e)},captchaUpdate(){var e={action:"wpforms_update_field_captcha",id:m.formID,nonce:wpforms_builder.nonce};return v.post(wpforms_builder.ajax_url,e,function(t){if(t.success){let e={title:!1,content:!1,icon:"fa fa-exclamation-circle",type:"orange",boxWidth:"450px",buttons:{confirm:{text:wpforms_builder.ok,btnClass:"btn-confirm",keys:["enter"]}}},i=v("#wpforms-panel-field-settings-recaptcha"),o=t.data.current;i.data("provider",t.data.provider),"configured_not_enabled"!==o&&"configured_enabled"!==o||(o=i.prop("checked")?"configured_enabled":"configured_not_enabled",e.buttons.confirm.action=function(){i.prop("checked","configured_not_enabled"===o).trigger("change")}),e.title=t.data.cases[o].title,e.content=t.data.cases[o].content,t.data.cases[o].cancel&&(e.buttons.cancel={text:wpforms_builder.cancel,keys:["esc"]}),v.confirm(e)}else console.log(t)}).fail(function(e){console.log(e.responseText)})},disableDragAndDrop(){console.warn('WARNING! Function "WPFormsBuilder.disableDragAndDrop()" has been deprecated, please use the new "WPForms.Admin.Builder.DragFields.disableDragAndDrop()" function instead!'),WPForms.Admin.Builder.DragFields.disableDragAndDrop()},enableDragAndDrop(){console.warn('WARNING! Function "WPFormsBuilder.enableDragAndDrop()" has been deprecated, please use the new "WPForms.Admin.Builder.DragFields.enableDragAndDrop()" function instead!'),WPForms.Admin.Builder.DragFields.enableDragAndDrop()},disableFormActions(){v.each([C.$previewButton,C.$embedButton,C.$saveButton,C.$exitButton],function(e,i){i.prop("disabled",!0).addClass("wpforms-disabled")})},enableFormActions(){v.each([C.$previewButton,C.$embedButton,C.$saveButton,C.$exitButton],function(e,i){i.prop("disabled",!1).removeClass("wpforms-disabled")})},fieldSortable(){console.warn('WARNING! Function "WPFormsBuilder.fieldSortable()" has been deprecated, please use the new "WPForms.Admin.Builder.DragFields.initSortableFields()" function instead!'),WPForms.Admin.Builder.DragFields.initSortableFields()},fieldDragDisable(e,i=!0){console.warn('WARNING! Function "WPFormsBuilder.fieldDragDisable()" has been deprecated, please use the new "WPForms.Admin.Builder.DragFields.fieldDragDisable()" function instead!'),WPForms.Admin.Builder.DragFields.fieldDragDisable(e,i)},fieldDragEnable(e){console.warn('WARNING! Function "WPFormsBuilder.fieldDragEnable()" has been deprecated, please use the new "WPForms.Admin.Builder.DragFields.fieldDragEnable()" function instead!'),WPForms.Admin.Builder.DragFields.fieldDragEnable(e)},fieldChoiceAdd(e,i){e.preventDefault();var e=v(i),i=e.parent(),o=i.find("input.default").is(":checked"),e=e.closest(".wpforms-field-option-row-choices").data("field-id");let t=i.parent().attr("data-next-id");var r=i.parent().data("field-type"),s=i.clone().insertAfter(i);s.attr("data-key",t),s.find(".wpforms-icon-select .ic-fa-preview").removeClass().addClass("ic-fa-preview ic-fa-"+wpforms_builder.icon_choices.default_icon_style+" ic-fa-"+wpforms_builder.icon_choices.default_icon),s.find(".wpforms-icon-select .ic-fa-preview + span").text(wpforms_builder.icon_choices.default_icon),s.find(".preview").empty(),s.find(".wpforms-image-upload-add").show(),s.find(".wpforms-money-input").trigger("focusout"),s.find("input, select").each(function(){var e=v(this),i=e.attr("type");e.attr("name",v(this).attr("name").replace(/\[choices]\[(\d+)]/g,`[choices][${t}]`)),"radio"===i||"checkbox"===i?e.prop("checked",!1):e.val("")}),s.find(".wpforms-icon-select input.source-icon").val(wpforms_builder.icon_choices.default_icon),s.find(".wpforms-icon-select input.source-icon-style").val(wpforms_builder.icon_choices.default_icon_style),!0===o&&i.find("input.default").prop("checked",!0),t++,i.parent().attr("data-next-id",t),y.trigger("wpformsFieldChoiceAdd",[e]),k.fieldChoiceUpdate(r,e)},fieldChoiceDelete(e,i){e.preventDefault();let o=v(i),t=o.parent().parent(),r=t.find("li").not(".wpforms-choice-other-option").length,s={id:t.data("field-id"),choiceId:o.closest("li").data("key"),message:""+wpforms_builder.delete_choice_confirm+"",trigger:!1};if(y.trigger("wpformsBeforeFieldDeleteAlert",[s]),1===r)k.fieldChoiceDeleteAlert();else{let e=function(){o.parent().remove(),k.fieldChoiceUpdate(t.data("field-type"),t.data("field-id")),y.trigger("wpformsFieldChoiceDelete",[t.data("field-id")])};s.trigger?v.confirm({title:!1,content:s.message,icon:"fa fa-exclamation-circle",type:"orange",buttons:{confirm:{text:wpforms_builder.ok,btnClass:"btn-confirm",keys:["enter"],action(){e()}},cancel:{text:wpforms_builder.cancel}}}):e()}},fieldChoiceDeleteAlert(){v.alert({title:!1,content:wpforms_builder.error_choice,icon:"fa fa-info-circle",type:"blue",buttons:{confirm:{text:wpforms_builder.ok,btnClass:"btn-confirm",keys:["enter"]}}})},fieldChoiceSortable(t,e=void 0){v(e=void 0!==e?e:".wpforms-field-option-"+t+" .wpforms-field-option-row-choices ul").one("mouseenter",function(){v(this).sortable({items:"li:not(.not-draggable)",axis:"y",delay:100,opacity:.6,handle:".move",stop(e,i){var o=i.item.parent().data("field-id");k.fieldChoiceUpdate(t,o),y.trigger("wpformsFieldChoiceMove",i)},update(){}})})},fieldChoiceLabel(e,i){var o=["payment-multiple","payment-checkbox"].includes(e.settings.type),t=e.settings.choices_icons||e.settings.choices_images,r=void 0===e.settings.choices[i].label||0===e.settings.choices[i].label.length;if(r&&!o&&t)return"";t=o?wpforms_builder.payment_choice_empty_label_tpl:wpforms_builder.choice_empty_label_tpl;let s=r?t.replace("{number}",i):wpf.sanitizeHTML(e.settings.choices[i].label,wpforms_builder.allowed_label_html_tags);return e.settings.show_price_after_labels&&(s+=" - "+wpf.amountFormatCurrency(e.settings.choices[i].value)),s},fieldChoiceUpdate:(p,t,r=-1)=>{let f=k.dropdownField.helpers.isDynamicChoices(t);if(!k.replaceChoicesWithTemplate(p,t,f)){-1===r&&(r=k.settings.choicesLimitLong),"payment-select"===p&&(p="select");let s=v("#wpforms-field-"+t+" .primary-input"),l="",e=("select"===p?f||(l='',s.find("option").not(".placeholder").remove()):"radio"!==p&&"checkbox"!==p&&"gdpr-checkbox"!==p||(p="gdpr-checkbox"===p?"checkbox":p,s.find("li").remove(),l='
      • {label}
      • '),v(`#wpforms-field-option-row-${t}-choices .choices-list`)),i=e.find("li").slice(0,r),o=!!e.find("input.default:checked").length,a=[],n=v("#wpforms-field-option-"+t+"-show_price_after_labels").prop("checked"),d=k.dropdownField.helpers.isModernSelect(s);var c;i.get().forEach(function(e){var e=v(e),i=e.find("input.value").val(),o=e.data("key");let t=wpf.sanitizeHTML(e.find("input.label").val().trim(),wpforms_builder.allowed_label_html_tags),r;if(t=""!==t?t:wpforms_builder.choice_empty_label_tpl.replace("{number}",o),t+=n&&i?" - "+wpf.amountFormatCurrency(i):"",d?a.push({value:t,label:t}):f||(r=v(l.replace(/{label}/g,t)),s.append(r)),!0===e.find("input.default").is(":checked"))switch(p){case"select":d?a[a.length-1].selected=!0:k.setClassicSelectedChoice(r);break;case"radio":case"checkbox":r.find("input").prop("checked","true")}}),d&&(r=s.prop("multiple")?"input.choices__input":".choices__inner .choices__placeholder",c=k.dropdownField.helpers.getInstance(s),f||c.removeActiveItems(),c.setChoices(a,"value","label",!0),k.dropdownField.helpers.update(t,f),s.closest(".choices").find(r).toggleClass("wpforms-hidden",o))}},replaceChoicesWithTemplate:(e,i,o)=>{if("radio"!==e&&"checkbox"!==e&&"payment-multiple"!==e&&"payment-checkbox"!==e)return!1;var t=wpf.getChoicesOrder(i),r=wp.template("wpforms-field-preview-checkbox-radio-payment-multiple");let s=wpf.getField(i),l={},a=t.slice(0,k.settings.choicesLimit),n={settings:s,order:a,type:"radio"};return s.choices_icons&&(n.settings.choices_icons_color=k.getValidColorPickerValue(v("#wpforms-field-option-"+i+"-choices_icons_color"))),a.forEach(function(e){l[e]=s.choices[e]}),s.choices=l,"checkbox"!==e&&"payment-checkbox"!==e||(n.type="checkbox"),o||v("#wpforms-field-"+i).find("ul.primary-input").replaceWith(r(n)),k.firstNChoicesAlert(i,t.length),!0},setClassicSelectedChoice(e){void 0!==e&&e.prop("selected","true")},fieldChoiceBulkAddToggle(i){var i=v(i),o=i.closest("label");if(i.hasClass("bulk-add-showing")){let e=o.next(".bulk-add-display");e.slideUp(400,function(){e.remove()}),i.find("span").text(wpforms_builder.bulk_add_show)}else{let e='
        ';for(var t in e=e+('

        '+wpforms_builder.bulk_add_heading+' '+wpforms_builder.bulk_add_presets_show+"

        ")+"")+(''))+('")+"
        ",o.after(e),o.next(".bulk-add-display").slideDown(400,function(){v(this).find("textarea").trigger("focus")}),i.find("span").text(wpforms_builder.bulk_add_hide)}i.toggleClass("bulk-add-showing")},fieldChoiceBulkAddInsert(e){var i,e=v(e),o=e.closest(".wpforms-field-option-row"),t=o.find("textarea"),r=o.find(".choices-list"),s=r.find("li:first-of-type").clone().wrap("
        ").parent(),l=o.data("field-id"),a=r.data("field-type");let n=Number(r.attr("data-next-id"));var d,p=t.val().split("\n");let f="";for(d in e.prop("disabled",!0).html(e.html()+" "+m.spinner),s.find("input.value,input.label").attr("value",""),s.find("input.default").attr("checked",!1),s.find("input.source-icon").attr("value",wpforms_builder.icon_choices.default_icon),s.find("input.source-icon-style").attr("value",wpforms_builder.icon_choices.default_icon_style),s.find(".ic-fa-preview").removeClass().addClass(`ic-fa-preview ic-fa-${wpforms_builder.icon_choices.default_icon_style} ic-fa-`+wpforms_builder.icon_choices.default_icon),s.find(".ic-fa-preview + span").text(wpforms_builder.icon_choices.default_icon),i=s.html(),p)if(p.hasOwnProperty(d)){var c=wpf.sanitizeHTML(p[d]).trim().replace(/"/g,""");let e=i;e=(e=(e=(e=e.replace(/\[choices]\[(\d+)]/g,"[choices]["+n+"]")).replace(/data-key="(\d+)"/g,'data-key="'+n+'"')).replace(/value="" class="label"/g,'value="'+c+'" class="label"')).replace(/class="label" type="text" value=""/g,'class="label" type="text" value="'+c+'"'),f+=e,n++}r.attr("data-next-id",n);t=r.find("li.wpforms-choice-other-option").first();t.length?t.before(f):r.append(f),k.fieldChoiceUpdate(a,l,n),y.trigger("wpformsFieldChoiceAdd"),k.fieldChoiceBulkAddToggle(o.find(".toggle-bulk-add-display"))},triggerBuilderEvent(e){y.trigger(e)},fieldTabToggle(e){var i;if(WPFormsUtils.triggerEvent(y,"wpformsFieldTabToggle",[e]).isDefaultPrevented())return!1;v(".wpforms-tab a").removeClass("active"),v(".wpforms-field, .wpforms-title-desc").removeClass("active"),"add-fields"===e?(C.$addFieldsTab.addClass("active"),v(".wpforms-field-options").hide(),v(".wpforms-add-fields").show()):(v("#field-options a").addClass("active"),"field-options"===e?((i=v(".wpforms-field").first()).addClass("active"),e=i.data("field-id")):v("#wpforms-field-"+e).addClass("active"),v(".wpforms-field-option").hide(),v("#wpforms-field-option-"+e).show(),v(".wpforms-add-fields").hide(),v(".wpforms-field-options").show(),y.trigger("wpformsFieldOptionTabToggle",[e]))},fieldPagebreakAdd(e,i,o){if("pagebreak"===o){let e;m.pagebreakTop?m.pagebreakBottom||(m.pagebreakBottom=!0,e={position:"bottom",scroll:!1,defaults:{position:"bottom"}},k.fieldAdd("pagebreak",e).done(function(e){m.pagebreakBottom=e.data.field.id;var i=v("#wpforms-field-"+e.data.field.id);v("#wpforms-field-option-"+e.data.field.id).find(".wpforms-field-option-group").addClass("wpforms-pagebreak-bottom"),i.addClass("wpforms-field-stick wpforms-pagebreak-bottom")})):(m.pagebreakTop=!0,e={position:"top",scroll:!1,defaults:{position:"top",nav_align:"left"}},k.fieldAdd("pagebreak",e).done(function(e){m.pagebreakTop=e.data.field.id;var i=v("#wpforms-field-"+e.data.field.id);v("#wpforms-field-option-"+e.data.field.id).find(".wpforms-field-option-group").addClass("wpforms-pagebreak-top"),i.addClass("wpforms-field-stick wpforms-pagebreak-top")}))}},fieldPagebreakDelete(e,i,o){var t,r,s;"pagebreak"!==o||v("#wpforms-panel-fields .wpforms-field-pagebreak").not(".wpforms-pagebreak-top, .wpforms-pagebreak-bottom").length||(r=(t=(o=v("#wpforms-panel-fields .wpforms-preview-wrap")).find(".wpforms-pagebreak-top")).data("field-id"),s=(o=o.find(".wpforms-pagebreak-bottom")).data("field-id"),t.remove(),v("#wpforms-field-option-"+r).remove(),m.pagebreakTop=!1,o.remove(),v("#wpforms-field-option-"+s).remove(),m.pagebreakBottom=!1)},fieldPageBreakInitDisplayPrevious(e){var i=e.data("field-id"),o=v("#wpforms-field-option-row-"+i+"-prev_toggle"),i=v("#wpforms-field-option-row-"+i+"-prev"),t=e.find(".wpforms-pagebreak-prev");0":">")+i[o].label+"",e.append(s)}else for(o in t="radio",a.hasClass("wpforms-field-checkbox")&&(t="checkbox"),e.empty(),i)s='
      • ":">")+i[o].label+"
      • ",e.append(s);r.find("ul").removeClass("wpforms-hidden"),r.find(".wpforms-alert").addClass("wpforms-hidden"),e.removeClass("wpforms-hidden")}wpf.fieldOptionLoading(i,!0)}},fieldDynamicChoiceSource(e){let i=v(e),o=i.parent(),t=i.val(),r=o.data("field-id"),s=v("#wpforms-builder-form").data("id"),l=v("#wpforms-field-option-row-"+r+"-choices"),a=v("#wpforms-field-"+r),n=v(`#wpforms-field-option-${r}-dynamic_choices option:selected`).val(),d=20;wpf.fieldOptionLoading(o);e={type:n,source:t,field_id:r,form_id:s,action:"wpforms_builder_dynamic_source",nonce:wpforms_builder.nonce};v.post(wpforms_builder.ajax_url,e,function(i){if(i.success){if(l.find(".dynamic-name").text(i.data.source_name),l.find(".dynamic-type").text(i.data.type_name),l.find("ul").addClass("wpforms-hidden"),l.find(".wpforms-alert").removeClass("wpforms-hidden"),k.fieldDynamicChoiceSourceItems(a,i.data.items),a.hasClass("wpforms-field-select")&&(d=200),a.find(".wpforms-notice-dynamic-empty").remove(),Number(i.data.total)>d){let e=wpforms_builder.dynamic_choices.limit_message;e=(e=(e=(e=e.replace("{source}",i.data.source_name)).replace("{type}",i.data.type_name)).replace("{limit}",d)).replace("{total}",i.data.total),v.alert({title:wpforms_builder.heads_up,content:e,icon:"fa fa-info-circle",type:"blue",buttons:{confirm:{text:wpforms_builder.ok,btnClass:"btn-confirm",keys:["enter"]}}})}k.firstNChoicesAlert(r,i.data.total),0===Number(i.data.total)&&k.emptyChoicesNotice(r,i.data.source_name,i.data.type)}else console.log(i);wpf.fieldOptionLoading(o,!0)}).fail(function(e){console.log(e.responseText)})},fieldDynamicChoiceSourceItems(i,o){var t=i.find(".primary-input");let r=0;if(i.hasClass("wpforms-field-select"))k.dropdownField.helpers.isModernSelect(t)?k.fieldDynamicChoiceSourceForModernSelect(t,o):k.fieldDynamicChoiceSourceForClassicSelect(t,o);else{let e="radio";for(r in i.hasClass("wpforms-field-checkbox")&&(e="checkbox"),t.empty(),o)t.append('
      • '+wpf.sanitizeHTML(o[r])+"
      • ")}},fieldDynamicChoiceSourceForModernSelect(e,i){var o=k.dropdownField.helpers.getInstance(e),t=e.closest(".wpforms-field").data().fieldId;o.destroy(),k.dropdownField.helpers.updatePlaceholderChoice(o,t),k.fieldDynamicChoiceSourceForClassicSelect(e,i),k.dropdownField.events.choicesInit(e)},fieldDynamicChoiceSourceForClassicSelect(e,i){let o=0;var t=i.length;for(e.find("option").not(".placeholder").remove();o'+r+"")}e.toggleClass("wpforms-hidden",!t)},fieldDynamicChoiceToggleImageChoices(){v(`#wpforms-builder .wpforms-field-options .wpforms-field-option-checkbox, + #wpforms-builder .wpforms-field-options .wpforms-field-option-radio`).each(function(e,i){var i=v(i),o=i.find(".wpforms-field-option-row-dynamic_choices select").val(),o=void 0!==o&&""!==o,t=i.find(".wpforms-field-option-row-choices_images input").is(":checked");i.find(".wpforms-field-option-row-choices_images").toggleClass("wpforms-hidden",o),t&&!o||i.find(".wpforms-field-option-row-choices_images_style").addClass("wpforms-hidden")})},fieldDynamicChoiceToggleIconChoices(){v(`#wpforms-builder .wpforms-field-options .wpforms-field-option-checkbox, + #wpforms-builder .wpforms-field-options .wpforms-field-option-radio`).each(function(e,i){var i=v(i),o=i.find(".wpforms-field-option-row-dynamic_choices select").val(),o=void 0!==o&&""!==o,t=i.find(".wpforms-field-option-row-choices_icons input").is(":checked");i.find(".wpforms-field-option-row-choices_icons").toggleClass("wpforms-hidden",o),t&&!o||(i.find(".wpforms-field-option-row-choices_icons_color").addClass("wpforms-hidden"),i.find(".wpforms-field-option-row-choices_icons_size").addClass("wpforms-hidden"),i.find(".wpforms-field-option-row-choices_icons_style").addClass("wpforms-hidden"))})},fieldDynamicChoiceToggleOtherOption(){v("#wpforms-builder .wpforms-field-options .wpforms-field-option-radio").each(function(e,i){var i=v(i),o=i.find(".wpforms-field-option-row-dynamic_choices select"),t=o.val(),t=void 0!==t&&""!==t,r=i.find(".wpforms-field-option-row-choices_other input").is(":checked"),o=o.closest(".wpforms-field-option-row").data("field-id"),s=v("#wpforms-field-option-"+o).find(".wpforms-field-option-row-choices_other input");t?s.is(":checked")&&s.prop("checked",!1).trigger("change"):WPForms.Admin.Builder.MultipleChoices.updatePreviewState(o),i.find(".wpforms-field-option-row-choices_other").toggleClass("wpforms-hidden",t),r&&!t||(i.find(".wpforms-field-option-row-other_placeholder").addClass("wpforms-hidden"),i.find(".wpforms-field-option-row-other_size").addClass("wpforms-hidden"))})},firstNChoicesAlert:(e,i)=>{var o,t,r,e=v("#wpforms-field-"+e);e.hasClass("wpforms-field-select")||(o=wp.template("wpforms-choices-limit-message"),t={total:i},r=k.settings.choicesLimit,e.find(".wpforms-alert-dynamic").remove(),r .layout-selector-display`);if(!e.length){var t,r={"layout-1":[{class:"one-half",data:"wpforms-one-half wpforms-first"},{class:"one-half",data:"wpforms-one-half"}],"layout-2":[{class:"one-third",data:"wpforms-one-third wpforms-first"},{class:"one-third",data:"wpforms-one-third"},{class:"one-third",data:"wpforms-one-third"}],"layout-3":[{class:"one-fourth",data:"wpforms-one-fourth wpforms-first"},{class:"one-fourth",data:"wpforms-one-fourth"},{class:"one-fourth",data:"wpforms-one-fourth"},{class:"one-fourth",data:"wpforms-one-fourth"}],"layout-4":[{class:"one-third",data:"wpforms-one-third wpforms-first"},{class:"two-third",data:"wpforms-two-thirds"}],"layout-5":[{class:"two-third",data:"wpforms-two-thirds wpforms-first"},{class:"one-third",data:"wpforms-one-third"}],"layout-6":[{class:"one-fourth",data:"wpforms-one-fourth wpforms-first"},{class:"one-fourth",data:"wpforms-one-fourth"},{class:"two-fourth",data:"wpforms-two-fourths"}],"layout-7":[{class:"two-fourth",data:"wpforms-two-fourths wpforms-first"},{class:"one-fourth",data:"wpforms-one-fourth"},{class:"one-fourth",data:"wpforms-one-fourth"}],"layout-8":[{class:"one-fourth",data:"wpforms-one-fourth wpforms-first"},{class:"two-fourth",data:"wpforms-two-fourths"},{class:"one-fourth",data:"wpforms-one-fourth"}]};let e,i=`
        +

        ${wpforms_builder.layout_selector_layout}

        +
        `;for(t in r){for(var s in e=r[t],i+='
        ',e)i+=``;i+="
        "}i+="
        ",v(`#wpforms-field-option-row-${o}-css > label`).after(i)}},fieldLayoutSelectorLayout(e){e=v(e);e.parent().find(".layout-selector-display-layout").not(e).remove(),e.parent().find(".heading").text(wpforms_builder.layout_selector_column),e.toggleClass("layout-selector-display-layout layout-selector-display-columns")},fieldLayoutSelectorInsert(e){let i=v(e),o=i.closest(".layout-selector-display"),t=o.parent(),r=t.data("field-id"),s=t.find("label"),l=t.find("input[type=text]"),a=i.data("classes"),n=l.val();n&&(["wpforms-one-half","wpforms-first","wpforms-one-third","wpforms-one-fourth","wpforms-two-thirds","wpforms-two-fourths"].forEach(e=>{n=n.replace(new RegExp("\\b"+e+"\\b","gi"),"")}),n=n.replace(/\s\s+/g," ").trim(),a+=" "+n),l.val(a),o.slideUp(400,function(){o.remove(),k.fieldLayoutSelectorInit(r)}),s.find(".toggle-layout-selector-display").removeClass("layout-selector-showing"),s.find(".toggle-layout-selector-display span").text(wpforms_builder.layout_selector_show)},toggleOrderSummaryConfirmation(e,i,o){"payment-total"===o&&v(".wpforms-confirmation").each(function(){v(this).find(".wpforms-panel-field-confirmations-message_order_summary").closest(".wpforms-panel-field").toggle(0!==v("#wpforms-panel-fields .wpforms-field-payment-total").length)})},bindUIActionsSettings(){y.on("click","#wpforms-panel-fields .wpforms-title-desc, #wpforms-panel-fields .wpforms-field-submit-button, .wpforms-center-form-name",function(e){e.preventDefault(),k.panelSwitch("settings"),(v(this).hasClass("wpforms-center-form-name")||v(this).hasClass("wpforms-title-desc"))&&setTimeout(function(){v("#wpforms-panel-field-settings-form_title").trigger("focus")},300)}),y.on("click",".wpforms-field-pagebreak-last button",function(e){e.preventDefault(),k.panelSwitch("settings"),v("#wpforms-panel-field-settings-pagebreak_prev").trigger("focus")}),y.on("click",".wpforms-panel-content-also-available-item-add-captcha",function(e){e.preventDefault();e=y.find("#wpforms-add-fields-captcha");e.data("action")?e.trigger("click"):k.fieldAdd("captcha",{}).done(function(e){k.panelSwitch("fields"),v("#wpforms-field-"+e.data.field.id).trigger("click")})}),y.on("input","#wpforms-panel-field-settings-pagebreak_prev",function(){v(".wpforms-field-pagebreak-last button").text(v(this).val())}),y.on("input","#wpforms-panel-field-settings-form_title, #wpforms-setup-name",function(){var e=v(this).val().toString().trim();v(".wpforms-preview .wpforms-form-name").text(e),v(".wpforms-center-form-name.wpforms-form-name").text(e),k.trimFormTitle()}),y.on("input","#wpforms-panel-field-settings-form_desc",function(){v(".wpforms-form-desc").text(v(this).val())}),y.on("input","#wpforms-panel-field-settings-submit_text",function(){var e=v(this).val()||wpforms_builder.submit_text;v(".wpforms-field-submit input[type=submit]").val(e)}),y.on("change","#wpforms-panel-field-settings-recaptcha",function(){k.captchaToggle()}),y.on("change",".wpforms-panel-field-confirmations-type",function(){k.confirmationFieldsToggle(v(this))}),y.on("change",".wpforms-panel-field-confirmations-message_entry_preview",k.confirmationEntryPreviewToggle),y.on("change","#wpforms-panel-field-settings-notification_enable",k.notificationToggle),y.on("click",".wpforms-builder-settings-block-add",function(e){e.preventDefault(),wpforms_builder.pro&&k.settingsBlockAdd(v(this))}),y.on("click",".wpforms-builder-settings-block-edit",function(e){e.preventDefault();e=v(this);e.parents(".wpforms-builder-settings-block-header").find(".wpforms-builder-settings-block-name").hasClass("editing")?k.settingsBlockNameEditingHide(e):k.settingsBlockNameEditingShow(e)}),y.on("blur",".wpforms-builder-settings-block-name-edit input",function(e){v(e.relatedTarget).hasClass("wpforms-builder-settings-block-edit")||k.settingsBlockNameEditingHide(v(this))}),y.on("keypress",".wpforms-builder-settings-block-name-edit input",function(e){13===e.keyCode&&(k.settingsBlockNameEditingHide(v(this)),e.preventDefault())}),y.on("click",".wpforms-builder-settings-block-clone",function(e){e.preventDefault(),k.settingsBlockPanelClone(v(this))}),y.on("click",".wpforms-builder-settings-block-toggle",function(e){e.preventDefault(),k.settingsBlockPanelToggle(v(this))}),y.on("click",".wpforms-builder-settings-block-delete",function(e){e.preventDefault(),k.settingsBlockDelete(v(this))}),y.on("wpformsSettingsBlockAdded wpformsSettingsBlockCloned",function(e,i){i.hasClass("wpforms-notification")&&k.notificationUpdateStatus(i)}),y.on("click",".wpforms-status-button",function(){v(this).hasClass("wpforms-notification-status-button")?k.notificationChangeStatus(v(this)):k.handleStatusButton(v(this))}),y.on("change","#wpforms-panel-field-settings-ajax_submit",function(){k.hideOpenConfirmationsInNewTabOptions(!v(this).is(":checked"))})},hideOpenConfirmationsInNewTabOptions(o){var e=v(".wpforms-panel-field-confirmations-redirect_new_tab");e.length&&e.each(function(){var e=v(this),i=e.closest(".wpforms-builder-settings-block").find(".wpforms-panel-field-confirmations-type").val();e.closest(".wpforms-panel-field").toggle(!o&&["redirect","page"].includes(i))})},captchaToggle(){var e=y.find(".wpforms-field-recaptcha"),i=v("#wpforms-panel-field-settings-recaptcha"),o=i.data("provider")||"recaptcha";e.length&&(i.is(":checked")?e.show().toggleClass("is-recaptcha","recaptcha"===o):e.hide())},initConfirmationsType(){v(".wpforms-panel-field-confirmations-type").each(function(){k.confirmationFieldsToggle(v(this))})},initElementsTinyMCE(e,t={}){if("undefined"!=typeof tinymce&&void 0!==wp.editor){let i={...m.tinymceDefaults,...t},o=i.tinymce.setup;i.tinymce.toolbar1.includes("wpf_insert_smart_tag")||(i.tinymce.toolbar1+=",wpf_insert_smart_tag"),i.tinymce.setup=function(e){o?.call(this,e),e.addButton("wpf_insert_smart_tag",{text:"",tooltip:wpforms_builder.smart_tags_dropdown_title,icon:!1,image:wpforms_builder.smart_tags_dropdown_mce_icon,classes:"wpforms-smart-tags-mce-button"})},e.each(function(){var e=v(this).attr("id");wp.editor.remove(e),wp.editor.initialize(e,i)})}},confirmationsSetup(){k.initConfirmationsType(),k.initElementsTinyMCE(v(".wpforms-panel-field-confirmations-message")),y.on("focusout",".wpforms-panel-field-confirmations-redirect",function(){let e=v(this);var i=e.val().trim();e.val(i),wpf.isURL(i)||""===i||k.confirmationRedirectValidationError(function(){e.trigger("focus")})}),y.on("wpformsBeforeSave wpformsPanelSectionSwitch wpformsPanelSwitch",function(t){v(".wpforms-confirmation").each(function(e,i){i=v(i);let o=i.find(".wpforms-panel-field-confirmations-redirect");if(!o.is(":hidden")){i=i.find(".wpforms-panel-field-confirmations-type");if(!("redirect"!==i.val()||0`,t='

        '+wpforms_builder[c+"_error"]+"

        ",r=i+o+t,s=v.confirm({container:y,title:!1,content:r,icon:"fa fa-info-circle",type:"blue",buttons:{confirm:{text:wpforms_builder.ok,btnClass:"btn-confirm",keys:["enter"],action(){var e=this.$content.find("input#settings-block-name").val().toString().trim(),i=this.$content.find(".error");if(""===e)return i.show(),!1;var i=d.closest(".wpforms-panel-content-section").find(".wpforms-builder-settings-block").first(),o=(wpf.restoreTooltips(i),"#wpforms-"+c+"-template-block"),o=v(o);let t,r;if(o.length){let e=o.text();e=e.replace(/{CLONE}/g,p).replace(/CLONE/g,p),t=v(e),r=p}else t=i.clone(),r=i.data("block-id");let s,l=(t.attr("data-block-id",p),t.find(".wpforms-builder-settings-block-name-holder span").text(e),t.find("input, textarea, select").each(function(){var e=v(this),i=e.parent();e.hasClass("wpforms-disabled")&&(i.hasClass("from-name")||i.hasClass("from-email"))||i.hasClass("wpforms-pdf-file-name")||(i=e).attr("name")&&(i.val("").attr("name",i.attr("name").replace(/\[(\d+)]/,"["+p+"]")),i.is("select")?(i.find("option").prop("selected",!1).attr("selected",!1),i.find("option").first().prop("selected",!0).attr("selected","selected")):"checkbox"===i.attr("type")?(e=i.closest(".wpforms-panel-field").hasClass("js-wpforms-enabled-notification"),i.prop("checked",e).attr("checked",e).val("1")):i.val("").attr("value",""))}),"wpforms-panel-field-"+f+"-"),a=l+r,n=(t.find('[id^="'+a+'"], [for^="'+a+'"]').each(function(){var e=v(this),i="LABEL"===e.prop("tagName")?"for":"id",o=e.attr(i).replace(new RegExp(a,"g"),l+p);e.attr(i,o)}),r+"-notification-by-status");t.find('[data-radio-group="'+n+'"]').each(function(){v(this).removeClass("wpforms-radio-group-"+n).addClass("wpforms-radio-group-"+p+"-notification-by-status").attr("data-radio-group",p+"-notification-by-status")}),t.find(".wpforms-builder-settings-block-name-holder input").val(e).attr("value",e),"notification"===c&&(t.find(".email-msg textarea").val("{all_fields}").text("{all_fields}").attr("value","{all_fields}"),t.find(".email-recipient input").val("{admin_email}").attr("value","{admin_email}")),t.removeClass("wpforms-builder-settings-block-default"),"confirmation"===c&&(t.find(".wpforms-panel-field-tinymce").remove(),"undefined"!=typeof WPForms)&&t.find(".wpforms-panel-field-confirmations-type-wrap").after(WPForms.Admin.Builder.Templates.get("wpforms-builder-confirmations-message-field")({id:p}));o=t.find(".wpforms-conditional-block"),o.length&&"undefined"!=typeof WPForms&&o.html(WPForms.Admin.Builder.Templates.get("wpforms-builder-conditional-logic-toggle-field")({id:p,type:c,actions:JSON.stringify(t.find(".wpforms-panel-field-conditional_logic-checkbox").data("actions")),actionDesc:t.find(".wpforms-panel-field-conditional_logic-checkbox").data("action-desc"),reference:t.find(".wpforms-panel-field-conditional_logic-checkbox").data("reference")})),e=t.find(".wpforms-field-map-table"),e.length&&e.each(function(e,i){var i=v(i),o=(i.find("tr:not(:first-child)").remove(),i.find(".key input")),i=i.find(".field select"),t=i.data("name");o.attr("value",""),i.attr("name","").attr("data-name",t.replace(/\[(\d+)]/,"["+p+"]"))}),s=(s=t.wrap("
        ").parent().html()).replace(/\[conditionals]\[(\d+)]\[(\d+)]/g,"[conditionals][0][0]"),0===i.length?d.closest(".wpforms-panel-content-section").append(s):i.before(s),o=0===i.length?d.closest(".wpforms-panel-content-section").find(".wpforms-builder-settings-block").first():i.prev();"confirmation"===c&&(k.prepareChoicesJSField(o,p),k.confirmationFieldsToggle(v(".wpforms-panel-field-confirmations-type").first())),"undefined"!=typeof tinymce&&void 0!==wp.editor&&"confirmation"===c&&wp.editor.initialize("wpforms-panel-field-confirmations-message-"+p,m.tinymceDefaults),wpf.initTooltips(),y.trigger("wpformsSettingsBlockAdded",[o]),d.attr("data-next-id",p+1)}},cancel:{text:wpforms_builder.cancel}}});y.on("keypress","#settings-block-name",function(e){13===e.keyCode&&v(s.buttons.confirm.el).trigger("click")})},prepareChoicesJSField(e,i){var o,e=e.find(`#wpforms-panel-field-confirmations-${i}-page-wrap`);e.length<=0||(i=e.find(`#wpforms-panel-field-confirmations-${i}-page`)).length<=0&&!i.hasClass("choicesjs-select")||(o=e.find(".choices")).length<=0||((i=i.first()).removeAttr("data-choice"),i.removeAttr("hidden"),i.removeClass("choices__input"),v(i).appendTo(e.first()),o.first().remove(),k.dropdownField.events.choicesInit(i))},settingsBlockNameEditingShow(e){e=e.parents(".wpforms-builder-settings-block-name-holder");e.find(".wpforms-builder-settings-block-name").addClass("editing").hide(),e.find(".wpforms-builder-settings-block-name-edit").addClass("active"),wpf.focusCaretToEnd(e.find("input"))},settingsBlockNameEditingHide(e){var i=e.parents(".wpforms-builder-settings-block-header"),o=i.find(".wpforms-builder-settings-block-name"),i=i.find(".wpforms-builder-settings-block-name-edit");let t=i.find("input").val().trim();e=e.data("block-type")||e.closest(".wpforms-builder-settings-block").data("block-type");t.length||(t=wpforms_builder[e+"_def_name"]),i.find("input").val(t),o.text(t),o.removeClass("editing").show(),i.removeClass("active")},settingsBlockPanelClone(e){let i=e.closest(".wpforms-panel-content-section"),o=i.find(".wpforms-builder-settings-block-add"),t=e.closest(".wpforms-builder-settings-block"),r=t.find(".wpforms-builder-settings-block-content"),s=parseInt(o.attr("data-next-id"),10),l=t.data("block-type"),a=t.find(".wpforms-builder-settings-block-name").text().trim()+wpforms_builder[l+"_clone"],n=r.is(":hidden"),d=(wpf.restoreTooltips(t),t.clone(!1,!0));k.settingsBlockUpdateState(n,s,l),d.data("block-id",s).attr("data-block-id",s),d.find(".wpforms-builder-settings-block-name-holder span").text(a),d.find(".wpforms-builder-settings-block-name-holder input").val(a),d.removeClass("wpforms-builder-settings-block-default"),o.attr("data-next-id",s+1),d.find("input, textarea, select").each(function(){var e=v(this);e.attr("name")&&e.attr("name",e.attr("name").replace(/\[(\d+)]/,"["+s+"]")),e.data("name")&&e.data("name",e.data("name").replace(/\[(\d+)]/,"["+s+"]")),e.attr("class")&&e.attr("class",e.attr("class").replace(/-(\d+)/,"-"+s)),e.attr("data-radio-group")&&e.attr("data-radio-group",e.attr("data-radio-group").replace(/(\d+)-/,s+"-"))}),d.find("*").each(function(){var e=v(this);e.attr("id")&&e.attr("id",e.attr("id").replace(/-(\d+)/,"-"+s)),e.attr("for")&&e.attr("for",e.attr("for").replace(/-(\d+)-/,"-"+s+"-")),e.data("input-name")&&e.data("input-name",e.data("input-name").replace(/\[(\d+)]/,"["+s+"]"))}),t.find("select").each(function(){var e=v(this).attr("name"),i=v(this).attr("name").replace(/\[(\d+)]/,"["+s+"]");d.find('select[name="'+i+'"]').val(v(this).attr("name",e).val())}),d.css("display","none").insertBefore(t).show("fast",function(){wpf.initTooltips()}),y.trigger("wpformsSettingsBlockCloned",[d,t.data("block-id")])},settingsBlockPanelToggle(e,i=null){let o=e.closest(".wpforms-builder-settings-block"),t=o.data("block-id"),r=o.data("block-type"),s=o.find(".wpforms-builder-settings-block-content"),l=s.is(":visible"),a={duration:400,start(){k.settingsBlockUpdateState(l,t,r)},always(){s.is(":visible")?e.html(''):e.html('')}};s.stop(),!0===i?s.slideDown(a):!1===i?s.slideUp(a):s.slideToggle(a)},settingsBlockDelete(e){var i=e.closest(".wpforms-panel-content-section");if(!(i.find(".wpforms-builder-settings-block").length<2&&"pdf"!==e.parents(".wpforms-builder-settings-block").data("block-type"))){let o=e.closest(".wpforms-builder-settings-block"),t=o.data("block-type");v.confirm({title:!1,content:wpforms_builder[t+"_delete"],icon:"fa fa-exclamation-circle",type:"orange",buttons:{confirm:{text:wpforms_builder.ok,btnClass:"btn-confirm",keys:["enter"],action(){var e=o.data("block-id"),i=o.data("block-type");v.post(wpforms_builder.ajax_url,{action:"wpforms_builder_settings_block_state_remove",nonce:wpforms_builder.nonce,block_id:e,block_type:i,form_id:m.formID}),o.remove(),y.trigger("wpformsSettingsBlockDeleted",[t,e])}},cancel:{text:wpforms_builder.cancel}}})}},settingsBlockUpdateState(e,i,o){v.post(wpforms_builder.ajax_url,{action:"wpforms_builder_settings_block_state_save",state:e?"closed":"opened",form_id:m.formID,block_id:i,block_type:o,nonce:wpforms_builder.nonce})},notificationsUpdateElementsVisibility(){console.warn('WARNING! Function "WPFormsBuilder.notificationsUpdateElementsVisibility()" has been deprecated.')},notificationUpdateStatus(e){var i=e.data("block-id"),i=v(`#wpforms-panel-field-notifications-${i}-enable`),e=e.find(".wpforms-builder-settings-block-status");k.changeStatusButton(e,"0"!==i.val()),i.val()||i.val("1")},notificationChangeStatus(e){var i=e.closest(".wpforms-notification").data("block-id"),i=v(`#wpforms-panel-field-notifications-${i}-enable`),o=e.data("active");k.changeStatusButton(e,!o),i.val(o?"0":"1")},handleStatusButton(e){var i=e.data("connection-id"),o=e.data("active");k.changeStatusButton(e,!o),v("#wpforms-connection-status-"+i).val(o?"0":"1")},changeStatusButton(e,i){e.removeClass("wpforms-badge-green wpforms-badge-silver");var o=e.find(".fa"),t=e.find(".wpforms-status-label");o.removeClass("fa-check fa-times"),i?(e.addClass("wpforms-badge-green"),o.addClass("fa-check"),t.text(wpforms_builder.active),e.attr("title",wpforms_builder.deactivate)):(e.addClass("wpforms-badge-silver"),o.addClass("fa-times"),t.text(wpforms_builder.inactive),e.attr("title",wpforms_builder.activate)),e.data("active",i)},bindUIActionsRevisions(){y.on("wpformsPanelSwitched",function(e,i){"revisions"===i&&(k.updateRevisionsList(),k.updateRevisionPreview())}),y.on("wpformsSaved",function(){"revisions"===wpf.getQueryString("view")&&k.updateRevisionsList()}),y.on("click",".wpforms-panel-content-revisions-link",function(e){e.preventDefault(),k.panelSwitch("revisions")})},updateRevisionsList(){let i=v(".wpforms-panel-revisions-button .badge-exclamation");if(i.length&&v.post(wpforms_builder.ajax_url,{action:"wpforms_mark_panel_viewed",form_id:m.formID,nonce:wpforms_builder.nonce}).done(function(e){e.success?i.remove():wpf.debug(e)}).fail(function(e,i){wpf.debug(e.responseText||i||"")}),y.hasClass("wpforms-revisions-enabled")){let o=v("#wpforms-panel-revisions .wpforms-revisions-content");o.fadeTo(250,.25,function(){v.post(wpforms_builder.ajax_url,{action:"wpforms_get_form_revisions",form_id:m.formID,revision_id:wpf.getQueryString("revision_id"),nonce:wpforms_builder.nonce}).done(function(e){e.success?o.replaceWith(e.data.html):wpf.debug(e)}).fail(function(e,i){wpf.debug(e.responseText||i||""),o.fadeTo(250,1)})})}},updateRevisionPreview(){var e=C.$formPreview.clone();e.find(".wpforms-field-duplicate, .wpforms-field-delete, .wpforms-field-helper, .wpforms-debug").remove().end(),e.find(".wpforms-field-wrap").removeClass("ui-sortable").addClass("ui-sortable-disabled"),e.find(".wpforms-field").removeClass("ui-sortable-handle ui-draggable ui-draggable-handle active").removeAttr("id data-field-id data-field-type").removeData(),e.find(".wpforms-field-submit-button").prop("disabled",!0),C.$revisionPreview.hasClass("has-preview")?C.$revisionPreview.find(".wpforms-preview-wrap").replaceWith(e):C.$revisionPreview.append(e).addClass("has-preview")},confirmSaveRevision(){v.confirm({title:wpforms_builder.heads_up,content:wpforms_builder.revision_update_confirm,icon:"fa fa-exclamation-circle",type:"orange",closeIcon:!1,buttons:{confirm:{text:wpforms_builder.save,btnClass:"btn-confirm",keys:["enter"],action(){y.addClass("wpforms-revision-is-saving"),WPFormsBuilder.formSave(!1).done(k.revisionSavedReload)}},cancel:{text:wpforms_builder.cancel,action(){WPFormsBuilder.setCloseConfirmation(!0)}}}})},revisionSavedReload(){wpf.updateQueryString("view",wpf.getQueryString("view")),wpf.removeQueryParam("revision_id"),a.location.reload()},bindUIActionsSaveExit(){y.on("click","#wpforms-embed",function(e){e.preventDefault(),v(this).hasClass("wpforms-disabled")||v(this).hasClass("wpforms-btn-light-grey-disabled")||WPFormsFormEmbedWizard.openPopup()}),y.on("click","#wpforms-save",function(e){e.preventDefault(),k.formSave(!1)}),y.on("click","#wpforms-exit",function(e){e.preventDefault(),k.formExit()}),y.on("wpformsSaved",function(){wpf.removeQueryParam("newform")})},formSave(s){if(y.hasClass("wpforms-is-revision")&&!y.hasClass("wpforms-revision-is-saving"))k.confirmSaveRevision();else{"undefined"!=typeof tinyMCE&&tinyMCE.triggerSave();var l=WPFormsUtils.triggerEvent(y,"wpformsBeforeSave");if(!l.isDefaultPrevented()){let e=C.$saveButton,i=e.find("i.fa-check"),o=e.find("i.wpforms-loading-spinner"),t=e.find("span"),r=t.text();t.text(wpforms_builder.saving),e.prop("disabled",!0),i.addClass("wpforms-hidden"),o.removeClass("wpforms-hidden");l={action:"wpforms_save_form",data:JSON.stringify(k.serializeAllData(v("#wpforms-builder-form"))),id:m.formID,nonce:wpforms_builder.nonce};return v.post(wpforms_builder.ajax_url,l,function(e){e.success?(wpf.initialSave=!1,setTimeout(()=>{wpf._updateFormState(),y.trigger("wpformsSaved",e.data),!0===s&&(k.isBuilderInPopup()?k.builderInPopupClose("saved"):a.location.href=wpforms_builder.exit_url)},0)):(wpf.debug(e),k.formSaveError(e.data))}).fail(function(e){wpf.debug(e);let i="";403===e.status&&(i=wpforms_builder.error_save_form_forbidden),k.formSaveError(i)}).always(function(){t.text(r),e.prop("disabled",!1),o.addClass("wpforms-hidden"),i.removeClass("wpforms-hidden")})}}},serializeAllData(e){let o=e.serializeArray();return e.find(".wpforms-field-option-layout .wpforms-field-option-row-label_hide input[type=checkbox]").each(function(){var e=v(this),i=e.attr("name"),e=e.is(":checked")?"1":"";e||o.push({name:i,value:e})}),o},formSaveError(e=""){wpf.empty(e)&&(e=wpforms_builder.error_save_form),v.confirm({title:wpforms_builder.heads_up,content:"

        "+e+"

        "+wpforms_builder.error_contact_support+"

        ",icon:"fa fa-exclamation-circle",type:"orange",buttons:{confirm:{text:wpforms_builder.ok,btnClass:"btn-confirm",keys:["enter"]}}})},formExit(){k.isBuilderInPopup()&&k.formIsSaved()?k.builderInPopupClose("saved"):k.formIsSaved()?a.location.href=wpforms_builder.exit_url:v.confirm({title:!1,content:wpforms_builder.exit_confirm,icon:"fa fa-exclamation-circle",type:"orange",closeIcon:!0,buttons:{confirm:{text:wpforms_builder.save_exit,btnClass:"btn-confirm",keys:["enter"],action(){k.formSave(!0)}},cancel:{text:wpforms_builder.exit,action(){o=!1,k.isBuilderInPopup()?k.builderInPopupClose("canceled"):a.location.href=wpforms_builder.exit_url}}}})},setCloseConfirmation(e){o=!!e},formIsSaved(){if("object"==typeof wpf.savedFormState&&0!==Object.keys(wpf.savedFormState).length){var e,i,o=wpf.isDebug(),t={},r=wpf._getCurrentFormState();for(e in r)if(r[e]!==wpf.savedFormState[e]){if(!o)return!1;t[e]={old:wpf.savedFormState[e],new:r[e]}}for(i in wpf.savedFormState)if(!(i in r)){if(!o)return!1;t[i]={old:wpf.savedFormState[i],new:void 0}}if(!Object.keys(t).length)return!0;wpf.debug("Form state differences:",t)}return!1},isBuilderInPopup(){return a.self!==a.parent&&"wpforms-builder-iframe"===a.self.frameElement.id},builderInPopupClose(e){var i=a.parent.jQuery(".wpforms-builder-popup"),o=v(".wpforms-center-form-name").text();i.find("#wpforms-builder-iframe").attr("src","about:blank"),i.fadeOut(),i.trigger("wpformsBuilderInPopupClose",[e,m.formID,o])},bindUIActionsGeneral(){y.on("click",".toggle-smart-tag-display",k.smartTagToggle),y.on("click",".smart-tags-list-display a",k.smartTagInsert),y.on("click",".wpforms-panel-fields-group.unfoldable .wpforms-panel-fields-group-title",k.toggleUnfoldableGroup),y.on("click",".wpforms-field-helper-hide ",k.hideFieldHelper),y.on("input",".wpforms-money-input",function(){var e=v(this),i=e.val(),o=e[0].selectionStart,t=e[0].selectionEnd;e.val(i.replace(/[^0-9.,]/g,"")),e[0].setSelectionRange(o,t)}),y.on("focusout",".wpforms-money-input",function(){var e=v(this),i=e.val();if(!i)return i;i=wpf.amountSanitize(i),i=wpf.amountFormat(i);e.val(i)}),y.on("change",".wpforms-panel-field-toggle",function(){var e=v(this);e.prop("disabled")||(e.prop("disabled",!0),k.toggleOptionsGroup(e))}),y.on("click",".wpforms-image-upload-add",function(e){e.preventDefault();let o=v(this),t=o.parent(),r=wpf.initMediaLibrary({title:wpforms_builder.upload_image_title,extensions:wpforms_builder.upload_image_extensions,extensionsError:wpforms_builder.upload_image_extensions_error,buttonText:wpforms_builder.upload_image_button});r.on("select",function(){var e=r.state().get("selection").first().toJSON(),i=t.find(".preview");t.find(".source").val(e.url),i.empty(),i.prepend(''),"hide"===o.data("after-upload")&&o.hide(),y.trigger("wpformsImageUploadAdd",[o,t])}).on("close",function(){r.off("library:selection:add")}),r.open()}),y.on("click",".wpforms-image-upload-remove",function(e){e.preventDefault();e=v(this).parent().parent();e.find(".preview").empty(),e.find(".wpforms-image-upload-add").show(),e.find(".source").val(""),y.trigger("wpformsImageUploadRemove",[v(this),e])}),y.on("blur",'.wpforms-notification .wpforms-panel-field-text input:not([type="search"])',function(){k.validateEmailSmartTags(v(this))}),y.on("blur",".wpforms-notification .wpforms-panel-field-textarea textarea",function(){k.validateEmailSmartTags(v(this))}),y.on("focusout",'.wpforms-notification .wpforms-panel-field.js-wpforms-from-email-validation input:not([type="search"])',k.validateFromEmail),y.on("wpformsPanelSectionSwitch",k.notificationsPanelSectionSwitch),y.on("click","#wpforms-builder-mobile-notice .wpforms-fullscreen-notice-button-primary, #wpforms-builder-mobile-notice .close",function(){a.location.href=wpforms_builder.exit_url}),y.on("click","#wpforms-builder-mobile-notice .wpforms-fullscreen-notice-button-secondary",function(){a.location.href=wpf.updateQueryString("force_desktop_view",1,a.location.href)}),v("#wpforms-builder-license-alert .close").on("click",function(){a.location.href=wpforms_builder.exit_url}),v("#wpforms-builder-license-alert .dismiss").on("click",function(e){e.preventDefault(),v("#wpforms-builder-license-alert").remove(),wpCookies.set("wpforms-builder-license-alert","true",3600)}),y.on("change","#wpforms-panel-field-settings-akismet.wpforms-akismet-disabled",function(){let e=v(this),i=e.data("akismet-status");e.prop("checked")&&v.alert({title:wpforms_builder.heads_up,content:wpforms_builder[i],icon:"fa fa-exclamation-circle",type:"orange",buttons:{confirm:{text:wpforms_builder.ok,btnClass:"btn-confirm",keys:["enter"]}},onClose(){e.prop("checked",!1)}})}),y.on("wpformsPanelSectionSwitch wpformsPanelSwitched",function(){wpf.reInitShowMoreChoices(v("#wpforms-panel-providers, #wpforms-panel-settings"))})},notificationsPanelSectionSwitch(e,i){"notifications"===i&&v(".wpforms-notification .wpforms-panel-field.js-wpforms-from-email-validation input").trigger("focusout")},isPaymentsEnabled(){let e=!1;return v(k.getPaymentsTogglesSelector()).each(function(){if(v(this).prop("checked"))return!(e=!0)}),e},getPaymentsTogglesSelector(){return`.wpforms-panel-content-section-payment-toggle-one-time input, + .wpforms-panel-content-section-payment-toggle-recurring input, + #wpforms-panel-field-stripe-enable, + #wpforms-panel-field-paypal_standard-enable, + #wpforms-panel-field-authorize_net-enable, + #wpforms-panel-field-square-enable`},toggleOptionsGroup(e){var i=e.attr("name");function o(){e.prop("disabled",!1)}let t="",r=v('.wpforms-panel-field-toggle-body[data-toggle="'+i+'"]');k.toggleProviderActiveIcon(e),0===r.length?o():(i=e.attr("type"),t="checkbox"!==i&&"radio"!==i||e.prop("checked")?e.val():"0",r.each(function(){var e=v(this);e.attr("data-toggle-value").toString()===t.toString()?e.slideDown(150,o):e.slideUp(150,o)}))},toggleProviderActiveIcon(e){var o=e.closest(".wpforms-panel-content-section").data("provider"),t=["wpforms-panel-field-"+o+"-enable-wrap","wpforms-panel-field-"+o+"-enable_one_time-wrap","wpforms-panel-field-"+o+"-enable_recurring-wrap"];if(o&&t.includes(e.attr("id"))){let i=!1;t.forEach(e=>{e=v("#"+e);e.length&&e.find("input").is(":checked")&&(i=!0)}),v(`.wpforms-panel-sidebar-section[data-section=${o}]`).find(".fa-check-circle-o").toggleClass("wpforms-hidden",!i)}},toggleAllOptionGroups(e){(e=e||y||v("#wpforms-builder")||v("body"))&&e.find(".wpforms-panel-field-toggle").each(function(){var e=v(this);e.prop("disabled",!0),k.toggleOptionsGroup(e)})},toggleUnfoldableGroup(e){e.preventDefault();let i=v(e.target),o=i.closest(".wpforms-panel-fields-group"),t=o.find(".wpforms-panel-fields-group-inner"),r="wpforms_fields_group_"+o.data("group");o.hasClass("opened")?(wpCookies.remove(r),t.stop().slideUp(150,function(){o.removeClass("opened")})):(wpCookies.set(r,"true",2592e3),o.addClass("opened"),t.stop().slideDown(150))},hideFieldHelper(e){e.preventDefault(),e.stopPropagation();e=v(".wpforms-field-helper");wpCookies.set("wpforms_field_helper_hide","true",2592e3),e.hide()},smartTagToggle(e){console.warn('WARNING! Function "WPFormsBuilder.smartTagToggle()" has been deprecated.'),e.preventDefault(),C.$focusOutTarget=null;var e=v(this),i=e.closest(".wpforms-panel-field,.wpforms-field-option-row");i.hasClass("smart-tags-toggling")||(i.addClass("smart-tags-toggling"),e.hasClass("smart-tag-showing")?k.removeSmartTagsList(e):k.insertSmartTagsList(e))},removeSmartTagsList(e){console.warn('WARNING! Function "WPFormsBuilder.removeSmartTagsList()" has been deprecated.');let i=e.closest(".wpforms-panel-field,.wpforms-field-option-row"),o=i.find(".smart-tags-list-display");e.find("span").text(wpforms_builder.smart_tags_show),o.slideUp("",function(){o.remove(),e.removeClass("smart-tag-showing"),i.removeClass("smart-tags-toggling")})},insertSmartTagsList(e){console.warn('WARNING! Function "WPFormsBuilder.insertSmartTagsList()" has been deprecated.');let i=e.closest(".wpforms-panel-field,.wpforms-field-option-row"),o=e.closest("label"),t=!0;o.length||(o=i.find("label"),t=!1);var r=k.getSmartTagsList(e,-1!==o.attr("for").indexOf("wpforms-field-option-"));(t?o:e).after(r),e.find("span").text(wpforms_builder.smart_tags_hide),i.find(".smart-tags-list-display").slideDown("",function(){e.addClass("smart-tag-showing"),i.removeClass("smart-tags-toggling")})},getSmartTagsList(e,i){var o;return console.warn('WARNING! Function "WPFormsBuilder.getSmartTagsList()" has been deprecated.'),o='
          ',(o+=k.getSmartTagsListFieldsElements(e))+k.getSmartTagsListOtherElements(e,i)+"
        "},getSmartTagsListFieldsElements(e){console.warn('WARNING! Function "WPFormsBuilder.getSmartTagsListFieldsElements()" has been deprecated.');var i=e.data("type");if(!["fields","all"].includes(i))return"";var o,t=k.getSmartTagsFields(e);if(!t)return'
      • '+wpforms_builder.fields_unavailable+"
      • ";let r="";for(o in r+='
      • '+wpforms_builder.fields_available+"
      • ",t)r+=k.getSmartTagsListFieldsElement(t[o]);return r},getSmartTagsFields(e){console.warn('WARNING! Function "WPFormsBuilder.getSmartTagsFields()" has been deprecated.');var i=e.data("fields"),e=e.data("allow-repeated-fields"),i=i?i.split(","):void 0;return wpf.getFields(i,!0,e)},getSmartTagsListFieldsElement(o){console.warn('WARNING! Function "WPFormsBuilder.getSmartTagsListFieldsElement()" has been deprecated.');let t=o.label?wpf.encodeHTMLEntities(wpf.sanitizeHTML(o.label)):wpforms_builder.field+" #"+o.id,r=`
      • ${t}
      • `;var e=o.additional||[];return 1{var i=e.charAt(0).toUpperCase()+e.slice(1).replace(/(\D)(\d)/g,"$1 $2");r+=`
      • ${t} – ${i}
      • `}),r},getSmartTagsListOtherElements(e,i){console.warn('WARNING! Function "WPFormsBuilder.getSmartTagsListOtherElements()" has been deprecated.');var o,t=e.data("type");let r;if("other"!==t&&"all"!==t)return"";for(o in r='
      • '+wpforms_builder.other+"
      • ",wpforms_builder.smart_tags)i&&wpforms_builder.smart_tags_disabled_for_fields.includes(o)||"confirmations"===e.data("location")&&wpforms_builder.smart_tags_disabled_for_confirmations.includes(o)||(r+='
      • "+wpforms_builder.smart_tags[o]+"
      • ");return r},smartTagInsert(e){console.warn('WARNING! Function "WPFormsBuilder.smartTagInsert()" has been deprecated.'),e.preventDefault();let i=v(this),o=i.closest(".smart-tags-list-display"),t=o.closest(".wpforms-panel-field,.wpforms-field-option-row"),r=t.find(".toggle-smart-tag-display"),s=t.find("input[type=text], textarea"),l=i.data("meta"),a=i.data("additional")?"|"+i.data("additional"):"",n=i.data("type"),d="field"===n?'{field_id="'+l+a+'"}':"{"+l+"}",p;"undefined"!=typeof tinyMCE&&(p=tinyMCE.get(s.prop("id")))&&!p.hasFocus()&&p.focus(!0),p&&!p.isHidden()?p.insertContent(d):(s.insertAtCaret(" "+d+" "),s.val(s.val().trim().replace(" "," ")),s.trigger("focus").trigger("input")),o.slideUp("",function(){o.remove()}),r.find("span").text(wpforms_builder.smart_tags_show),t.find(".toggle-smart-tag-display").removeClass("smart-tag-showing")},validateEmailSmartTags(e){console.warn('WARNING! Function "WPFormsBuilder.validateEmailSmartTags()" has been deprecated.');let i=e.val();i&&(i=i.replace(/{(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))}/g,function(e){return e.slice(1,-1)}),e.val(i))},getEmailFieldSmartTagError(e){var i=/\{field_id="(\d+)"}/g;if(!i.test(e))return null;i.lastIndex=0;i=i.exec(e),e=i?i[1]:null,i=wpf.getField(e);return i&&"email"===i.type?"":wpforms_builder.allow_only_email_fields},validateFromEmail(){var e,i,o;wpf.isRepeatedCall("validateFromEmail")||(e=(i=v(this)).val(),i.data("value")!==e&&(i.data("value",e),i=i.parent(),o="wpforms-panel-field-warning",/[\s,;]/g.test(e.trim())?(i.addClass(o),k.printNotice(wpforms_builder.allow_only_one_email,i)):k.shouldCallAjaxValidation(e,i,o)&&k.ajaxValidation(e,i,o)))},shouldCallAjaxValidation(e,i,o){let t="",r=!0;return""===(t=""===e?wpforms_builder.empty_email_address:"")&&(t=k.getEmailFieldSmartTagError(e),r=null===t),t?(i.addClass(o),k.printNotice(t,i,""===e),!1):!!r||(i.removeClass(o),k.removeNotice(i),!1)},ajaxValidation(e,i,o){e={form_id:m.formID,email:e,nonce:wpforms_builder.nonce,action:"wpforms_builder_notification_from_email_validate"};v.post(wpforms_builder.ajax_url,e,function(e){k.removeNotice(i),e.success?i.removeClass(o):(i.addClass(o),i.append(e.data))}).fail(function(e){console.log(e.responseText)})},disabledFields:{init(){k.disabledFields.initCouponsChoicesJS(),k.disabledFields.initFileUploadChoicesJS()},initCouponsChoicesJS(){"function"!=typeof a.Choices||WPForms.Admin.Builder.Coupons||v(".wpforms-field-option-row-allowed_coupons select:not(.choices__input)").each(function(){var e=v(this),i=new Choices(e.get(0),{shouldSort:!1,removeItemButton:!0,renderChoicesLimit:5,callbackOnInit(){wpf.showMoreButtonForChoices(this.containerOuter.element)}});e.data("choicesjs",i)})},initFileUploadChoicesJS(){"function"!=typeof a.Choices||WPForms.Admin.Builder.FieldFileUpload||v(".wpforms-file-upload-user-roles-select, .wpforms-file-upload-user-names-select").each(function(){new Choices(v(this)[0],{removeItemButton:!0})})}},iconChoices:{cache:{},config:{colorPropertyName:"--wpforms-icon-choices-color"},init(){k.iconChoices.extendJqueryConfirm(),y.on("wpformsBuilderReady",function(e){wpforms_builder.icon_choices.is_active&&!wpforms_builder.icon_choices.is_installed&&(k.iconChoices.openInstallPromptModal(!0),e.preventDefault())}),y.on("change",".wpforms-field-option-row-choices_icons input",k.iconChoices.toggleIconChoices),y.on("change",".wpforms-field-option-row-choices_icons_color .wpforms-color-picker",k.iconChoices.changeIconsColor),y.on("change",".wpforms-field-option-row-choices_icons_style select, .wpforms-field-option-row-choices_icons_size select",function(){var e=v(this).parent().data("field-id"),i=v("#wpforms-field-option-"+e).find(".wpforms-field-option-hidden-type").val();k.fieldChoiceUpdate(i,e)}),y.on("click",".wpforms-field-option-row-choices .choices-list .wpforms-icon-select",k.iconChoices.openIconPickerModal)},toggleIconChoices(){var e,i,o,t=v(this),r=t.is(":checked");r&&!wpforms_builder.icon_choices.is_installed?(k.iconChoices.cache.toggle=t,k.iconChoices.openInstallPromptModal()):(t=t.closest(".wpforms-field-option-row").data("field-id"),o=(e=v("#wpforms-field-option-"+t)).find(`#wpforms-field-option-${t}-choices_images`),i=e.find(`#wpforms-field-option-row-${t}-choices ul`),r&&o.is(":checked")&&o.prop("checked",!1).trigger("change"),e.find(`#wpforms-field-option-row-${t}-dynamic_choices`).toggleClass("wpforms-hidden",r),e.find(`#wpforms-field-option-row-${t}-choices_icons_color`).toggleClass("wpforms-hidden"),e.find(`#wpforms-field-option-row-${t}-choices_icons_size`).toggleClass("wpforms-hidden"),e.find(`#wpforms-field-option-row-${t}-choices_icons_style`).toggleClass("wpforms-hidden"),o=e.find(`#wpforms-field-option-${t}-choices_icons_color`),o=_.isEmpty(o.val())?wpforms_builder.icon_choices.default_color:o.val(),i.prop("style",k.iconChoices.config.colorPropertyName+`: ${o};`),i.toggleClass("show-icons",r),e.find(`#wpforms-field-option-${t}-input_columns`).val(r?"inline":"").trigger("change"),v(`#wpforms-field-option-row-${t}-choices_icons_hide`).toggleClass("wpforms-hidden",!r),k.fieldChoiceUpdate(e.find(".wpforms-field-option-hidden-type").val(),t))},changeIconsColor(){var e=v(this),i=e.parents(".wpforms-field-option-row").data("field-id"),o=v("#wpforms-field-option-"+i),t=o.find(".wpforms-field-option-hidden-type").val(),o=o.find(".wpforms-field-option-row-choices .choices-list"),e=k.getValidColorPickerValue(e);o.prop("style",k.iconChoices.config.colorPropertyName+`: ${e};`),k.fieldChoiceUpdate(t,i)},openInstallPromptModal(e=!1){var i=e?wpforms_builder.icon_choices.strings.reinstall_prompt_content:wpforms_builder.icon_choices.strings.install_prompt_content,i=v.confirm({title:wpforms_builder.heads_up,content:i,icon:"fa fa-info-circle",type:"orange",buttons:{continue:{text:wpforms_builder.continue,btnClass:"btn-confirm",keys:["enter"],action(){return this.setIcon("fa fa-cloud-download"),this.setTitle(wpforms_builder.icon_choices.strings.install_title),this.setContent(wpforms_builder.icon_choices.strings.install_content),v.each(this.buttons,function(e,i){i.hide()}),k.iconChoices.installIconLibrary(),!1}}},onOpen(){!e&&k.iconChoices.cache.toggle&&k.iconChoices.cache.toggle.prop("checked",!1),k.iconChoices.cache.previousModal=this}});e||(i.buttons.cancel={text:wpforms_builder.cancel,keys:["esc"],action(){k.iconChoices.cache.toggle.prop("checked",!1)}})},installIconLibrary(){var e={_wp_http_referer:wpf.updateQueryString("_wp_http_referer",null),nonce:wpforms_builder.nonce,action:"wpforms_icon_choices_install"};v.ajaxSetup({type:"POST",timeout:12e4}),v.post(wpforms_builder.ajax_url,e,function(e){e.success?k.iconChoices.openInstallSuccessModal():k.iconChoices.openInstallErrorModal(e)}).fail(function(e){k.iconChoices.openInstallErrorModal(e)})},openInstallSuccessModal(){v.confirm({title:wpforms_builder.done,content:wpforms_builder.icon_choices.strings.install_success_content,icon:"fa fa-check-circle",type:"green",buttons:{confirm:{text:wpforms_builder.ok,btnClass:"btn-confirm",keys:["enter"],action(){var e;k.iconChoices.cache.toggle&&(k.iconChoices.cache.toggle.prop("checked",!0),e=k.iconChoices.cache.toggle.parents(".wpforms-field-option-row").data("field-id"),(e=y.find(`#wpforms-field-option-${e}-choices_images`)).is(":checked"))&&e.prop("checked",!1),wpforms_builder.exit_url=a.location.href,k.formSave(!0)}}},onOpen(){var e;k.iconChoices.cache.toggle&&(e=k.iconChoices.cache.toggle.parents(".wpforms-field-option-row-choices_icons").data("field-id"),y.find(`#wpforms-field-option-${e}-input_columns`).val("inline")),k.iconChoices.cache.previousModal.close()}})},openInstallErrorModal(e){v.confirm({title:wpforms_builder.uh_oh,content:wpforms_builder.icon_choices.strings.install_error_content,icon:"fa fa-exclamation-circle",type:"red",buttons:{confirm:{text:wpforms_builder.ok,btnClass:"btn-confirm",keys:["enter"],action(){k.iconChoices.cache.toggle?k.iconChoices.cache.toggle.prop("checked",!1):k.formSaveError()}}},onOpen(){wpf.debug(e),k.iconChoices.cache.previousModal.close()},onDestroy(){delete k.iconChoices.cache.previousModal,delete k.iconChoices.cache.toggle}})},extendJqueryConfirm(){a.Jconfirm.prototype._updateContentMaxHeight=function(){var e=v(a).height()-(this.$jconfirmBox.outerHeight()-this.$contentPane.outerHeight())-(this.offsetTop+this.offsetBottom),i=this.contentMaxHeight||e;this.$contentPane.css({"max-height":Math.min(i,e)+"px"})}},openIconPickerModal(){var e=v(this);let i={fieldId:e.parents(".wpforms-field-option-row").data("field-id"),choiceId:e.parent().data("key"),selectedIcon:e.find(".source-icon").val(),selectedIconStyle:e.find(".source-icon-style").val()};var e=` + ${wpforms_builder.icon_choices.strings.icon_picker_title} + ${wpforms_builder.icon_choices.strings.icon_picker_description} + + `,o=` +
        +
          +
            +

            +

            `;v.confirm({title:e,titleClass:"wpforms-icon-picker-title",content:o,icon:!1,closeIcon:!0,type:"orange",backgroundDismiss:!0,boxWidth:800,contentMaxHeight:368,smoothContent:!1,buttons:!1,onOpenBefore(){this.$body.addClass("wpforms-icon-picker-jconfirm-box"),this.$contentPane.addClass("wpforms-icon-picker-jconfirm-content-pane")},onContentReady(){let e=this;k.iconChoices.initIconsList(i),e.$title.find(".search").focus(),e.$content.find(".wpforms-icon-picker-icons").on("click","li",function(){k.iconChoices.selectIcon(e,v(this))})}})},initIconsList(o){var e={valueNames:["name"],listClass:"wpforms-icon-picker-icons",page:wpforms_builder.icon_choices.icons_per_page,pagination:{paginationClass:"wpforms-icon-picker-pagination"},item(e){var i=e.icon===o.selectedIcon&&e.style===o.selectedIconStyle?'class="selected"':"";return` +
          • + + ${e.icon} +
          • `},indexAsync:!0};let t=new List("wpforms-icon-picker-icons",e,wpforms_builder.icon_choices.icons);k.iconChoices.infiniteScrollPagination(t),v("#wpforms-icon-picker-search").on("keyup",function(){t.search(v(this).val(),["name"],function(o){for(let e=0,i=t.items.length;ealt
            s")}})},registerTemplates(){"undefined"!=typeof WPForms&&WPForms.Admin.Builder.Templates.add(["wpforms-builder-confirmations-message-field","wpforms-builder-conditional-logic-toggle-field"])},exitBack(){console.warn('WARNING! Function "WPFormsBuilder.exitBack()" has been deprecated.')},onUpdateSelectPlaceholder(e,i){!["select","payment-select"].includes(i.data("field-type"))||!i.hasClass("required")||v(`#wpforms-field-option-${e}-multiple`).prop("checked")||k.dropdownField.helpers.hasDefaults(e)||k.updateSelectPlaceholder(e)},updateSelectPlaceholder(e){e=v(`#wpforms-field-option-${e}-placeholder`);e.val()||e.val(wpforms_builder.select_choice).trigger("input")},maybeUpdateRequiredPlaceholder(e){v(`#wpforms-field-option-${e}-required`).is(":checked")&&k.updateSelectPlaceholder(e)}};return k})(document,window,jQuery);WPFormsBuilder.init(); \ No newline at end of file diff --git a/wp-content/plugins/wpforms-lite/assets/js/admin/builder/chocolate-choices.js b/wp-content/plugins/wpforms-lite/assets/js/admin/builder/chocolate-choices.js new file mode 100755 index 00000000..fa426489 --- /dev/null +++ b/wp-content/plugins/wpforms-lite/assets/js/admin/builder/chocolate-choices.js @@ -0,0 +1,81 @@ +/** + * Chocolate choices' functionality. + * + * @since 1.9.6.1 + */ +// eslint-disable-next-line no-unused-vars +const WPFormsChocolateChoices = { + /** + * Initializes the chocolate choices component. + * + * @since 1.9.6.1 + * + * @param {Object} $grid The grid container for the choices. + * @param {Object} options Object with name and choices properties. + * @param {string} options.name The name attribute for the checkbox inputs. + * @param {Array} options.choices Array of choice objects with label and value properties. + * @param {Array} options.selected Array of selected choice values. + */ + init( $grid, options ) { + const selected = options.selected?.map?.( String ) ?? []; + const $ = jQuery; + /** + * Generate a random ID string. + * The ID is based on current timestamp and converted to a base-16 string. + * + * @since 1.9.6.1 + * + * @return {string} A hexadecimal string representation of the current timestamp. + */ + const getRandomId = () => new Date().getTime().toString( 16 ); + + /** + * Creates a single choice item. + * + * @since 1.9.6.1 + * + * @param {Object|string|number} itemData The choice data object with label and value. + * @param {number} index The index of the choice item. + * + * @return {jQuery} The created choice item element. + */ + const createChoiceItem = ( itemData, index ) => { + const id = `choice-${ index }-${ getRandomId() }`; + const itemValue = String( typeof itemData === 'object' ? itemData.value : itemData ); + + // Create the container div. + const $itemDiv = $( '
            ', { + class: 'choice-item', + } ); + + // Create the checkbox input. + const $checkbox = $( '', { + type: 'checkbox', + id, + value: itemValue, + checked: selected.includes( itemValue ), + name: options.name.replace( '{index}', index ), + } ); + + // Create the label. + const $label = $( '