PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.8.2
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.8.2
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / classes / models / FrmSolution.php

FrmSolution.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.8.2, at classes/models/FrmSolution.php

899 lines 21.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles the installation of a solution and any dependencies.
4 * This page is shown when a Formidable plugin is activated.
5 *
6 * @since 4.06.02
7 * @package Formidable
8 */
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 die( 'You are not allowed to call this page directly.' );
12 }
13
14 class FrmSolution {
15
16 protected $plugin_slug = '';
17
18 protected $plugin_file = '';
19
20 /**
21 * Hidden welcome page slug.
22 *
23 * @since 4.06.02
24 * @var string
25 */
26 protected $page = '';
27
28 protected $icon = 'frm_icon_font frm_settings_icon';
29
30 public function __construct( $atts = array() ) {
31 if ( empty( $this->plugin_slug ) ) {
32 return;
33 }
34
35 add_action( 'plugins_loaded', array( $this, 'load_hooks' ), 50 );
36 add_action( 'admin_init', array( $this, 'redirect' ), 9999 );
37
38 if ( empty( $this->plugin_file ) ) {
39 $this->plugin_file = $this->plugin_slug . '.php';
40 }
41 }
42
43 /**
44 * Register all WP hooks.
45 *
46 * @since 4.06.02
47 *
48 * @return void
49 */
50 public function load_hooks() {
51 // If user is in admin ajax or doing cron, return.
52 if ( wp_doing_cron() ) {
53 return;
54 }
55
56 add_filter( 'frm_add_settings_section', array( $this, 'add_settings' ) );
57
58 if ( wp_doing_ajax() ) {
59 return;
60 }
61
62 // If user cannot manage_options, return.
63 if ( ! current_user_can( 'frm_change_settings' ) && ! FrmAppHelper::is_formidable_admin() ) {
64 return;
65 }
66
67 add_filter( 'plugin_action_links_' . $this->plugin_slug . '/' . $this->plugin_file, array( $this, 'plugin_links' ) );
68 add_action( 'admin_menu', array( $this, 'register' ) );
69 add_action( 'admin_head', array( $this, 'hide_menu' ) );
70 }
71
72 public function plugin_links( $links ) {
73 if ( ! $this->is_complete() ) {
74 $settings = '<a href="' . esc_url( $this->settings_link() ) . '">' . __( 'Setup', 'formidable' ) . '</a>';
75 array_unshift( $links, $settings );
76 }
77
78 return $links;
79 }
80
81 /**
82 * Register the pages to be used for the Welcome screen (and tabs).
83 *
84 * These pages will be removed from the Dashboard menu, so they will
85 * not actually show. Sneaky, sneaky.
86 *
87 * @since 4.06.02
88 *
89 * @return void
90 */
91 public function register() {
92
93 // Getting started - shows after installation.
94 add_dashboard_page(
95 esc_html( $this->page_title() ),
96 esc_html( $this->page_title() ),
97 'frm_change_settings',
98 $this->page,
99 array( $this, 'output' )
100 );
101 }
102
103 /**
104 * Removed the dashboard pages from the admin menu.
105 *
106 * This means the pages are still available to us, but hidden.
107 *
108 * @since 4.06.02
109 *
110 * @return void
111 */
112 public function hide_menu() {
113 remove_submenu_page( 'index.php', $this->page );
114 }
115
116 /**
117 * @return string
118 *
119 * @psalm-return ''
120 */
121 protected function plugin_name() {
122 return '';
123 }
124
125 /**
126 * @return string
127 */
128 protected function page_title() {
129 return __( 'Welcome to Formidable Forms', 'formidable' );
130 }
131
132 /**
133 * @return string
134 */
135 protected function page_description() {
136 return __( 'Follow the steps below to get started.', 'formidable' );
137 }
138
139 /**
140 * Welcome screen redirect.
141 *
142 * This function checks if a new install or update has just occurred. If so,
143 * then we redirect the user to the appropriate page.
144 *
145 * @since 4.06.02
146 *
147 * @return void
148 */
149 public function redirect() {
150
151 $current_page = FrmAppHelper::simple_get( 'page', 'sanitize_title' );
152 if ( $current_page === $this->page ) {
153 // Prevent endless loop.
154 return;
155 }
156
157 // Only do this for single site installs.
158 if ( isset( $_GET['activate-multi'] ) || is_network_admin() ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
159 return;
160 }
161
162 // Check if we should consider redirection.
163 if ( ! $this->is_current_plugin() ) {
164 return;
165 }
166
167 delete_transient( 'frm_activation_redirect' );
168
169 // Initial install.
170 wp_safe_redirect( $this->settings_link() );
171 exit;
172 }
173
174 /**
175 * @return string
176 */
177 protected function settings_link() {
178 return admin_url( 'index.php?page=' . $this->page );
179 }
180
181 /**
182 * Add page to global settings.
183 */
184 public function add_settings( $sections ) {
185 wp_enqueue_style( 'formidable-pro-fields' );
186 $sections[ $this->plugin_slug ] = array(
187 'class' => $this,
188 'function' => 'settings_page',
189 'name' => $this->plugin_name(),
190 'icon' => $this->icon,
191 'ajax' => true,
192 );
193 return $sections;
194 }
195
196 /*
197 * Output for global settings.
198 */
199 /**
200 * @return void
201 */
202 public function settings_page() {
203 $steps = $this->get_steps_data();
204 if ( ! $steps['license']['complete'] || ( isset( $steps['plugin'] ) && ! $steps['plugin']['complete'] ) ) {
205 // Redirect to the welcome page if install hasn't been done.
206 $url = $this->settings_link();
207 echo '<script>window.location.replace("' . esc_url_raw( $url ) . '");</script>';
208 return;
209 }
210
211 $all_imported = $this->is_complete( 'all' );
212
213 $step = $steps['import'];
214 $step['label'] = '';
215 $step['nested'] = true;
216
217 if ( $steps['complete']['current'] ) {
218 // Always show this step in settings.
219 $step['current'] = true;
220
221 $new_class = $all_imported ? ' button frm_hidden' : '';
222 $step['button_class'] = str_replace( 'frm_grey disabled', $new_class, $step['button_class'] );
223 }
224 if ( $all_imported ) {
225 $step['description'] = __( 'The following form(s) have been created.', 'formidable' );
226 }
227 $this->show_app_install( $step );
228
229 if ( ! $all_imported ) {
230 $step = $steps['complete'];
231 $step['current'] = false;
232 $step['button_class'] .= ' frm_grey disabled';
233 $this->show_page_links( $step );
234 }
235 }
236
237 /**
238 * Getting Started screen. Shows after first install.
239 *
240 * @return void
241 */
242 public function output() {
243 FrmAppHelper::include_svg();
244 $this->css();
245 $class = FrmAppHelper::pro_is_installed() ? 'pro' : 'lite';
246
247 echo '<div id="frm-welcome" class="wrap frm-wrap frm-admin-plugin-landing upgrade_to_pro ' . sanitize_html_class( $class ) . '">';
248
249 $this->header();
250 $this->main_content();
251
252 echo '</div>';
253 }
254
255 /**
256 * Heading section.
257 *
258 * @return void
259 */
260 protected function header() {
261 $size = array(
262 'height' => 90,
263 'width' => 90,
264 );
265
266 ?>
267 <section class="top">
268 <div class="frm-smtp-logos">
269 <?php FrmAppHelper::show_logo( $size ); ?>
270 <?php
271 FrmAppHelper::icon_by_class(
272 'frmfont frm_arrow_right_icon',
273 array(
274 'aria-label' => 'Install',
275 'style' => 'width:30px;height:30px;margin:0 35px;',
276 )
277 );
278 FrmAppHelper::icon_by_class(
279 'frmfont frm_wordpress_icon',
280 array(
281 'aria-label' => 'WordPress',
282 'style' => 'width:90px;height:90px;',
283 )
284 );
285 ?>
286 </div>
287 <h1><?php echo esc_html( $this->page_title() ); ?></h1>
288 <p><?php echo esc_html( $this->page_description() ); ?></p>
289 </section>
290 <?php
291 }
292
293 /**
294 * This is the welcome page content.
295 * Override me to insert different content.
296 *
297 * @return void
298 */
299 protected function main_content() {
300 $steps = $this->get_steps_data();
301 $this->license_box( $steps['license'] );
302 if ( isset( $steps['plugin'] ) ) {
303 $this->show_plugin_install( $steps['plugin'] );
304 }
305 $this->show_app_install( $steps['import'] );
306 $this->show_page_links( $steps['complete'] );
307 }
308
309 protected function get_steps_data() {
310 $pro_installed = FrmAppHelper::pro_is_connected();
311
312 $steps = array(
313 'license' => array(
314 'label' => __( 'Connect to FormidableForms.com', 'formidable' ),
315 'description' => __( 'Create a connection to get plugin downloads.', 'formidable' ),
316 'button_label' => __( 'Connect an Account', 'formidable' ),
317 'current' => empty( $pro_installed ),
318 'complete' => $pro_installed,
319 'num' => 1,
320 ),
321 'plugin' => array(
322 'label' => __( 'Install and Activate Add-Ons', 'formidable' ),
323 'description' => __( 'Install any required add-ons from FormidableForms.com.', 'formidable' ),
324 'button_label' => __( 'Install & Activate', 'formidable' ),
325 'current' => false,
326 'complete' => false,
327 'num' => 2,
328 ),
329 'import' => array(
330 'label' => __( 'Setup Forms, Views, and Pages', 'formidable' ),
331 'description' => __( 'Build the forms, views, and pages automatically.', 'formidable' ),
332 'button_label' => __( 'Create Now', 'formidable' ),
333 'complete' => $this->is_complete(),
334 'num' => 3,
335 ),
336 'complete' => array(
337 'label' => __( 'Customize Your New Pages', 'formidable' ),
338 'description' => __( 'Make any required changes and publish the page.', 'formidable' ),
339 'button_label' => __( 'View Page', 'formidable' ),
340 'complete' => false,
341 'num' => 4,
342 ),
343 );
344
345 $this->adjust_plugin_install_step( $steps );
346
347 $has_current = false;
348 foreach ( $steps as $k => $step ) {
349 // Set the current step.
350 if ( ! isset( $step['current'] ) ) {
351 if ( $step['complete'] ) {
352 $steps[ $k ]['current'] = false;
353 } else {
354 $steps[ $k ]['current'] = ! $has_current;
355 $has_current = true;
356 }
357 } elseif ( $step['current'] ) {
358 $has_current = true;
359 }
360
361 // Set disabled buttons.
362 $class = isset( $step['button_class'] ) ? $step['button_class'] : '';
363 $class .= ' button-primary frm-button-primary';
364 if ( ! $steps[ $k ]['current'] ) {
365 $class .= ' frm_grey disabled';
366 }
367 $steps[ $k ]['button_class'] = $class;
368 }//end foreach
369
370 return $steps;
371 }
372
373 /**
374 * @param array $steps
375 *
376 * @return void
377 */
378 protected function adjust_plugin_install_step( &$steps ) {
379 $plugins = $this->required_plugins();
380 if ( empty( $plugins ) ) {
381 unset( $steps['plugin'] );
382 $steps['import']['num'] = 2;
383 $steps['complete']['num'] = 3;
384 return;
385 }
386
387 $missing = array();
388 $rel = array();
389 foreach ( $plugins as $plugin_key ) {
390 $plugin = FrmAddonsController::install_link( $plugin_key );
391 if ( $plugin['status'] === 'active' ) {
392 continue;
393 }
394 $links[ $plugin_key ] = $plugin;
395 if ( isset( $plugin['url'] ) ) {
396 $rel[] = $plugin['url'];
397 } else {
398 // Add-on is required but not allowed.
399 $missing[] = $plugin_key;
400 }
401 }
402 if ( empty( $rel ) && empty( $missing ) ) {
403 $steps['plugin']['complete'] = true;
404 } elseif ( ! empty( $missing ) ) {
405 $steps['plugin']['error'] = sprintf(
406 /* translators: %1$s: Plugin name */
407 esc_html__( 'You need permission to download the Formidable %1$s plugin', 'formidable' ),
408 implode( ', ', $missing )
409 );
410 } else {
411 $steps['plugin']['links'] = $rel;
412 $steps['plugin']['button_class'] = 'frm-solution-multiple ';
413 }
414
415 if ( $steps['license']['complete'] && ! $steps['plugin']['complete'] ) {
416 $steps['plugin']['current'] = true;
417 }
418 }
419
420 /**
421 * @return void
422 */
423 protected function step_top( $step ) {
424 $section_class = ( ! isset( $step['current'] ) || ! $step['current'] ) ? 'frm_grey' : '';
425
426 ?>
427 <section class="step step-install <?php echo esc_attr( $section_class ); ?>">
428 <aside class="num">
429 <?php
430 if ( isset( $step['complete'] ) && $step['complete'] ) {
431 FrmAppHelper::icon_by_class(
432 'frmfont frm_step_complete_icon',
433 array(
434 /* translators: %1$s: Step number */
435 'aria-label' => sprintf( __( 'Step %1$d', 'formidable' ), $step['num'] ),
436 'style' => 'width:50px;height:50px;',
437 )
438 );
439 } else {
440 ?>
441 <svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 100 100"><circle cx="50" cy="50" r="50" fill="#ccc"/><text x="50%" y="50%" text-anchor="middle" fill="#fff" stroke="#fff" stroke-width="2px" dy=".3em" font-size="3.7em"><?php echo esc_html( $step['num'] ); ?></text></svg>
442 <?php
443 }
444 ?>
445 <i class="loader hidden"></i>
446 </aside>
447 <div>
448 <?php if ( $step['label'] ) { ?>
449 <h3 class="frm-step-heading"><?php echo esc_html( $step['label'] ); ?></h3>
450 <?php } ?>
451 <p><?php echo esc_html( $step['description'] ); ?></p>
452 <?php if ( isset( $step['error'] ) ) { ?>
453 <p class="frm_error"><?php echo esc_html( $step['error'] ); ?></p>
454 <?php } ?>
455 <?php
456 }
457
458 /**
459 * @return void
460 */
461 protected function step_bottom( $step ) {
462 ?>
463 </div>
464 </section>
465 <?php
466 }
467
468 /**
469 * Generate and output Connect step section HTML.
470 *
471 * @return void
472 */
473 protected function license_box( $step ) {
474 $this->step_top( $step );
475
476 if ( $step['complete'] ) {
477 ?>
478 <a href="#" class="<?php echo esc_attr( $step['button_class'] ); ?>">
479 <?php echo esc_html( $step['button_label'] ); ?>
480 </a>
481 <?php
482 } else {
483 FrmSettingsController::license_box();
484 }
485
486 $this->step_bottom( $step );
487 }
488
489 /**
490 * @return void
491 */
492 protected function show_plugin_install( $step ) {
493 $this->step_top( $step );
494
495 if ( ! isset( $step['error'] ) ) {
496 $rel = isset( $step['links'] ) ? $step['links'] : array();
497
498 ?>
499 <a rel="<?php echo esc_attr( implode( ',', $rel ) ); ?>" class="<?php echo esc_attr( $step['button_class'] ); ?>">
500 <?php echo esc_html( $step['button_label'] ); ?>
501 </a>
502 <?php
503 }
504
505 $this->step_bottom( $step );
506 }
507
508 /**
509 * @return void
510 */
511 protected function show_app_install( $step ) {
512 $is_complete = $step['complete'];
513 if ( ! empty( $this->form_options() ) && ! $is_complete ) {
514 $step['description'] = __( 'Select the form or view you would like to create.', 'formidable' );
515 }
516
517 $this->step_top( $step );
518
519 $api = new FrmFormApi();
520 $addons = $api->get_api_info();
521
522 $id = $this->download_id();
523 $has_file = isset( $addons[ $id ] ) && isset( $addons[ $id ]['beta'] );
524
525 if ( ! $step['current'] ) {
526 ?>
527 <a href="#" class="<?php echo esc_attr( $step['button_class'] ); ?>">
528 <?php echo esc_html( $step['button_label'] ); ?>
529 </a>
530 <?php
531
532 $this->step_bottom( $step );
533 return;
534 }
535
536 if ( ! $has_file ) {
537 echo '<p class="frm_error_style">' . esc_html__( 'We didn\'t find anything to import. Please contact our team.', 'formidable' ) . '</p>';
538 } elseif ( ! isset( $addons[ $id ]['beta']['package'] ) ) {
539 echo '<p class="frm_error_style">' . esc_html__( 'Looks like you may not have a current subscription for this solution. Please check your account.', 'formidable' ) . '</p>';
540 } else {
541 $xml = $addons[ $id ]['beta']['package'];
542 if ( is_array( $xml ) ) {
543 $xml = reset( $xml );
544 }
545
546 if ( isset( $step['nested'] ) ) {
547 echo '<fieldset id="frm-new-template" class="field-group">';
548 } else {
549 echo '<form name="frm-new-template" id="frm-new-template" method="post" class="field-group">';
550 }
551
552 ?>
553 <input type="hidden" name="link" id="frm_link" value="<?php echo esc_attr( $xml ); ?>" />
554 <input type="hidden" name="type" id="frm_action_type" value="frm_install_template" />
555 <input type="hidden" name="template_name" id="frm_template_name" value="" />
556 <input type="hidden" name="template_desc" id="frm_template_desc" value="" />
557 <input type="hidden" name="redirect" value="0" />
558 <input type="hidden" name="show_response" value="frm_install_error" />
559 <?php
560 $this->show_form_options( $xml );
561 $this->show_view_options();
562
563 if ( ! $this->is_complete( 'all' ) ) {
564 // Don't show on the settings page when complete.
565 $this->show_page_options();
566 }
567 ?>
568 <p>
569 <button <?php echo esc_html( isset( $step['nested'] ) ? '' : 'type="submit" ' ); ?>class="<?php echo esc_attr( $step['button_class'] ); ?>">
570 <?php echo esc_html( $step['button_label'] ); ?>
571 </button>
572 </p>
573 <p id="frm_install_error" class="frm_error_style frm_hidden"></p>
574 <?php
575 if ( isset( $step['nested'] ) ) {
576 echo '</fieldset>';
577 } else {
578 echo '</form>';
579 }
580 }//end if
581
582 $this->step_bottom( $step );
583 }
584
585 /**
586 * @return void
587 */
588 protected function show_form_options( $xml ) {
589 $this->show_import_options( $this->form_options(), 'form', $xml );
590 }
591
592 /**
593 * @return void
594 */
595 protected function show_view_options() {
596 $this->show_import_options( $this->view_options(), 'view' );
597 }
598
599 /**
600 * @param array $options
601 * @param string $importing
602 * @param string $xml
603 *
604 * @psalm-param 'form'|'view' $importing
605 *
606 * @return void
607 */
608 protected function show_import_options( $options, $importing, $xml = '' ) {
609 if ( empty( $options ) ) {
610 return;
611 }
612
613 $imported = $this->previously_imported_forms();
614 $count = count( $options );
615 foreach ( $options as $info ) {
616 // Count the number of options displayed for css.
617 if ( $count > 1 && ! isset( $info['img'] ) ) {
618 $count --;
619 }
620 }
621 $width = floor( ( 533 - ( ( $count - 1 ) * 20 ) ) / $count );
622 unset( $count );
623
624 $selected = false;
625
626 include( FrmAppHelper::plugin_path() . '/classes/views/solutions/_import.php' );
627 }
628
629 /**
630 * @return void
631 */
632 protected function show_page_options() {
633 $pages = $this->needed_pages();
634 if ( empty( $pages ) ) {
635 return;
636 }
637
638 echo '<h3>Choose New Page Title</h3>';
639 foreach ( $pages as $page ) {
640 ?>
641 <p>
642 <label for="pages_<?php echo esc_html( $page['type'] ); ?>">
643 <?php echo esc_html( $page['label'] ); ?>
644 </label>
645 <input type="text" name="pages[<?php echo esc_html( $page['type'] ); ?>]" value="<?php echo esc_attr( $page['name'] ); ?>" id="pages_<?php echo esc_html( $page['type'] ); ?>" required />
646 </p>
647 <?php
648 }
649 }
650
651 /**
652 * @return void
653 */
654 protected function show_page_links( $step ) {
655 if ( $step['current'] ) {
656 return;
657 }
658
659 $this->step_top( $step );
660
661 ?>
662 <a href="#" target="_blank" rel="noopener" id="frm-redirect-link" class="<?php echo esc_attr( $step['button_class'] ); ?>">
663 <?php echo esc_html( $step['button_label'] ); ?>
664 </a>
665 <?php
666
667 $this->step_bottom( $step );
668 }
669
670 /**
671 * Only show the content for the correct plugin.
672 *
673 * @return bool
674 */
675 protected function is_current_plugin() {
676 $to_redirect = get_transient( 'frm_activation_redirect' );
677 return $to_redirect === $this->plugin_slug && empty( $this->is_complete() );
678 }
679
680 /**
681 * Override this function to indicate when install is complete.
682 *
683 * @param int|string $count
684 *
685 * @psalm-param 'all'|1 $count
686 *
687 * @return bool
688 */
689 protected function is_complete( $count = 1 ) {
690 $imported = $this->previously_imported_forms();
691 if ( $count === 'all' ) {
692 return count( $imported ) >= count( $this->form_options() );
693 }
694 return ! empty( $imported );
695 }
696
697 /**
698 * Get an array of all of the forms that have been imported.
699 *
700 * @return array
701 */
702 protected function previously_imported_forms() {
703 $imported = array();
704 $forms = $this->form_options();
705 foreach ( $forms as $form ) {
706 $was_imported = isset( $form['form'] ) ? FrmForm::get_id_by_key( $form['form'] ) : false;
707 if ( $was_imported ) {
708 $imported[ $form['form'] ] = $was_imported;
709 }
710 }
711
712 return $imported;
713 }
714
715 /**
716 * In the new plugin has any dependencies, include them here.
717 *
718 * @return array
719 */
720 protected function required_plugins() {
721 return array();
722 }
723
724 /**
725 * This needs to be overridden.
726 *
727 * @return int
728 */
729 protected function download_id() {
730 return 0;
731 }
732
733 /**
734 * Give options for which forms to import.
735 *
736 * @return array
737 */
738 protected function form_options() {
739 /**
740 * Example:
741 * array(
742 * 'unique-key' => array(
743 * 'keys' => 'forms keys here',
744 * 'name' => 'displayed label here',
745 * 'img' => 'svg code',
746 * ),
747 * )
748 */
749 return array();
750 }
751
752 /**
753 * Give options for which view to use.
754 *
755 * @return array
756 */
757 protected function view_options() {
758 return array();
759 }
760
761 /**
762 * If the pages aren't imported automatically, set the page names.
763 *
764 * @return array
765 */
766 protected function needed_pages() {
767 /**
768 * Example:
769 * array(
770 * array(
771 * 'label' => 'Page Name',
772 * 'name' => 'Default name',
773 * 'type' => 'form' or 'view',
774 * ),
775 * )
776 */
777
778 return array();
779 }
780
781 /**
782 * @return void
783 */
784 private function css() {
785 wp_enqueue_style( 'formidable-pro-fields' );
786 ?>
787 <style>
788 #frm-welcome *, #frm-welcome *::before, #frm-welcome *::after {
789 -webkit-box-sizing: border-box;
790 -moz-box-sizing: border-box;
791 box-sizing: border-box;
792 }
793 #frm-welcome{
794 width: 700px;
795 margin: 0 auto;
796 }
797 #frm-welcome p {
798 font-size: 15px;
799 }
800 #frm-welcome section{
801 margin: 50px 0;
802 text-align: left;
803 clear: both;
804 }
805 #frm-welcome .top{
806 text-align: center;
807 }
808 .frm-smtp-logos {
809 margin-bottom: 38px;
810 }
811 .frm-smtp-logos svg {
812 vertical-align: middle;
813 }
814 #frm-welcome .top h1 {
815 font-size: 26px;
816 font-weight: 600;
817 margin-bottom: 0;
818 padding: 0;
819 }
820 #frm-welcome .top p {
821 font-size: 17px;
822 color: #777;
823 margin-top: .5em;
824 }
825 #frm-welcome .screenshot ul {
826 display: inline-block;
827 margin: 0 0 0 30px;
828 list-style-type: none;
829 max-width: calc(100% - 350px);
830 }
831 #frm-welcome .screenshot li {
832 margin: 16px 0;
833 padding: 0;
834 font-size: 15px;
835 color: #777;
836 }
837 #frm-welcome .screenshot .cont img {
838 max-width: 100%;
839 display: block;
840 }
841 #frm-welcome .screenshot .cont {
842 display: inline-block;
843 position: relative;
844 width: 315px;
845 padding: 5px;
846 background-color: #fff;
847 border-radius: 3px;
848 }
849 #frm-welcome .step,
850 #frm-welcome .screenshot .cont {
851 -webkit-box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.05);
852 -moz-box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.05);
853 box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.05);
854 }
855 #frm-welcome .step {
856 background-color: #F9F9F9;
857 border: 1px solid #E5E5E5;
858 margin: 0 0 25px;
859 }
860 #frm-welcome .screenshot > *,
861 #frm-welcome .step > * {
862 vertical-align: middle;
863 }
864 #frm-welcome .step p {
865 font-size: 16px;
866 color: #777777;
867 }
868 #frm-welcome .step .num {
869 display: inline-block;
870 position: relative;
871 width: 100px;
872 height: 50px;
873 text-align: center;
874 }
875 #frm-welcome .step > div {
876 display: inline-block;
877 width: calc(100% - 104px);
878 background-color: #fff;
879 padding: 30px;
880 border-left: 1px solid #eee;
881 }
882 #frm-welcome .step h3.frm-step-heading {
883 font-size: 24px;
884 line-height: 22px;
885 margin-top: 0;
886 margin-bottom: 15px;
887 }
888 #frm-welcome .button.disabled {
889 cursor: default;
890 }
891 #frm-welcome #frm-using-lite {
892 display: none;
893 }
894 </style>
895 <?php
896 }
897
898 }
899