Page Builder by SiteOrigin - Version 2.10.4

Version Description

  • 3 April 2019 =
  • New welcome page.
  • Include row style wrapper in cell CSS direct child selectors.
Download this release

Release Info

Developer gpriday
Plugin Icon 128x128 Page Builder by SiteOrigin
Version 2.10.4
Comparing to
See all releases

Code changes from version 2.10.3 to 2.10.4

inc/css-builder.php CHANGED
@@ -97,29 +97,43 @@ class SiteOrigin_Panels_Css_Builder {
97
  * @param bool $specify_layout Sometimes for CSS specificity, we need to include the layout ID.
98
  */
99
  public function add_cell_css( $li, $ri = false, $ci = false, $sub_selector = '', $attributes = array(), $resolution = 1920, $specify_layout = false ) {
100
- $selector = array();
101
 
102
  if ( $ri === false && $ci === false ) {
103
  // This applies to all cells in the layout
104
- $selector[] = '#pl-' . $li;
105
- $selector[] = '.panel-grid-cell';
106
  } elseif ( $ri !== false && $ci === false ) {
107
  // This applies to all cells in a row
 
 
108
  if ( $specify_layout ) {
109
- $selector[] = '#pl-' . $li;
110
  }
111
- $selector[] = is_string( $ri ) ? ( '#' . $ri ) : '#pg-' . $li . '-' . $ri;
112
- $selector[] = '> .panel-grid-cell';
 
 
 
 
 
 
 
 
 
 
113
  } elseif ( $ri !== false && $ci !== false ) {
114
  // This applies to a specific cell
115
  if ( $specify_layout ) {
116
- $selector[] = '#pl-' . $li;
117
  }
118
- $selector[] = '#pgc-' . $li . '-' . $ri . '-' . $ci;
119
  }
120
 
121
- $selector = implode( ' ', $selector );
122
- $selector = $this->add_sub_selector( $selector, $sub_selector );
 
 
123
 
124
  // Add this to the CSS array
125
  $this->add_css( $selector, $attributes, $resolution );
97
  * @param bool $specify_layout Sometimes for CSS specificity, we need to include the layout ID.
98
  */
99
  public function add_cell_css( $li, $ri = false, $ci = false, $sub_selector = '', $attributes = array(), $resolution = 1920, $specify_layout = false ) {
100
+ $selector_parts = array();
101
 
102
  if ( $ri === false && $ci === false ) {
103
  // This applies to all cells in the layout
104
+ $selector_parts[] = '#pl-' . $li;
105
+ $selector_parts[] = '.panel-grid-cell';
106
  } elseif ( $ri !== false && $ci === false ) {
107
  // This applies to all cells in a row
108
+ $sel = '';
109
+
110
  if ( $specify_layout ) {
111
+ $sel = '#pl-' . $li . ' ';
112
  }
113
+ $sel .= is_string( $ri ) ? ( '#' . $ri ) : '#pg-' . $li . '-' . $ri;
114
+
115
+ // If row styles are set, there's a row style wrapper between the row and the cell, so we need to include
116
+ // the selector for both. This is a somewhat hacky fix, but trying to prevent further breakage in existing
117
+ // layouts.
118
+ $sel_with_style = ', ' . $sel . ' > .panel-row-style';
119
+
120
+ $sel .= ' > .panel-grid-cell';
121
+ $sel_with_style .= ' > .panel-grid-cell';
122
+
123
+ $selector_parts[] = $sel;
124
+ $selector_parts[] = $sel_with_style;
125
  } elseif ( $ri !== false && $ci !== false ) {
126
  // This applies to a specific cell
127
  if ( $specify_layout ) {
128
+ $selector_parts[] = '#pl-' . $li;
129
  }
130
+ $selector_parts[] = '#pgc-' . $li . '-' . $ri . '-' . $ci;
131
  }
132
 
133
+ $selector = implode( ' ', $selector_parts );
134
+ if ( ! empty( $sub_selector ) ) {
135
+ $selector = $this->add_sub_selector( $selector, $sub_selector );
136
+ }
137
 
138
  // Add this to the CSS array
139
  $this->add_css( $selector, $attributes, $resolution );
inc/functions.php CHANGED
@@ -1,106 +1,106 @@
1
- <?php
2
- /**
3
- * Contains several legacy and shorthand functions
4
- *
5
- * @since 3.0
6
- */
7
-
8
- /**
9
- * @return mixed|void Are we currently viewing the home page
10
- */
11
- function siteorigin_panels_is_home() {
12
- return SiteOrigin_Panels::is_home();
13
- }
14
-
15
- /**
16
- * Check if we're currently viewing a page builder page.
17
- *
18
- * @param bool $can_edit Also check if the user can edit this page
19
- *
20
- * @return bool
21
- */
22
- function siteorigin_panels_is_panel( $can_edit = false ) {
23
- return SiteOrigin_Panels::is_panel( $can_edit );
24
- }
25
-
26
-
27
- function siteorigin_panels_get_home_page_data() {
28
- return SiteOrigin_Panels::single()->get_home_page_data();
29
- }
30
-
31
- /**
32
- * Render Page Builder content
33
- *
34
- * @param bool $post_id
35
- * @param bool $enqueue_css
36
- * @param bool $panels_data
37
- *
38
- * @return string The HTML content.
39
- */
40
- function siteorigin_panels_render( $post_id = false, $enqueue_css = true, $panels_data = false ) {
41
- return SiteOrigin_Panels::renderer()->render( $post_id, $enqueue_css, $panels_data );
42
- }
43
-
44
- /**
45
- * Generate the CSS for the page layout.
46
- *
47
- * @param $post_id
48
- * @param $panels_data
49
- * @return string
50
- */
51
- function siteorigin_panels_generate_css($post_id, $panels_data = false){
52
- return SiteOrigin_Panels::renderer()->generate_css( $post_id, $panels_data );
53
- }
54
-
55
- /**
56
- * Legacy function to process raw widgets.
57
- *
58
- * @param $widgets
59
- * @param $old_widgets
60
- * @param $escape_classes
61
- *
62
- * @return array
63
- */
64
- function siteorigin_panels_process_raw_widgets( $widgets, $old_widgets = false, $escape_classes = false ) {
65
- return SiteOrigin_Panels_Admin::single()->process_raw_widgets( $widgets, $old_widgets, $escape_classes );
66
- }
67
-
68
- function siteorigin_panels_the_widget( $widget_info, $instance, $grid, $cell, $panel, $is_first, $is_last, $post_id = false, $style_wrapper = '' ) {
69
- SiteOrigin_Panels::renderer()->the_widget( $widget_info, $instance, $grid, $cell, $panel, $is_first, $is_last, $post_id, $style_wrapper );
70
- }
71
-
72
- /**
73
- * Get a setting with the given key.
74
- *
75
- * @param string $key
76
- *
77
- * @return array|bool|mixed|null
78
- */
79
- function siteorigin_panels_setting( $key = '' ) {
80
- return SiteOrigin_Panels_Settings::single()->get( $key );
81
- }
82
-
83
- function siteorigin_panels_plugin_activation_install_url( $plugin, $plugin_name, $source = false ) {
84
- return SiteOrigin_Panels_Admin_Widgets_Bundle::install_url( $plugin, $plugin_name, $source );
85
- }
86
-
87
- /**
88
- * A null function for compatibility with aTheme themes.
89
- *
90
- * @return bool
91
- */
92
- function siteorigin_panels_activate(){
93
- return false;
94
- }
95
-
96
-
97
- /**
98
- * Returns the base URL of our widget with `$path` appended.
99
- *
100
- * @param string $path Extra path to append to the end of the URL.
101
- *
102
- * @return string Base URL of the widget, with $path appended.
103
- */
104
- function siteorigin_panels_url( $path = '' ) {
105
- return plugins_url( 'siteorigin-panels/' . $path );
106
- }
1
+ <?php
2
+ /**
3
+ * Contains several legacy and shorthand functions
4
+ *
5
+ * @since 3.0
6
+ */
7
+
8
+ /**
9
+ * @return mixed|void Are we currently viewing the home page
10
+ */
11
+ function siteorigin_panels_is_home() {
12
+ return SiteOrigin_Panels::is_home();
13
+ }
14
+
15
+ /**
16
+ * Check if we're currently viewing a page builder page.
17
+ *
18
+ * @param bool $can_edit Also check if the user can edit this page
19
+ *
20
+ * @return bool
21
+ */
22
+ function siteorigin_panels_is_panel( $can_edit = false ) {
23
+ return SiteOrigin_Panels::is_panel( $can_edit );
24
+ }
25
+
26
+
27
+ function siteorigin_panels_get_home_page_data() {
28
+ return SiteOrigin_Panels::single()->get_home_page_data();
29
+ }
30
+
31
+ /**
32
+ * Render Page Builder content
33
+ *
34
+ * @param bool $post_id
35
+ * @param bool $enqueue_css
36
+ * @param bool $panels_data
37
+ *
38
+ * @return string The HTML content.
39
+ */
40
+ function siteorigin_panels_render( $post_id = false, $enqueue_css = true, $panels_data = false ) {
41
+ return SiteOrigin_Panels::renderer()->render( $post_id, $enqueue_css, $panels_data );
42
+ }
43
+
44
+ /**
45
+ * Generate the CSS for the page layout.
46
+ *
47
+ * @param $post_id
48
+ * @param $panels_data
49
+ * @return string
50
+ */
51
+ function siteorigin_panels_generate_css($post_id, $panels_data = false){
52
+ return SiteOrigin_Panels::renderer()->generate_css( $post_id, $panels_data );
53
+ }
54
+
55
+ /**
56
+ * Legacy function to process raw widgets.
57
+ *
58
+ * @param $widgets
59
+ * @param $old_widgets
60
+ * @param $escape_classes
61
+ *
62
+ * @return array
63
+ */
64
+ function siteorigin_panels_process_raw_widgets( $widgets, $old_widgets = false, $escape_classes = false ) {
65
+ return SiteOrigin_Panels_Admin::single()->process_raw_widgets( $widgets, $old_widgets, $escape_classes );
66
+ }
67
+
68
+ function siteorigin_panels_the_widget( $widget_info, $instance, $grid, $cell, $panel, $is_first, $is_last, $post_id = false, $style_wrapper = '' ) {
69
+ SiteOrigin_Panels::renderer()->the_widget( $widget_info, $instance, $grid, $cell, $panel, $is_first, $is_last, $post_id, $style_wrapper );
70
+ }
71
+
72
+ /**
73
+ * Get a setting with the given key.
74
+ *
75
+ * @param string $key
76
+ *
77
+ * @return array|bool|mixed|null
78
+ */
79
+ function siteorigin_panels_setting( $key = '' ) {
80
+ return SiteOrigin_Panels_Settings::single()->get( $key );
81
+ }
82
+
83
+ function siteorigin_panels_plugin_activation_install_url( $plugin, $plugin_name, $source = false ) {
84
+ return SiteOrigin_Panels_Admin_Widgets_Bundle::install_url( $plugin, $plugin_name, $source );
85
+ }
86
+
87
+ /**
88
+ * A null function for compatibility with aTheme themes.
89
+ *
90
+ * @return bool
91
+ */
92
+ function siteorigin_panels_activate(){
93
+ return false;
94
+ }
95
+
96
+
97
+ /**
98
+ * Returns the base URL of our widget with `$path` appended.
99
+ *
100
+ * @param string $path Extra path to append to the end of the URL.
101
+ *
102
+ * @return string Base URL of the widget, with $path appended.
103
+ */
104
+ function siteorigin_panels_url( $path = '' ) {
105
+ return plugins_url( 'siteorigin-panels/' . $path );
106
+ }
inc/renderer.php CHANGED
@@ -207,12 +207,9 @@ class SiteOrigin_Panels_Renderer {
207
  'flex-direction' => $collapse_order == 'left-top' ? 'column' : 'column-reverse',
208
  ), $panels_mobile_width );
209
 
210
- $css->add_cell_css( $post_id, $ri, false, '', array(
211
- 'margin-right' => 0,
212
- ), $panels_mobile_width );
213
-
214
  $css->add_cell_css( $post_id, $ri, false, '', array(
215
  'width' => '100%',
 
216
  ), $panels_mobile_width );
217
  }
218
 
207
  'flex-direction' => $collapse_order == 'left-top' ? 'column' : 'column-reverse',
208
  ), $panels_mobile_width );
209
 
 
 
 
 
210
  $css->add_cell_css( $post_id, $ri, false, '', array(
211
  'width' => '100%',
212
+ 'margin-right' => 0,
213
  ), $panels_mobile_width );
214
  }
215
 
inc/sidebars-emulator.php CHANGED
@@ -65,17 +65,26 @@ class SiteOrigin_Panels_Sidebars_Emulator {
65
  * Register all the current widgets so we can filter the get_option('widget_...') values to add instances
66
  */
67
  function register_widgets() {
 
 
 
68
  // Get the ID of the current post
69
- $post_id = url_to_postid( add_query_arg( false, false ) );
 
 
 
 
 
70
  if ( empty( $post_id ) ) {
71
  // Maybe this is the home page
72
- $current_url_path = parse_url( add_query_arg( false, false ), PHP_URL_PATH );
73
  $home_url_path = parse_url( trailingslashit( home_url() ), PHP_URL_PATH );
74
 
75
  if ( $current_url_path === $home_url_path && get_option( 'page_on_front' ) != 0 ) {
76
  $post_id = absint( get_option( 'page_on_front' ) );
77
  }
78
  }
 
79
  if ( empty( $post_id ) ) {
80
  return;
81
  }
65
  * Register all the current widgets so we can filter the get_option('widget_...') values to add instances
66
  */
67
  function register_widgets() {
68
+ $current_url = add_query_arg( false, false );
69
+ $cache_key = md5( $current_url );
70
+
71
  // Get the ID of the current post
72
+ $post_id = wp_cache_get( $cache_key, 'siteorigin_url_to_postid' );
73
+ if ( false === $post_id ) {
74
+ $post_id = url_to_postid( $current_url );
75
+ wp_cache_set( $cache_key, $post_id, 'siteorigin_url_to_postid', 3 * HOUR_IN_SECONDS );
76
+ }
77
+
78
  if ( empty( $post_id ) ) {
79
  // Maybe this is the home page
80
+ $current_url_path = parse_url( $current_url, PHP_URL_PATH );
81
  $home_url_path = parse_url( trailingslashit( home_url() ), PHP_URL_PATH );
82
 
83
  if ( $current_url_path === $home_url_path && get_option( 'page_on_front' ) != 0 ) {
84
  $post_id = absint( get_option( 'page_on_front' ) );
85
  }
86
  }
87
+
88
  if ( empty( $post_id ) ) {
89
  return;
90
  }
js/siteorigin-panels-2104.js ADDED
@@ -0,0 +1,7447 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
2
+ var panels = window.panels;
3
+
4
+ module.exports = Backbone.Collection.extend( {
5
+ model: panels.model.cell,
6
+
7
+ initialize: function () {
8
+ },
9
+
10
+ /**
11
+ * Get the total weight for the cells in this collection.
12
+ * @returns {number}
13
+ */
14
+ totalWeight: function () {
15
+ var totalWeight = 0;
16
+ this.each( function ( cell ) {
17
+ totalWeight += cell.get( 'weight' );
18
+ } );
19
+
20
+ return totalWeight;
21
+ },
22
+
23
+ } );
24
+
25
+ },{}],2:[function(require,module,exports){
26
+ var panels = window.panels;
27
+
28
+ module.exports = Backbone.Collection.extend( {
29
+ model: panels.model.historyEntry,
30
+
31
+ /**
32
+ * The builder model
33
+ */
34
+ builder: null,
35
+
36
+ /**
37
+ * The maximum number of items in the history
38
+ */
39
+ maxSize: 12,
40
+
41
+ initialize: function () {
42
+ this.on( 'add', this.onAddEntry, this );
43
+ },
44
+
45
+ /**
46
+ * Add an entry to the collection.
47
+ *
48
+ * @param text The text that defines the action taken to get to this
49
+ * @param data
50
+ */
51
+ addEntry: function ( text, data ) {
52
+
53
+ if ( _.isEmpty( data ) ) {
54
+ data = this.builder.getPanelsData();
55
+ }
56
+
57
+ var entry = new panels.model.historyEntry( {
58
+ text: text,
59
+ data: JSON.stringify( data ),
60
+ time: parseInt( new Date().getTime() / 1000 ),
61
+ collection: this
62
+ } );
63
+
64
+ this.add( entry );
65
+ },
66
+
67
+ /**
68
+ * Resize the collection so it's not bigger than this.maxSize
69
+ */
70
+ onAddEntry: function ( entry ) {
71
+
72
+ if ( this.models.length > 1 ) {
73
+ var lastEntry = this.at( this.models.length - 2 );
74
+
75
+ if (
76
+ (
77
+ entry.get( 'text' ) === lastEntry.get( 'text' ) && entry.get( 'time' ) - lastEntry.get( 'time' ) < 15
78
+ ) ||
79
+ (
80
+ entry.get( 'data' ) === lastEntry.get( 'data' )
81
+ )
82
+ ) {
83
+ // If both entries have the same text and are within 20 seconds of each other, or have the same data, then remove most recent
84
+ this.remove( entry );
85
+ lastEntry.set( 'count', lastEntry.get( 'count' ) + 1 );
86
+ }
87
+ }
88
+
89
+ // Make sure that there are not to many entries in this collection
90
+ while ( this.models.length > this.maxSize ) {
91
+ this.shift();
92
+ }
93
+ }
94
+ } );
95
+
96
+ },{}],3:[function(require,module,exports){
97
+ var panels = window.panels;
98
+
99
+ module.exports = Backbone.Collection.extend( {
100
+ model: panels.model.row,
101
+
102
+ /**
103
+ * Destroy all the rows in this collection
104
+ */
105
+ empty: function () {
106
+ var model;
107
+ do {
108
+ model = this.collection.first();
109
+ if ( ! model ) {
110
+ break;
111
+ }
112
+
113
+ model.destroy();
114
+ } while ( true );
115
+ }
116
+
117
+ } );
118
+
119
+ },{}],4:[function(require,module,exports){
120
+ var panels = window.panels;
121
+
122
+ module.exports = Backbone.Collection.extend( {
123
+ model: panels.model.widget,
124
+
125
+ initialize: function () {
126
+
127
+ }
128
+
129
+ } );
130
+
131
+ },{}],5:[function(require,module,exports){
132
+ var panels = window.panels, $ = jQuery;
133
+
134
+ module.exports = panels.view.dialog.extend( {
135
+ dialogClass: 'so-panels-dialog-add-builder',
136
+
137
+ render: function () {
138
+ // Render the dialog and attach it to the builder interface
139
+ this.renderDialog( this.parseDialogContent( $( '#siteorigin-panels-dialog-builder' ).html(), {} ) );
140
+ this.$( '.so-content .siteorigin-panels-builder' ).append( this.builder.$el );
141
+ },
142
+
143
+ initializeDialog: function () {
144
+ var thisView = this;
145
+ this.once( 'open_dialog_complete', function () {
146
+ thisView.builder.initSortable();
147
+ } );
148
+
149
+ this.on( 'open_dialog_complete', function () {
150
+ thisView.builder.trigger( 'builder_resize' );
151
+ } );
152
+ }
153
+ } );
154
+
155
+ },{}],6:[function(require,module,exports){
156
+ var panels = window.panels, $ = jQuery;
157
+
158
+ module.exports = panels.view.dialog.extend( {
159
+
160
+ historyEntryTemplate: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-dialog-history-entry' ).html() ) ),
161
+
162
+ entries: {},
163
+ currentEntry: null,
164
+ revertEntry: null,
165
+ selectedEntry: null,
166
+
167
+ previewScrollTop: null,
168
+
169
+ dialogClass: 'so-panels-dialog-history',
170
+ dialogIcon: 'history',
171
+
172
+ events: {
173
+ 'click .so-close': 'closeDialog',
174
+ 'click .so-restore': 'restoreSelectedEntry'
175
+ },
176
+
177
+ initializeDialog: function () {
178
+ this.entries = new panels.collection.historyEntries();
179
+
180
+ this.on( 'open_dialog', this.setCurrentEntry, this );
181
+ this.on( 'open_dialog', this.renderHistoryEntries, this );
182
+ },
183
+
184
+ render: function () {
185
+ var thisView = this;
186
+
187
+ // Render the dialog and attach it to the builder interface
188
+ this.renderDialog( this.parseDialogContent( $( '#siteorigin-panels-dialog-history' ).html(), {} ) );
189
+
190
+ this.$( 'iframe.siteorigin-panels-history-iframe' ).load( function () {
191
+ var $$ = $( this );
192
+ $$.show();
193
+
194
+ $$.contents().scrollTop( thisView.previewScrollTop );
195
+ } );
196
+ },
197
+
198
+ /**
199
+ * Set the original entry. This should be set when creating the dialog.
200
+ *
201
+ * @param {panels.model.builder} builder
202
+ */
203
+ setRevertEntry: function ( builder ) {
204
+ this.revertEntry = new panels.model.historyEntry( {
205
+ data: JSON.stringify( builder.getPanelsData() ),
206
+ time: parseInt( new Date().getTime() / 1000 )
207
+ } );
208
+ },
209
+
210
+ /**
211
+ * This is triggered when the dialog is opened.
212
+ */
213
+ setCurrentEntry: function () {
214
+ this.currentEntry = new panels.model.historyEntry( {
215
+ data: JSON.stringify( this.builder.model.getPanelsData() ),
216
+ time: parseInt( new Date().getTime() / 1000 )
217
+ } );
218
+
219
+ this.selectedEntry = this.currentEntry;
220
+ this.previewEntry( this.currentEntry );
221
+ this.$( '.so-buttons .so-restore' ).addClass( 'disabled' );
222
+ },
223
+
224
+ /**
225
+ * Render the history entries in the sidebar
226
+ */
227
+ renderHistoryEntries: function () {
228
+ // Set up an interval that will display the time since every 10 seconds
229
+ var thisView = this;
230
+
231
+ var c = this.$( '.history-entries' ).empty();
232
+
233
+ if ( this.currentEntry.get( 'data' ) !== this.revertEntry.get( 'data' ) || ! _.isEmpty( this.entries.models ) ) {
234
+ $( this.historyEntryTemplate( {title: panelsOptions.loc.history.revert, count: 1} ) )
235
+ .data( 'historyEntry', this.revertEntry )
236
+ .prependTo( c );
237
+ }
238
+
239
+ // Now load all the entries in this.entries
240
+ this.entries.each( function ( entry ) {
241
+
242
+ var html = thisView.historyEntryTemplate( {
243
+ title: panelsOptions.loc.history[entry.get( 'text' )],
244
+ count: entry.get( 'count' )
245
+ } );
246
+
247
+ $( html )
248
+ .data( 'historyEntry', entry )
249
+ .prependTo( c );
250
+ } );
251
+
252
+
253
+ $( this.historyEntryTemplate( {title: panelsOptions.loc.history['current'], count: 1} ) )
254
+ .data( 'historyEntry', this.currentEntry )
255
+ .addClass( 'so-selected' )
256
+ .prependTo( c );
257
+
258
+ // Handle loading and selecting
259
+ c.find( '.history-entry' ).click( function () {
260
+ var $$ = jQuery( this );
261
+ c.find( '.history-entry' ).not( $$ ).removeClass( 'so-selected' );
262
+ $$.addClass( 'so-selected' );
263
+
264
+ var entry = $$.data( 'historyEntry' );
265
+
266
+ thisView.selectedEntry = entry;
267
+
268
+ if ( thisView.selectedEntry.cid !== thisView.currentEntry.cid ) {
269
+ thisView.$( '.so-buttons .so-restore' ).removeClass( 'disabled' );
270
+ } else {
271
+ thisView.$( '.so-buttons .so-restore' ).addClass( 'disabled' );
272
+ }
273
+
274
+ thisView.previewEntry( entry );
275
+ } );
276
+
277
+ this.updateEntryTimes();
278
+ },
279
+
280
+ /**
281
+ * Preview an entry
282
+ *
283
+ * @param entry
284
+ */
285
+ previewEntry: function ( entry ) {
286
+ var iframe = this.$( 'iframe.siteorigin-panels-history-iframe' );
287
+ iframe.hide();
288
+ this.previewScrollTop = iframe.contents().scrollTop();
289
+
290
+ this.$( 'form.history-form input[name="live_editor_panels_data"]' ).val( entry.get( 'data' ) );
291
+ this.$( 'form.history-form input[name="live_editor_post_ID"]' ).val( this.builder.config.postId );
292
+ this.$( 'form.history-form' ).submit();
293
+ },
294
+
295
+ /**
296
+ * Restore the current entry
297
+ */
298
+ restoreSelectedEntry: function () {
299
+
300
+ if ( this.$( '.so-buttons .so-restore' ).hasClass( 'disabled' ) ) {
301
+ return false;
302
+ }
303
+
304
+ if ( this.currentEntry.get( 'data' ) === this.selectedEntry.get( 'data' ) ) {
305
+ this.closeDialog();
306
+ return false;
307
+ }
308
+
309
+ // Add an entry for this restore event
310
+ if ( this.selectedEntry.get( 'text' ) !== 'restore' ) {
311
+ this.builder.addHistoryEntry( 'restore', this.builder.model.getPanelsData() );
312
+ }
313
+
314
+ this.builder.model.loadPanelsData( JSON.parse( this.selectedEntry.get( 'data' ) ) );
315
+
316
+ this.closeDialog();
317
+
318
+ return false;
319
+ },
320
+
321
+ /**
322
+ * Update the entry times for the list of entries down the side
323
+ */
324
+ updateEntryTimes: function () {
325
+ var thisView = this;
326
+
327
+ this.$( '.history-entries .history-entry' ).each( function () {
328
+ var $$ = jQuery( this );
329
+
330
+ var time = $$.find( '.timesince' );
331
+ var entry = $$.data( 'historyEntry' );
332
+
333
+ time.html( thisView.timeSince( entry.get( 'time' ) ) );
334
+ } );
335
+ },
336
+
337
+ /**
338
+ * Gets the time since as a nice string.
339
+ *
340
+ * @param date
341
+ */
342
+ timeSince: function ( time ) {
343
+ var diff = parseInt( new Date().getTime() / 1000 ) - time;
344
+
345
+ var parts = [];
346
+ var interval;
347
+
348
+ // There are 3600 seconds in an hour
349
+ if ( diff > 3600 ) {
350
+ interval = Math.floor( diff / 3600 );
351
+ if ( interval === 1 ) {
352
+ parts.push( panelsOptions.loc.time.hour.replace( '%d', interval ) );
353
+ } else {
354
+ parts.push( panelsOptions.loc.time.hours.replace( '%d', interval ) );
355
+ }
356
+ diff -= interval * 3600;
357
+ }
358
+
359
+ // There are 60 seconds in a minute
360
+ if ( diff > 60 ) {
361
+ interval = Math.floor( diff / 60 );
362
+ if ( interval === 1 ) {
363
+ parts.push( panelsOptions.loc.time.minute.replace( '%d', interval ) );
364
+ } else {
365
+ parts.push( panelsOptions.loc.time.minutes.replace( '%d', interval ) );
366
+ }
367
+ diff -= interval * 60;
368
+ }
369
+
370
+ if ( diff > 0 ) {
371
+ if ( diff === 1 ) {
372
+ parts.push( panelsOptions.loc.time.second.replace( '%d', diff ) );
373
+ } else {
374
+ parts.push( panelsOptions.loc.time.seconds.replace( '%d', diff ) );
375
+ }
376
+ }
377
+
378
+ // Return the amount of time ago
379
+ return _.isEmpty( parts ) ? panelsOptions.loc.time.now : panelsOptions.loc.time.ago.replace( '%s', parts.slice( 0, 2 ).join( ', ' ) );
380
+
381
+ }
382
+
383
+ } );
384
+
385
+ },{}],7:[function(require,module,exports){
386
+ var panels = window.panels, $ = jQuery;
387
+
388
+ module.exports = panels.view.dialog.extend( {
389
+
390
+ directoryTemplate: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-directory-items' ).html() ) ),
391
+
392
+ builder: null,
393
+ dialogClass: 'so-panels-dialog-prebuilt-layouts',
394
+ dialogIcon: 'layouts',
395
+
396
+ layoutCache: {},
397
+ currentTab: false,
398
+ directoryPage: 1,
399
+
400
+ events: {
401
+ 'click .so-close': 'closeDialog',
402
+ 'click .so-sidebar-tabs li a': 'tabClickHandler',
403
+ 'click .so-content .layout': 'layoutClickHandler',
404
+ 'keyup .so-sidebar-search': 'searchHandler',
405
+
406
+ // The directory items
407
+ 'click .so-screenshot, .so-title': 'directoryItemClickHandler'
408
+ },
409
+
410
+ /**
411
+ * Initialize the prebuilt dialog.
412
+ */
413
+ initializeDialog: function () {
414
+ var thisView = this;
415
+
416
+ this.on( 'open_dialog', function () {
417
+ thisView.$( '.so-sidebar-tabs li a' ).first().click();
418
+ thisView.$( '.so-status' ).removeClass( 'so-panels-loading' );
419
+ } );
420
+
421
+ this.on( 'button_click', this.toolbarButtonClick, this );
422
+ },
423
+
424
+ /**
425
+ * Render the prebuilt layouts dialog
426
+ */
427
+ render: function () {
428
+ this.renderDialog( this.parseDialogContent( $( '#siteorigin-panels-dialog-prebuilt' ).html(), {} ) );
429
+
430
+ this.initToolbar();
431
+ },
432
+
433
+ /**
434
+ *
435
+ * @param e
436
+ * @return {boolean}
437
+ */
438
+ tabClickHandler: function ( e ) {
439
+ e.preventDefault();
440
+ // Reset selected item state when changing tabs
441
+ this.selectedLayoutItem = null;
442
+ this.uploadedLayout = null;
443
+ this.updateButtonState( false );
444
+
445
+ this.$( '.so-sidebar-tabs li' ).removeClass( 'tab-active' );
446
+
447
+ var $$ = $( e.target );
448
+ var tab = $$.attr( 'href' ).split( '#' )[1];
449
+ $$.parent().addClass( 'tab-active' );
450
+
451
+ var thisView = this;
452
+
453
+ // Empty everything
454
+ this.$( '.so-content' ).empty();
455
+
456
+ thisView.currentTab = tab;
457
+ if ( tab == 'import' ) {
458
+ this.displayImportExport();
459
+ } else {
460
+ this.displayLayoutDirectory( '', 1, tab );
461
+ }
462
+
463
+ thisView.$( '.so-sidebar-search' ).val( '' );
464
+ },
465
+
466
+ /**
467
+ * Display and setup the import/export form
468
+ */
469
+ displayImportExport: function () {
470
+ var c = this.$( '.so-content' ).empty().removeClass( 'so-panels-loading' );
471
+ c.html( $( '#siteorigin-panels-dialog-prebuilt-importexport' ).html() );
472
+
473
+ var thisView = this;
474
+ var uploadUi = thisView.$( '.import-upload-ui' );
475
+
476
+ // Create the uploader
477
+ var uploader = new plupload.Uploader( {
478
+ runtimes: 'html5,silverlight,flash,html4',
479
+
480
+ browse_button: uploadUi.find( '.file-browse-button' ).get( 0 ),
481
+ container: uploadUi.get( 0 ),
482
+ drop_element: uploadUi.find( '.drag-upload-area' ).get( 0 ),
483
+
484
+ file_data_name: 'panels_import_data',
485
+ multiple_queues: false,
486
+ max_file_size: panelsOptions.plupload.max_file_size,
487
+ url: panelsOptions.plupload.url,
488
+ flash_swf_url: panelsOptions.plupload.flash_swf_url,
489
+ silverlight_xap_url: panelsOptions.plupload.silverlight_xap_url,
490
+ filters: [
491
+ {title: panelsOptions.plupload.filter_title, extensions: 'json'}
492
+ ],
493
+
494
+ multipart_params: {
495
+ action: 'so_panels_import_layout'
496
+ },
497
+
498
+ init: {
499
+ PostInit: function ( uploader ) {
500
+ if ( uploader.features.dragdrop ) {
501
+ uploadUi.addClass( 'has-drag-drop' );
502
+ }
503
+ uploadUi.find( '.progress-precent' ).css( 'width', '0%' );
504
+ },
505
+ FilesAdded: function ( uploader ) {
506
+ uploadUi.find( '.file-browse-button' ).blur();
507
+ uploadUi.find( '.drag-upload-area' ).removeClass( 'file-dragover' );
508
+ uploadUi.find( '.progress-bar' ).fadeIn( 'fast' );
509
+ thisView.$( '.js-so-selected-file' ).text( panelsOptions.loc.prebuilt_loading );
510
+ uploader.start();
511
+ },
512
+ UploadProgress: function ( uploader, file ) {
513
+ uploadUi.find( '.progress-precent' ).css( 'width', file.percent + '%' );
514
+ },
515
+ FileUploaded: function ( uploader, file, response ) {
516
+ var layout = JSON.parse( response.response );
517
+ if ( ! _.isUndefined( layout.widgets ) ) {
518
+
519
+ thisView.uploadedLayout = layout;
520
+ uploadUi.find( '.progress-bar' ).hide();
521
+ thisView.$( '.js-so-selected-file' ).text(
522
+ panelsOptions.loc.ready_to_insert.replace( '%s', file.name )
523
+ );
524
+ thisView.updateButtonState( true );
525
+ } else {
526
+ alert( panelsOptions.plupload.error_message );
527
+ }
528
+ },
529
+ Error: function () {
530
+ alert( panelsOptions.plupload.error_message );
531
+ }
532
+ }
533
+ } );
534
+ uploader.init();
535
+
536
+ if ( /Edge\/\d./i.test(navigator.userAgent) ){
537
+ // A very dirty fix for a Microsoft Edge issue.
538
+ // TODO find a more elegant fix if Edge gains market share
539
+ setTimeout( function(){
540
+ uploader.refresh();
541
+ }, 250 );
542
+ }
543
+
544
+ // This is
545
+ uploadUi.find( '.drag-upload-area' )
546
+ .on( 'dragover', function () {
547
+ $( this ).addClass( 'file-dragover' );
548
+ } )
549
+ .on( 'dragleave', function () {
550
+ $( this ).removeClass( 'file-dragover' );
551
+ } );
552
+
553
+ // Handle exporting the file
554
+ c.find( '.so-export' ).submit( function ( e ) {
555
+ var $$ = $( this );
556
+ var panelsData = thisView.builder.model.getPanelsData();
557
+ var postName = $('input[name="post_title"]').val();
558
+ if ( ! postName ) {
559
+ postName = $('input[name="post_ID"]').val();
560
+ }
561
+ panelsData.name = postName;
562
+ $$.find( 'input[name="panels_export_data"]' ).val( JSON.stringify( panelsData ) );
563
+ } );
564
+
565
+ },
566
+
567
+ /**
568
+ * Display the layout directory tab.
569
+ *
570
+ * @param query
571
+ */
572
+ displayLayoutDirectory: function ( search, page, type ) {
573
+ var thisView = this;
574
+ var c = this.$( '.so-content' ).empty().addClass( 'so-panels-loading' );
575
+
576
+ if ( search === undefined ) {
577
+ search = '';
578
+ }
579
+ if ( page === undefined ) {
580
+ page = 1;
581
+ }
582
+ if ( type === undefined ) {
583
+ type = 'directory-siteorigin';
584
+ }
585
+
586
+ if ( type.match('^directory-') && ! panelsOptions.directory_enabled ) {
587
+ // Display the button to enable the prebuilt layout
588
+ c.removeClass( 'so-panels-loading' ).html( $( '#siteorigin-panels-directory-enable' ).html() );
589
+ c.find( '.so-panels-enable-directory' ).click( function ( e ) {
590
+ e.preventDefault();
591
+ // Sent the query to enable the directory, then enable the directory
592
+ $.get(
593
+ panelsOptions.ajaxurl,
594
+ {action: 'so_panels_directory_enable'},
595
+ function () {
596
+
597
+ }
598
+ );
599
+
600
+ // Enable the layout directory
601
+ panelsOptions.directory_enabled = true;
602
+ c.addClass( 'so-panels-loading' );
603
+ thisView.displayLayoutDirectory( search, page, type );
604
+ } );
605
+ return;
606
+ }
607
+
608
+ // Get all the items for the current query
609
+ $.get(
610
+ panelsOptions.ajaxurl,
611
+ {
612
+ action: 'so_panels_layouts_query',
613
+ search: search,
614
+ page: page,
615
+ type: type,
616
+ },
617
+ function ( data ) {
618
+ // Skip this if we're no longer viewing the layout directory
619
+ if ( thisView.currentTab !== type ) {
620
+ return;
621
+ }
622
+
623
+ // Add the directory items
624
+ c.removeClass( 'so-panels-loading' ).html( thisView.directoryTemplate( data ) );
625
+
626
+ // Lets setup the next and previous buttons
627
+ var prev = c.find( '.so-previous' ), next = c.find( '.so-next' );
628
+
629
+ if ( page <= 1 ) {
630
+ prev.addClass( 'button-disabled' );
631
+ } else {
632
+ prev.click( function ( e ) {
633
+ e.preventDefault();
634
+ thisView.displayLayoutDirectory( search, page - 1, thisView.currentTab );
635
+ } );
636
+ }
637
+
638
+ if ( page === data.max_num_pages || data.max_num_pages === 0 ) {
639
+ next.addClass( 'button-disabled' );
640
+ } else {
641
+ next.click( function ( e ) {
642
+ e.preventDefault();
643
+ thisView.displayLayoutDirectory( search, page + 1, thisView.currentTab );
644
+ } );
645
+ }
646
+
647
+ // Handle nice preloading of the screenshots
648
+ c.find( '.so-screenshot' ).each( function () {
649
+ var $$ = $( this ), $a = $$.find( '.so-screenshot-wrapper' );
650
+ $a.css( 'height', ( $a.width() / 4 * 3 ) + 'px' ).addClass( 'so-loading' );
651
+
652
+ if ( $$.data( 'src' ) !== '' ) {
653
+ // Set the initial height
654
+ var $img = $( '<img/>' ).attr( 'src', $$.data( 'src' ) ).load( function () {
655
+ $a.removeClass( 'so-loading' ).css( 'height', 'auto' );
656
+ $img.appendTo( $a ).hide().fadeIn( 'fast' );
657
+ } );
658
+ } else {
659
+ $( '<img/>' ).attr( 'src', panelsOptions.prebuiltDefaultScreenshot ).appendTo( $a ).hide().fadeIn( 'fast' );
660
+ }
661
+
662
+ } );
663
+
664
+ // Set the title
665
+ c.find( '.so-directory-browse' ).html( data.title );
666
+ },
667
+ 'json'
668
+ );
669
+ },
670
+
671
+ /**
672
+ * Set the selected state for the clicked layout directory item and remove previously selected item.
673
+ * Enable the toolbar buttons.
674
+ */
675
+ directoryItemClickHandler: function ( e ) {
676
+ var $directoryItem = this.$( e.target ).closest( '.so-directory-item' );
677
+ this.$( '.so-directory-items' ).find( '.selected' ).removeClass( 'selected' );
678
+ $directoryItem.addClass( 'selected' );
679
+ this.selectedLayoutItem = {lid: $directoryItem.data( 'layout-id' ), type: $directoryItem.data( 'layout-type' )};
680
+ this.updateButtonState( true );
681
+
682
+ },
683
+
684
+ /**
685
+ * Load a particular layout into the builder.
686
+ *
687
+ * @param id
688
+ */
689
+ toolbarButtonClick: function ( $button ) {
690
+ if ( ! this.canAddLayout() ) {
691
+ return false;
692
+ }
693
+ var position = $button.data( 'value' );
694
+ if ( _.isUndefined( position ) ) {
695
+ return false;
696
+ }
697
+ this.updateButtonState( false );
698
+
699
+ if ( $button.hasClass( 'so-needs-confirm' ) && ! $button.hasClass( 'so-confirmed' ) ) {
700
+ this.updateButtonState( true );
701
+ if ( $button.hasClass( 'so-confirming' ) ) {
702
+ return;
703
+ }
704
+ $button.addClass( 'so-confirming' );
705
+ var originalText = $button.html();
706
+ $button.html( '<span class="dashicons dashicons-yes"></span>' + $button.data( 'confirm' ) );
707
+ setTimeout( function () {
708
+ $button.removeClass( 'so-confirmed' ).html( originalText );
709
+ }, 2500 );
710
+ setTimeout( function () {
711
+ $button.removeClass( 'so-confirming' );
712
+ $button.addClass( 'so-confirmed' );
713
+ }, 200 );
714
+ return false;
715
+ }
716
+ this.addingLayout = true;
717
+ if ( this.currentTab === 'import' ) {
718
+ this.addLayoutToBuilder( this.uploadedLayout, position );
719
+ } else {
720
+ this.loadSelectedLayout().then( function ( layout ) {
721
+ this.addLayoutToBuilder( layout, position );
722
+ }.bind( this ) );
723
+ }
724
+ },
725
+
726
+ canAddLayout: function () {
727
+ return (
728
+ this.selectedLayoutItem || this.uploadedLayout
729
+ ) && ! this.addingLayout;
730
+ },
731
+
732
+ /**
733
+ * Load the layout according to selectedLayoutItem.
734
+ */
735
+ loadSelectedLayout: function () {
736
+ this.setStatusMessage( panelsOptions.loc.prebuilt_loading, true );
737
+
738
+ var args = _.extend( this.selectedLayoutItem, {action: 'so_panels_get_layout'} );
739
+ var deferredLayout = new $.Deferred();
740
+
741
+ $.get(
742
+ panelsOptions.ajaxurl,
743
+ args,
744
+ function ( layout ) {
745
+ var msg = '';
746
+ if ( ! layout.success ) {
747
+ msg = layout.data.message;
748
+ deferredLayout.reject( layout.data );
749
+ } else {
750
+ deferredLayout.resolve( layout.data );
751
+ }
752
+ this.setStatusMessage( msg, false, ! layout.success );
753
+ this.updateButtonState( true );
754
+ }.bind( this )
755
+ );
756
+ return deferredLayout.promise();
757
+ },
758
+
759
+ /**
760
+ * Handle an update to the search
761
+ */
762
+ searchHandler: function ( e ) {
763
+ if ( e.keyCode === 13 ) {
764
+ this.displayLayoutDirectory( $( e.currentTarget ).val(), 1, this.currentTab );
765
+ }
766
+ },
767
+
768
+ /**
769
+ * Attempt to set the 'Insert' button's state according to the `enabled` argument, also checking whether the
770
+ * requirements for inserting a layout have valid values.
771
+ */
772
+ updateButtonState: function ( enabled ) {
773
+ enabled = enabled && (
774
+ this.selectedLayoutItem || this.uploadedLayout
775
+ );
776
+ var $button = this.$( '.so-import-layout' );
777
+ $button.prop( "disabled", ! enabled );
778
+ if ( enabled ) {
779
+ $button.removeClass( 'disabled' );
780
+ } else {
781
+ $button.addClass( 'disabled' );
782
+ }
783
+ },
784
+
785
+ addLayoutToBuilder: function ( layout, position ) {
786
+ this.builder.addHistoryEntry( 'prebuilt_loaded' );
787
+ this.builder.model.loadPanelsData( layout, position );
788
+ this.addingLayout = false;
789
+ this.closeDialog();
790
+ }
791
+ } );
792
+
793
+ },{}],8:[function(require,module,exports){
794
+ var panels = window.panels, $ = jQuery;
795
+
796
+ module.exports = panels.view.dialog.extend({
797
+
798
+ cellPreviewTemplate: _.template( panels.helpers.utils.processTemplate( $('#siteorigin-panels-dialog-row-cell-preview').html() ) ),
799
+
800
+ editableLabel: true,
801
+
802
+ events: {
803
+ 'click .so-close': 'closeDialog',
804
+
805
+ // Toolbar buttons
806
+ 'click .so-toolbar .so-save': 'saveHandler',
807
+ 'click .so-toolbar .so-insert': 'insertHandler',
808
+ 'click .so-toolbar .so-delete': 'deleteHandler',
809
+ 'click .so-toolbar .so-duplicate': 'duplicateHandler',
810
+
811
+ // Changing the row
812
+ 'change .row-set-form > *': 'setCellsFromForm',
813
+ 'click .row-set-form button.set-row': 'setCellsFromForm',
814
+ },
815
+
816
+ rowView: null,
817
+ dialogIcon: 'add-row',
818
+ dialogClass: 'so-panels-dialog-row-edit',
819
+ styleType: 'row',
820
+
821
+ dialogType: 'edit',
822
+
823
+ /**
824
+ * The current settings, not yet saved to the model
825
+ */
826
+ row: {
827
+ // This will be a clone of cells collection.
828
+ cells: null,
829
+ // The style settings of the row
830
+ style: {}
831
+ },
832
+
833
+ cellStylesCache: [],
834
+
835
+ initializeDialog: function () {
836
+ this.on('open_dialog', function () {
837
+ if (!_.isUndefined(this.model) && !_.isEmpty(this.model.get('cells'))) {
838
+ this.setRowModel(this.model);
839
+ } else {
840
+ this.setRowModel(null);
841
+ }
842
+
843
+ this.regenerateRowPreview();
844
+ this.renderStyles();
845
+ }, this);
846
+
847
+ // This is the default row layout
848
+ this.row = {
849
+ cells: new panels.collection.cells([{weight: 0.5}, {weight: 0.5}]),
850
+ style: {}
851
+ };
852
+
853
+ // Refresh panels data after both dialog form components are loaded
854
+ this.dialogFormsLoaded = 0;
855
+ var thisView = this;
856
+ this.on('form_loaded styles_loaded', function () {
857
+ this.dialogFormsLoaded++;
858
+ if (this.dialogFormsLoaded === 2) {
859
+ thisView.updateModel({
860
+ refreshArgs: {
861
+ silent: true
862
+ }
863
+ });
864
+ }
865
+ });
866
+
867
+ this.on('close_dialog', this.closeHandler);
868
+
869
+ this.on( 'edit_label', function ( text ) {
870
+ // If text is set to default values, just clear it.
871
+ if ( text === panelsOptions.loc.row.add || text === panelsOptions.loc.row.edit ) {
872
+ text = '';
873
+ }
874
+ this.model.set( 'label', text );
875
+ if ( _.isEmpty( text ) ) {
876
+ var title = this.dialogType === 'create' ? panelsOptions.loc.row.add : panelsOptions.loc.row.edit;
877
+ this.$( '.so-title').text( title );
878
+ }
879
+ }.bind( this ) );
880
+ },
881
+
882
+ /**
883
+ *
884
+ * @param dialogType Either "edit" or "create"
885
+ */
886
+ setRowDialogType: function (dialogType) {
887
+ this.dialogType = dialogType;
888
+ },
889
+
890
+ /**
891
+ * Render the new row dialog
892
+ */
893
+ render: function () {
894
+ var title = this.dialogType === 'create' ? panelsOptions.loc.row.add : panelsOptions.loc.row.edit;
895
+ this.renderDialog( this.parseDialogContent( $( '#siteorigin-panels-dialog-row' ).html(), {
896
+ title: title,
897
+ dialogType: this.dialogType
898
+ } ) );
899
+
900
+ var titleElt = this.$( '.so-title' );
901
+
902
+ if ( this.model.has( 'label' ) && ! _.isEmpty( this.model.get( 'label' ) ) ) {
903
+ titleElt.text( this.model.get( 'label' ) );
904
+ }
905
+ this.$( '.so-edit-title' ).val( titleElt.text() );
906
+
907
+ if (!this.builder.supports('addRow')) {
908
+ this.$('.so-buttons .so-duplicate').remove();
909
+ }
910
+ if (!this.builder.supports('deleteRow')) {
911
+ this.$('.so-buttons .so-delete').remove();
912
+ }
913
+
914
+ if (!_.isUndefined(this.model)) {
915
+ // Set the initial value of the
916
+ this.$( 'input[name="cells"].so-row-field' ).val( this.model.get( 'cells' ).length );
917
+ if ( this.model.has( 'ratio' ) ) {
918
+ this.$( 'select[name="ratio"].so-row-field' ).val( this.model.get( 'ratio' ) );
919
+ }
920
+ if ( this.model.has( 'ratio_direction' ) ) {
921
+ this.$( 'select[name="ratio_direction"].so-row-field' ).val( this.model.get( 'ratio_direction' ) );
922
+ }
923
+ }
924
+
925
+ this.$('input.so-row-field').keyup(function () {
926
+ $(this).trigger('change');
927
+ });
928
+
929
+ return this;
930
+ },
931
+
932
+ renderStyles: function () {
933
+ if ( this.styles ) {
934
+ this.styles.off( 'styles_loaded' );
935
+ this.styles.remove();
936
+ }
937
+
938
+ // Now we need to attach the style window
939
+ this.styles = new panels.view.styles();
940
+ this.styles.model = this.model;
941
+ this.styles.render('row', this.builder.config.postId, {
942
+ builderType: this.builder.config.builderType,
943
+ dialog: this
944
+ });
945
+
946
+ var $rightSidebar = this.$('.so-sidebar.so-right-sidebar');
947
+ this.styles.attach( $rightSidebar );
948
+
949
+ // Handle the loading class
950
+ this.styles.on('styles_loaded', function (hasStyles) {
951
+ if ( ! hasStyles ) {
952
+ // If we don't have styles remove the view.
953
+ this.styles.remove();
954
+
955
+ // If the sidebar is empty, hide it.
956
+ if ( $rightSidebar.children().length === 0 ) {
957
+ $rightSidebar.closest('.so-panels-dialog').removeClass('so-panels-dialog-has-right-sidebar');
958
+ $rightSidebar.hide();
959
+ }
960
+ }
961
+ }, this);
962
+ },
963
+
964
+ /**
965
+ * Set the row model we'll be using for this dialog.
966
+ *
967
+ * @param model
968
+ */
969
+ setRowModel: function (model) {
970
+ this.model = model;
971
+
972
+ if (_.isEmpty(this.model)) {
973
+ return this;
974
+ }
975
+
976
+ // Set the rows to be a copy of the model
977
+ this.row = {
978
+ cells: this.model.get('cells').clone(),
979
+ style: {},
980
+ ratio: this.model.get('ratio'),
981
+ ratio_direction: this.model.get('ratio_direction'),
982
+ };
983
+
984
+ // Set the initial value of the cell field.
985
+ this.$( 'input[name="cells"].so-row-field' ).val( this.model.get( 'cells' ).length );
986
+ if ( this.model.has( 'ratio' ) ) {
987
+ this.$( 'select[name="ratio"].so-row-field' ).val( this.model.get( 'ratio' ) );
988
+ }
989
+ if ( this.model.has( 'ratio_direction' ) ) {
990
+ this.$( 'select[name="ratio_direction"].so-row-field' ).val( this.model.get( 'ratio_direction' ) );
991
+ }
992
+
993
+ this.clearCellStylesCache();
994
+
995
+ return this;
996
+ },
997
+
998
+ /**
999
+ * Regenerate the row preview and resizing interface.
1000
+ */
1001
+ regenerateRowPreview: function () {
1002
+ var thisDialog = this;
1003
+ var rowPreview = this.$('.row-preview');
1004
+
1005
+ // If no selected cell, select the first cell.
1006
+ var selectedIndex = this.getSelectedCellIndex();
1007
+
1008
+ rowPreview.empty();
1009
+
1010
+ var timeout;
1011
+
1012
+ // Represent the cells
1013
+ this.row.cells.each(function (cellModel, i) {
1014
+ var newCell = $(this.cellPreviewTemplate({weight: cellModel.get('weight')}));
1015
+ rowPreview.append(newCell);
1016
+
1017
+ if(i == selectedIndex) {
1018
+ newCell.find('.preview-cell-in').addClass('cell-selected');
1019
+ }
1020
+
1021
+ var prevCell = newCell.prev();
1022
+ var handle;
1023
+
1024
+ if (prevCell.length) {
1025
+ handle = $('<div class="resize-handle"></div>');
1026
+ handle
1027
+ .appendTo(newCell)
1028
+ .dblclick(function () {
1029
+ var prevCellModel = thisDialog.row.cells.at(i - 1);
1030
+ var t = cellModel.get('weight') + prevCellModel.get('weight');
1031
+ cellModel.set('weight', t / 2);
1032
+ prevCellModel.set('weight', t / 2);
1033
+ thisDialog.scaleRowWidths();
1034
+ });
1035
+
1036
+ handle.draggable({
1037
+ axis: 'x',
1038
+ containment: rowPreview,
1039
+ start: function (e, ui) {
1040
+
1041
+ // Create the clone for the current cell
1042
+ var newCellClone = newCell.clone().appendTo(ui.helper).css({
1043
+ position: 'absolute',
1044
+ top: '0',
1045
+ width: newCell.outerWidth(),
1046
+ left: 6,
1047
+ height: newCell.outerHeight()
1048
+ });
1049
+ newCellClone.find('.resize-handle').remove();
1050
+
1051
+ // Create the clone for the previous cell
1052
+ var prevCellClone = prevCell.clone().appendTo(ui.helper).css({
1053
+ position: 'absolute',
1054
+ top: '0',
1055
+ width: prevCell.outerWidth(),
1056
+ right: 6,
1057
+ height: prevCell.outerHeight()
1058
+ });
1059
+ prevCellClone.find('.resize-handle').remove();
1060
+
1061
+ $(this).data({
1062
+ 'newCellClone': newCellClone,
1063
+ 'prevCellClone': prevCellClone
1064
+ });
1065
+
1066
+ // Hide the
1067
+ newCell.find('> .preview-cell-in').css('visibility', 'hidden');
1068
+ prevCell.find('> .preview-cell-in').css('visibility', 'hidden');
1069
+ },
1070
+ drag: function (e, ui) {
1071
+ // Calculate the new cell and previous cell widths as a percent
1072
+ var cellWeight = thisDialog.row.cells.at(i).get('weight');
1073
+ var prevCellWeight = thisDialog.row.cells.at(i - 1).get('weight');
1074
+ var ncw = cellWeight - (
1075
+ (
1076
+ ui.position.left + 6
1077
+ ) / rowPreview.width()
1078
+ );
1079
+ var pcw = prevCellWeight + (
1080
+ (
1081
+ ui.position.left + 6
1082
+ ) / rowPreview.width()
1083
+ );
1084
+
1085
+ var helperLeft = ui.helper.offset().left - rowPreview.offset().left - 6;
1086
+
1087
+ $(this).data('newCellClone').css('width', rowPreview.width() * ncw)
1088
+ .find('.preview-cell-weight').html(Math.round(ncw * 1000) / 10);
1089
+
1090
+ $(this).data('prevCellClone').css('width', rowPreview.width() * pcw)
1091
+ .find('.preview-cell-weight').html(Math.round(pcw * 1000) / 10);
1092
+ },
1093
+ stop: function (e, ui) {
1094
+ // Remove the clones
1095
+ $(this).data('newCellClone').remove();
1096
+ $(this).data('prevCellClone').remove();
1097
+
1098
+ // Reshow the main cells
1099
+ newCell.find('.preview-cell-in').css('visibility', 'visible');
1100
+ prevCell.find('.preview-cell-in').css('visibility', 'visible');
1101
+
1102
+ // Calculate the new cell weights
1103
+ var offset = ui.position.left + 6;
1104
+ var percent = offset / rowPreview.width();
1105
+
1106
+ // Ignore this if any of the cells are below 2% in width.
1107
+ var cellModel = thisDialog.row.cells.at(i);
1108
+ var prevCellModel = thisDialog.row.cells.at(i - 1);
1109
+ if (cellModel.get('weight') - percent > 0.02 && prevCellModel.get('weight') + percent > 0.02) {
1110
+ cellModel.set('weight', cellModel.get('weight') - percent);
1111
+ prevCellModel.set('weight', prevCellModel.get('weight') + percent);
1112
+ }
1113
+
1114
+ thisDialog.scaleRowWidths();
1115
+ ui.helper.css('left', -6);
1116
+ }
1117
+ });
1118
+ }
1119
+
1120
+ newCell.click(function (event) {
1121
+
1122
+ if ( ! ( $(event.target).is('.preview-cell') || $(event.target).is('.preview-cell-in') ) ) {
1123
+ return;
1124
+ }
1125
+
1126
+ var cell = $(event.target);
1127
+ cell.closest('.row-preview').find('.preview-cell .preview-cell-in').removeClass('cell-selected');
1128
+ cell.addClass('cell-selected');
1129
+
1130
+ this.openSelectedCellStyles();
1131
+
1132
+ }.bind(this));
1133
+
1134
+ // Make this row weight click editable
1135
+ newCell.find('.preview-cell-weight').click(function (ci) {
1136
+
1137
+ // Disable the draggable while entering values
1138
+ thisDialog.$('.resize-handle').css('pointer-event', 'none').draggable('disable');
1139
+
1140
+ rowPreview.find('.preview-cell-weight').each(function () {
1141
+ var $$ = jQuery(this).hide();
1142
+ $('<input type="text" class="preview-cell-weight-input no-user-interacted" />')
1143
+ .val(parseFloat($$.html())).insertAfter($$)
1144
+ .focus(function () {
1145
+ clearTimeout(timeout);
1146
+ })
1147
+ .keyup(function (e) {
1148
+ if (e.keyCode !== 9) {
1149
+ // Only register the interaction if the user didn't press tab
1150
+ $(this).removeClass('no-user-interacted');
1151
+ }
1152
+
1153
+ // Enter is clicked
1154
+ if (e.keyCode === 13) {
1155
+ e.preventDefault();
1156
+ $(this).blur();
1157
+ }
1158
+ })
1159
+ .keydown(function (e) {
1160
+ if (e.keyCode === 9) {
1161
+ e.preventDefault();
1162
+
1163
+ // Tab will always cycle around the row inputs
1164
+ var inputs = rowPreview.find('.preview-cell-weight-input');
1165
+ var i = inputs.index($(this));
1166
+ if (i === inputs.length - 1) {
1167
+ inputs.eq(0).focus().select();
1168
+ } else {
1169
+ inputs.eq(i + 1).focus().select();
1170
+ }
1171
+ }
1172
+ })
1173
+ .blur(function () {
1174
+ rowPreview.find('.preview-cell-weight-input').each(function (i, el) {
1175
+ if (isNaN(parseFloat($(el).val()))) {
1176
+ $(el).val(Math.floor(thisDialog.row.cells.at(i).get('weight') * 1000) / 10);
1177
+ }
1178
+ });
1179
+
1180
+ timeout = setTimeout(function () {
1181
+ // If there are no weight inputs, then skip this
1182
+ if (rowPreview.find('.preview-cell-weight-input').length === 0) {
1183
+ return false;
1184
+ }
1185
+
1186
+ // Go through all the inputs
1187
+ var rowWeights = [],
1188
+ rowChanged = [],
1189
+ changedSum = 0,
1190
+ unchangedSum = 0;
1191
+
1192
+ rowPreview.find('.preview-cell-weight-input').each(function (i, el) {
1193
+ var val = parseFloat($(el).val());
1194
+ if (isNaN(val)) {
1195
+ val = 1 / thisDialog.row.cells.length;
1196
+ } else {
1197
+ val = Math.round(val * 10) / 1000;
1198
+ }
1199
+
1200
+ // Check within 3 decimal points
1201
+ var changed = !$(el).hasClass('no-user-interacted');
1202
+
1203
+ rowWeights.push(val);
1204
+ rowChanged.push(changed);
1205
+
1206
+ if (changed) {
1207
+ changedSum += val;
1208
+ } else {
1209
+ unchangedSum += val;
1210
+ }
1211
+ });
1212
+
1213
+ if (changedSum > 0 && unchangedSum > 0 && (
1214
+ 1 - changedSum
1215
+ ) > 0) {
1216
+ // Balance out the unchanged rows to occupy the weight left over by the changed sum
1217
+ for (var i = 0; i < rowWeights.length; i++) {
1218
+ if (!rowChanged[i]) {
1219
+ rowWeights[i] = (
1220
+ rowWeights[i] / unchangedSum
1221
+ ) * (
1222
+ 1 - changedSum
1223
+ );
1224
+ }
1225
+ }
1226
+ }
1227
+
1228
+ // Last check to ensure total weight is 1
1229
+ var sum = _.reduce(rowWeights, function (memo, num) {
1230
+ return memo + num;
1231
+ });
1232
+ rowWeights = rowWeights.map(function (w) {
1233
+ return w / sum;
1234
+ });
1235
+
1236
+ // Set the new cell weights and regenerate the preview.
1237
+ if (Math.min.apply(Math, rowWeights) > 0.01) {
1238
+ thisDialog.row.cells.each(function (cell, i) {
1239
+ cell.set('weight', rowWeights[i]);
1240
+ });
1241
+ }
1242
+
1243
+ // Now lets animate the cells into their new widths
1244
+ rowPreview.find('.preview-cell').each(function (i, el) {
1245
+ var cellWeight = thisDialog.row.cells.at(i).get('weight');
1246
+ $(el).animate({'width': Math.round(cellWeight * 1000) / 10 + "%"}, 250);
1247
+ $(el).find('.preview-cell-weight-input').val(Math.round(cellWeight * 1000) / 10);
1248
+ });
1249
+
1250
+ // So the draggable handle is not hidden.
1251
+ rowPreview.find('.preview-cell').css('overflow', 'visible');
1252
+ setTimeout(thisDialog.regenerateRowPreview.bind(thisDialog), 260);
1253
+
1254
+ }, 100);
1255
+ })
1256
+ .click(function () {
1257
+ $(this).select();
1258
+ });
1259
+ });
1260
+
1261
+ $(this).siblings('.preview-cell-weight-input').select();
1262
+
1263
+ });
1264
+
1265
+ }, this);
1266
+
1267
+ this.openSelectedCellStyles();
1268
+
1269
+ this.trigger('form_loaded', this);
1270
+ },
1271
+
1272
+ getSelectedCellIndex: function() {
1273
+ var selectedIndex = -1;
1274
+ this.$('.preview-cell .preview-cell-in').each(function(index, el) {
1275
+ if($(el).is('.cell-selected')) {
1276
+ selectedIndex = index;
1277
+ }
1278
+ });
1279
+ return selectedIndex;
1280
+ },
1281
+
1282
+ openSelectedCellStyles: function() {
1283
+ if (!_.isUndefined(this.cellStyles)) {
1284
+ if (this.cellStyles.stylesLoaded) {
1285
+ var style = {};
1286
+ try {
1287
+ style = this.getFormValues('.so-sidebar .so-visual-styles.so-cell-styles').style;
1288
+ }
1289
+ catch (err) {
1290
+ console.log('Error retrieving cell styles - ' + err.message);
1291
+ }
1292
+
1293
+ this.cellStyles.model.set('style', style);
1294
+ }
1295
+ this.cellStyles.detach();
1296
+ }
1297
+
1298
+ this.cellStyles = this.getSelectedCellStyles();
1299
+
1300
+ if ( this.cellStyles ) {
1301
+ var $rightSidebar = this.$( '.so-sidebar.so-right-sidebar' );
1302
+ this.cellStyles.attach( $rightSidebar );
1303
+ this.cellStyles.on( 'styles_loaded', function ( hasStyles ) {
1304
+ if ( hasStyles ) {
1305
+ $rightSidebar.closest('.so-panels-dialog').addClass('so-panels-dialog-has-right-sidebar');
1306
+ $rightSidebar.show();
1307
+ }
1308
+ } );
1309
+ }
1310
+ },
1311
+
1312
+ getSelectedCellStyles: function () {
1313
+ var cellIndex = this.getSelectedCellIndex();
1314
+ if ( cellIndex > -1 ) {
1315
+ var cellStyles = this.cellStylesCache[cellIndex];
1316
+ if ( !cellStyles ) {
1317
+ cellStyles = new panels.view.styles();
1318
+ cellStyles.model = this.row.cells.at( cellIndex );
1319
+ cellStyles.render( 'cell', this.builder.config.postId, {
1320
+ builderType: this.builder.config.builderType,
1321
+ dialog: this,
1322
+ index: cellIndex,
1323
+ } );
1324
+ this.cellStylesCache[cellIndex] = cellStyles;
1325
+ }
1326
+ }
1327
+
1328
+ return cellStyles;
1329
+ },
1330
+
1331
+ clearCellStylesCache: function () {
1332
+ // Call remove() on all cell styles to remove data, event listeners etc.
1333
+ this.cellStylesCache.forEach(function (cellStyles) {
1334
+ cellStyles.remove();
1335
+ });
1336
+ this.cellStylesCache = [];
1337
+ },
1338
+
1339
+ /**
1340
+ * Visually scale the row widths based on the cell weights
1341
+ */
1342
+ scaleRowWidths: function () {
1343
+ var thisDialog = this;
1344
+ this.$('.row-preview .preview-cell').each(function (i, el) {
1345
+ var cell = thisDialog.row.cells.at(i);
1346
+ $(el)
1347
+ .css('width', cell.get('weight') * 100 + "%")
1348
+ .find('.preview-cell-weight').html(Math.round(cell.get('weight') * 1000) / 10);
1349
+ });
1350
+ },
1351
+
1352
+ /**
1353
+ * Get the weights from the
1354
+ */
1355
+ setCellsFromForm: function () {
1356
+
1357
+ try {
1358
+ var f = {
1359
+ 'cells': parseInt(this.$('.row-set-form input[name="cells"]').val()),
1360
+ 'ratio': parseFloat(this.$('.row-set-form select[name="ratio"]').val()),
1361
+ 'direction': this.$('.row-set-form select[name="ratio_direction"]').val()
1362
+ };
1363
+
1364
+ if (_.isNaN(f.cells)) {
1365
+ f.cells = 1;
1366
+ }
1367
+ if (isNaN(f.ratio)) {
1368
+ f.ratio = 1;
1369
+ }
1370
+ if (f.cells < 1) {
1371
+ f.cells = 1;
1372
+ this.$('.row-set-form input[name="cells"]').val(f.cells);
1373
+ }
1374
+ else if (f.cells > 12) {
1375
+ f.cells = 12;
1376
+ this.$('.row-set-form input[name="cells"]').val(f.cells);
1377
+ }
1378
+
1379
+ this.$('.row-set-form select[name="ratio"]').val(f.ratio);
1380
+
1381
+ var cells = [];
1382
+ var cellCountChanged = (
1383
+ this.row.cells.length !== f.cells
1384
+ );
1385
+
1386
+ // Now, lets create some cells
1387
+ var currentWeight = 1;
1388
+ for (var i = 0; i < f.cells; i++) {
1389
+ cells.push(currentWeight);
1390
+ currentWeight *= f.ratio;
1391
+ }
1392
+
1393
+ // Now lets make sure that the row weights add up to 1
1394
+
1395
+ var totalRowWeight = _.reduce(cells, function (memo, weight) {
1396
+ return memo + weight;
1397
+ });
1398
+ cells = _.map(cells, function (cell) {
1399
+ return cell / totalRowWeight;
1400
+ });
1401
+
1402
+ // Don't return cells that are too small
1403
+ cells = _.filter(cells, function (cell) {
1404
+ return cell > 0.01;
1405
+ });
1406
+
1407
+ if (f.direction === 'left') {
1408
+ cells = cells.reverse();
1409
+ }
1410
+
1411
+ // Discard deleted cells.
1412
+ this.row.cells = new panels.collection.cells(this.row.cells.first(cells.length));
1413
+
1414
+ _.each(cells, function (cellWeight, index) {
1415
+ var cell = this.row.cells.at(index);
1416
+ if (!cell) {
1417
+ cell = new panels.model.cell({weight: cellWeight, row: this.model});
1418
+ this.row.cells.add(cell);
1419
+ } else {
1420
+ cell.set('weight', cellWeight);
1421
+ }
1422
+ }.bind(this));
1423
+
1424
+ this.row.ratio = f.ratio;
1425
+ this.row.ratio_direction = f.direction;
1426
+
1427
+ if (cellCountChanged) {
1428
+ this.regenerateRowPreview();
1429
+ } else {
1430
+ var thisDialog = this;
1431
+
1432
+ // Now lets animate the cells into their new widths
1433
+ this.$('.preview-cell').each(function (i, el) {
1434
+ var cellWeight = thisDialog.row.cells.at(i).get('weight');
1435
+ $(el).animate({'width': Math.round(cellWeight * 1000) / 10 + "%"}, 250);
1436
+ $(el).find('.preview-cell-weight').html(Math.round(cellWeight * 1000) / 10);
1437
+ });
1438
+
1439
+ // So the draggable handle is not hidden.
1440
+ this.$('.preview-cell').css('overflow', 'visible');
1441
+
1442
+ setTimeout(thisDialog.regenerateRowPreview.bind(thisDialog), 260);
1443
+ }
1444
+ }
1445
+ catch (err) {
1446
+ console.log('Error setting cells - ' + err.message);
1447
+ }
1448
+
1449
+
1450
+ // Remove the button primary class
1451
+ this.$('.row-set-form .so-button-row-set').removeClass('button-primary');
1452
+ },
1453
+
1454
+ /**
1455
+ * Handle a click on the dialog left bar tab
1456
+ */
1457
+ tabClickHandler: function ($t) {
1458
+ if ($t.attr('href') === '#row-layout') {
1459
+ this.$('.so-panels-dialog').addClass('so-panels-dialog-has-right-sidebar');
1460
+ } else {
1461
+ this.$('.so-panels-dialog').removeClass('so-panels-dialog-has-right-sidebar');
1462
+ }
1463
+ },
1464
+
1465
+ /**
1466
+ * Update the current model with what we have in the dialog
1467
+ */
1468
+ updateModel: function (args) {
1469
+ args = _.extend({
1470
+ refresh: true,
1471
+ refreshArgs: null
1472
+ }, args);
1473
+
1474
+ // Set the cells
1475
+ if (!_.isEmpty(this.model)) {
1476
+ this.model.setCells( this.row.cells );
1477
+ this.model.set( 'ratio', this.row.ratio );
1478
+ this.model.set( 'ratio_direction', this.row.ratio_direction );
1479
+ }
1480
+
1481
+ // Update the row styles if they've loaded
1482
+ if (!_.isUndefined(this.styles) && this.styles.stylesLoaded) {
1483
+ // This is an edit dialog, so there are styles
1484
+ var style = {};
1485
+ try {
1486
+ style = this.getFormValues('.so-sidebar .so-visual-styles.so-row-styles').style;
1487
+ }
1488
+ catch (err) {
1489
+ console.log('Error retrieving row styles - ' + err.message);
1490
+ }
1491
+
1492
+ this.model.set('style', style);
1493
+ }
1494
+
1495
+ // Update the cell styles if any are showing.
1496
+ if (!_.isUndefined(this.cellStyles) && this.cellStyles.stylesLoaded) {
1497
+
1498
+ var style = {};
1499
+ try {
1500
+ style = this.getFormValues('.so-sidebar .so-visual-styles.so-cell-styles').style;
1501
+ }
1502
+ catch (err) {
1503
+ console.log('Error retrieving cell styles - ' + err.message);
1504
+ }
1505
+
1506
+ this.cellStyles.model.set('style', style);
1507
+ }
1508
+
1509
+ if (args.refresh) {
1510
+ this.builder.model.refreshPanelsData(args.refreshArgs);
1511
+ }
1512
+ },
1513
+
1514
+ /**
1515
+ * Insert the new row
1516
+ */
1517
+ insertHandler: function () {
1518
+ this.builder.addHistoryEntry('row_added');
1519
+
1520
+ this.updateModel();
1521
+
1522
+ var activeCell = this.builder.getActiveCell({
1523
+ createCell: false,
1524
+ });
1525
+
1526
+ var options = {};
1527
+ if (activeCell !== null) {
1528
+ options.at = this.builder.model.get('rows').indexOf(activeCell.row) + 1;
1529
+ }
1530
+
1531
+ // Set up the model and add it to the builder
1532
+ this.model.collection = this.builder.model.get('rows');
1533
+ this.builder.model.get('rows').add(this.model, options);
1534
+
1535
+ this.closeDialog();
1536
+
1537
+ this.builder.model.refreshPanelsData();
1538
+
1539
+ return false;
1540
+ },
1541
+
1542
+ /**
1543
+ * We'll just save this model and close the dialog
1544
+ */
1545
+ saveHandler: function () {
1546
+ this.builder.addHistoryEntry('row_edited');
1547
+ this.updateModel();
1548
+ this.closeDialog();
1549
+
1550
+ this.builder.model.refreshPanelsData();
1551
+
1552
+ return false;
1553
+ },
1554
+
1555
+ /**
1556
+ * The user clicks delete, so trigger deletion on the row model
1557
+ */
1558
+ deleteHandler: function () {
1559
+ // Trigger a destroy on the model that will happen with a visual indication to the user
1560
+ this.rowView.visualDestroyModel();
1561
+ this.closeDialog({silent: true});
1562
+
1563
+ return false;
1564
+ },
1565
+
1566
+ /**
1567
+ * Duplicate this row
1568
+ */
1569
+ duplicateHandler: function () {
1570
+ this.builder.addHistoryEntry('row_duplicated');
1571
+
1572
+ var duplicateRow = this.model.clone(this.builder.model);
1573
+
1574
+ this.builder.model.get('rows').add( duplicateRow, {
1575
+ at: this.builder.model.get('rows').indexOf(this.model) + 1
1576
+ } );
1577
+
1578
+ this.closeDialog({silent: true});
1579
+
1580
+ return false;
1581
+ },
1582
+
1583
+ closeHandler: function() {
1584
+ this.clearCellStylesCache();
1585
+ if( ! _.isUndefined(this.cellStyles) ) {
1586
+ this.cellStyles = undefined;
1587
+ }
1588
+ },
1589
+
1590
+ });
1591
+
1592
+ },{}],9:[function(require,module,exports){
1593
+ var panels = window.panels, $ = jQuery;
1594
+ var jsWidget = require( '../view/widgets/js-widget' );
1595
+
1596
+ module.exports = panels.view.dialog.extend( {
1597
+
1598
+ builder: null,
1599
+ sidebarWidgetTemplate: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-dialog-widget-sidebar-widget' ).html() ) ),
1600
+
1601
+ dialogClass: 'so-panels-dialog-edit-widget',
1602
+ dialogIcon: 'add-widget',
1603
+
1604
+ widgetView: false,
1605
+ savingWidget: false,
1606
+ editableLabel: true,
1607
+
1608
+ events: {
1609
+ 'click .so-close': 'saveHandler',
1610
+ 'click .so-nav.so-previous': 'navToPrevious',
1611
+ 'click .so-nav.so-next': 'navToNext',
1612
+
1613
+ // Action handlers
1614
+ 'click .so-toolbar .so-delete': 'deleteHandler',
1615
+ 'click .so-toolbar .so-duplicate': 'duplicateHandler'
1616
+ },
1617
+
1618
+ initializeDialog: function () {
1619
+ var thisView = this;
1620
+ this.listenTo( this.model, 'change:values', this.handleChangeValues );
1621
+ this.listenTo( this.model, 'destroy', this.remove );
1622
+
1623
+ // Refresh panels data after both dialog form components are loaded
1624
+ this.dialogFormsLoaded = 0;
1625
+ this.on( 'form_loaded styles_loaded', function () {
1626
+ this.dialogFormsLoaded ++;
1627
+ if ( this.dialogFormsLoaded === 2 ) {
1628
+ thisView.updateModel( {
1629
+ refreshArgs: {
1630
+ silent: true
1631
+ }
1632
+ } );
1633
+ }
1634
+ } );
1635
+
1636
+ this.on( 'edit_label', function ( text ) {
1637
+ // If text is set to default value, just clear it.
1638
+ if ( text === panelsOptions.widgets[ this.model.get( 'class' ) ][ 'title' ] ) {
1639
+ text = '';
1640
+ }
1641
+ this.model.set( 'label', text );
1642
+ if ( _.isEmpty( text ) ) {
1643
+ this.$( '.so-title' ).text( this.model.getWidgetField( 'title' ) );
1644
+ }
1645
+ }.bind( this ) );
1646
+ },
1647
+
1648
+ /**
1649
+ * Render the widget dialog.
1650
+ */
1651
+ render: function () {
1652
+ // Render the dialog and attach it to the builder interface
1653
+ this.renderDialog( this.parseDialogContent( $( '#siteorigin-panels-dialog-widget' ).html(), {} ) );
1654
+ this.loadForm();
1655
+
1656
+ var title = this.model.getWidgetField( 'title' );
1657
+ this.$( '.so-title .widget-name' ).html( title );
1658
+ this.$( '.so-edit-title' ).val( title );
1659
+
1660
+ if( ! this.builder.supports( 'addWidget' ) ) {
1661
+ this.$( '.so-buttons .so-duplicate' ).remove();
1662
+ }
1663
+ if( ! this.builder.supports( 'deleteWidget' ) ) {
1664
+ this.$( '.so-buttons .so-delete' ).remove();
1665
+ }
1666
+
1667
+ // Now we need to attach the style window
1668
+ this.styles = new panels.view.styles();
1669
+ this.styles.model = this.model;
1670
+ this.styles.render( 'widget', this.builder.config.postId, {
1671
+ builderType: this.builder.config.builderType,
1672
+ dialog: this
1673
+ } );
1674
+
1675
+ var $rightSidebar = this.$( '.so-sidebar.so-right-sidebar' );
1676
+ this.styles.attach( $rightSidebar );
1677
+
1678
+ // Handle the loading class
1679
+ this.styles.on( 'styles_loaded', function ( hasStyles ) {
1680
+ // If we don't have styles remove the empty sidebar.
1681
+ if ( ! hasStyles ) {
1682
+ $rightSidebar.closest( '.so-panels-dialog' ).removeClass( 'so-panels-dialog-has-right-sidebar' );
1683
+ $rightSidebar.remove();
1684
+ }
1685
+ }, this );
1686
+ },
1687
+
1688
+ /**
1689
+ * Get the previous widget editing dialog by looking at the dom.
1690
+ * @returns {*}
1691
+ */
1692
+ getPrevDialog: function () {
1693
+ var widgets = this.builder.$( '.so-cells .cell .so-widget' );
1694
+ if ( widgets.length <= 1 ) {
1695
+ return false;
1696
+ }
1697
+ var currentIndex = widgets.index( this.widgetView.$el );
1698
+
1699
+ if ( currentIndex === 0 ) {
1700
+ return false;
1701
+ } else {
1702
+ var widgetView;
1703
+ do {
1704
+ widgetView = widgets.eq( --currentIndex ).data( 'view' );
1705
+ if ( ! _.isUndefined( widgetView ) && ! widgetView.model.get( 'read_only' ) ) {
1706
+ return widgetView.getEditDialog();
1707
+ }
1708
+ } while( ! _.isUndefined( widgetView ) && currentIndex > 0 );
1709
+ }
1710
+
1711
+ return false;
1712
+ },
1713
+
1714
+ /**
1715
+ * Get the next widget editing dialog by looking at the dom.
1716
+ * @returns {*}
1717
+ */
1718
+ getNextDialog: function () {
1719
+ var widgets = this.builder.$( '.so-cells .cell .so-widget' );
1720
+ if ( widgets.length <= 1 ) {
1721
+ return false;
1722
+ }
1723
+
1724
+ var currentIndex = widgets.index( this.widgetView.$el );
1725
+
1726
+ if ( currentIndex === widgets.length - 1 ) {
1727
+ return false;
1728
+ } else {
1729
+ var widgetView;
1730
+ do {
1731
+ widgetView = widgets.eq( ++currentIndex ).data( 'view' );
1732
+ if ( ! _.isUndefined( widgetView ) && ! widgetView.model.get( 'read_only' ) ) {
1733
+ return widgetView.getEditDialog();
1734
+ }
1735
+ } while( ! _.isUndefined( widgetView ) );
1736
+ }
1737
+
1738
+ return false;
1739
+ },
1740
+
1741
+ /**
1742
+ * Load the widget form from the server.
1743
+ * This is called when rendering the dialog for the first time.
1744
+ */
1745
+ loadForm: function () {
1746
+ // don't load the form if this dialog hasn't been rendered yet
1747
+ if ( ! this.$( '> *' ).length ) {
1748
+ return;
1749
+ }
1750
+
1751
+ this.$( '.so-content' ).addClass( 'so-panels-loading' );
1752
+
1753
+ var data = {
1754
+ 'action': 'so_panels_widget_form',
1755
+ 'widget': this.model.get( 'class' ),
1756
+ 'instance': JSON.stringify( this.model.get( 'values' ) ),
1757
+ 'raw': this.model.get( 'raw' )
1758
+ };
1759
+
1760
+ var $soContent = this.$( '.so-content' );
1761
+
1762
+ $.post( panelsOptions.ajaxurl, data, null, 'html' )
1763
+ .done( function ( result ) {
1764
+ // Add in the CID of the widget model
1765
+ var html = result.replace( /{\$id}/g, this.model.cid );
1766
+
1767
+ // Load this content into the form
1768
+ $soContent
1769
+ .removeClass( 'so-panels-loading' )
1770
+ .html( html );
1771
+
1772
+ // Trigger all the necessary events
1773
+ this.trigger( 'form_loaded', this );
1774
+
1775
+ // For legacy compatibility, trigger a panelsopen event
1776
+ this.$( '.panel-dialog' ).trigger( 'panelsopen' );
1777
+
1778
+ // If the main dialog is closed from this point on, save the widget content
1779
+ this.on( 'close_dialog', this.updateModel, this );
1780
+
1781
+ var widgetContent = $soContent.find( '> .widget-content' );
1782
+ // If there's a widget content wrapper, this is one of the new widgets in WP 4.8 which need some special
1783
+ // handling in JS.
1784
+ if ( widgetContent.length > 0 ) {
1785
+ jsWidget.addWidget( $soContent, this.model.widget_id );
1786
+ }
1787
+
1788
+ }.bind( this ) )
1789
+ .fail( function ( error ) {
1790
+ var html;
1791
+ if ( error && error.responseText ) {
1792
+ html = error.responseText;
1793
+ } else {
1794
+ html = panelsOptions.forms.loadingFailed;
1795
+ }
1796
+
1797
+ $soContent
1798
+ .removeClass( 'so-panels-loading' )
1799
+ .html( html );
1800
+ } );
1801
+ },
1802
+
1803
+ /**
1804
+ * Save the widget from the form to the model
1805
+ */
1806
+ updateModel: function ( args ) {
1807
+ args = _.extend( {
1808
+ refresh: true,
1809
+ refreshArgs: null
1810
+ }, args );
1811
+
1812
+ // Get the values from the form and assign the new values to the model
1813
+ this.savingWidget = true;
1814
+
1815
+ if ( ! this.model.get( 'missing' ) ) {
1816
+ // Only get the values for non missing widgets.
1817
+ var values = this.getFormValues();
1818
+ if ( _.isUndefined( values.widgets ) ) {
1819
+ values = {};
1820
+ } else {
1821
+ values = values.widgets;
1822
+ values = values[Object.keys( values )[0]];
1823
+ }
1824
+
1825
+ this.model.setValues( values );
1826
+ this.model.set( 'raw', true ); // We've saved from the widget form, so this is now raw
1827
+ }
1828
+
1829
+ if ( this.styles.stylesLoaded ) {
1830
+ // If the styles view has loaded
1831
+ var style = {};
1832
+ try {
1833
+ style = this.getFormValues( '.so-sidebar .so-visual-styles' ).style;
1834
+ }
1835
+ catch ( e ) {
1836
+ }
1837
+ this.model.set( 'style', style );
1838
+ }
1839
+
1840
+ this.savingWidget = false;
1841
+
1842
+ if ( args.refresh ) {
1843
+ this.builder.model.refreshPanelsData( args.refreshArgs );
1844
+ }
1845
+ },
1846
+
1847
+ /**
1848
+ *
1849
+ */
1850
+ handleChangeValues: function () {
1851
+ if ( ! this.savingWidget ) {
1852
+ // Reload the form when we've changed the model and we're not currently saving from the form
1853
+ this.loadForm();
1854
+ }
1855
+ },
1856
+
1857
+ /**
1858
+ * Save a history entry for this widget. Called when the dialog is closed.
1859
+ */
1860
+ saveHandler: function () {
1861
+ this.builder.addHistoryEntry( 'widget_edited' );
1862
+ this.closeDialog();
1863
+ },
1864
+
1865
+ /**
1866
+ * When the user clicks delete.
1867
+ *
1868
+ * @returns {boolean}
1869
+ */
1870
+ deleteHandler: function () {
1871
+ this.widgetView.visualDestroyModel();
1872
+ this.closeDialog( {silent: true} );
1873
+ this.builder.model.refreshPanelsData();
1874
+
1875
+ return false;
1876
+ },
1877
+
1878
+ duplicateHandler: function () {
1879
+ // Call the widget duplicate handler directly
1880
+ this.widgetView.duplicateHandler();
1881
+
1882
+ this.closeDialog( {silent: true} );
1883
+ this.builder.model.refreshPanelsData();
1884
+
1885
+ return false;
1886
+ }
1887
+
1888
+ } );
1889
+
1890
+ },{"../view/widgets/js-widget":31}],10:[function(require,module,exports){
1891
+ var panels = window.panels, $ = jQuery;
1892
+
1893
+ module.exports = panels.view.dialog.extend( {
1894
+
1895
+ builder: null,
1896
+ widgetTemplate: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-dialog-widgets-widget' ).html() ) ),
1897
+ filter: {},
1898
+
1899
+ dialogClass: 'so-panels-dialog-add-widget',
1900
+ dialogIcon: 'add-widget',
1901
+
1902
+ events: {
1903
+ 'click .so-close': 'closeDialog',
1904
+ 'click .widget-type': 'widgetClickHandler',
1905
+ 'keyup .so-sidebar-search': 'searchHandler'
1906
+ },
1907
+
1908
+ /**
1909
+ * Initialize the widget adding dialog
1910
+ */
1911
+ initializeDialog: function () {
1912
+
1913
+ this.on( 'open_dialog', function () {
1914
+ this.filter.search = '';
1915
+ this.filterWidgets( this.filter );
1916
+ }, this );
1917
+
1918
+ this.on( 'open_dialog_complete', function () {
1919
+ // Clear the search and re-filter the widgets when we open the dialog
1920
+ this.$( '.so-sidebar-search' ).val( '' ).focus();
1921
+ this.balanceWidgetHeights();
1922
+ } );
1923
+
1924
+ // We'll implement a custom tab click handler
1925
+ this.on( 'tab_click', this.tabClickHandler, this );
1926
+ },
1927
+
1928
+ render: function () {
1929
+ // Render the dialog and attach it to the builder interface
1930
+ this.renderDialog( this.parseDialogContent( $( '#siteorigin-panels-dialog-widgets' ).html(), {} ) );
1931
+
1932
+ // Add all the widgets
1933
+ _.each( panelsOptions.widgets, function ( widget ) {
1934
+ var $w = $( this.widgetTemplate( {
1935
+ title: widget.title,
1936
+ description: widget.description
1937
+ } ) );
1938
+
1939
+ if ( _.isUndefined( widget.icon ) ) {
1940
+ widget.icon = 'dashicons dashicons-admin-generic';
1941
+ }
1942
+
1943
+ $( '<span class="widget-icon" />' ).addClass( widget.icon ).prependTo( $w.find( '.widget-type-wrapper' ) );
1944
+
1945
+ $w.data( 'class', widget.class ).appendTo( this.$( '.widget-type-list' ) );
1946
+ }, this );
1947
+
1948
+ // Add the sidebar tabs
1949
+ var tabs = this.$( '.so-sidebar-tabs' );
1950
+ _.each( panelsOptions.widget_dialog_tabs, function ( tab ) {
1951
+ $( this.dialogTabTemplate( {'title': tab.title} ) ).data( {
1952
+ 'message': tab.message,
1953
+ 'filter': tab.filter
1954
+ } ).appendTo( tabs );
1955
+ }, this );
1956
+
1957
+ // We'll be using tabs, so initialize them
1958
+ this.initTabs();
1959
+
1960
+ var thisDialog = this;
1961
+ $( window ).resize( function () {
1962
+ thisDialog.balanceWidgetHeights();
1963
+ } );
1964
+ },
1965
+
1966
+ /**
1967
+ * Handle a tab being clicked
1968
+ */
1969
+ tabClickHandler: function ( $t ) {
1970
+ // Get the filter from the tab, and filter the widgets
1971
+ this.filter = $t.parent().data( 'filter' );
1972
+ this.filter.search = this.$( '.so-sidebar-search' ).val();
1973
+
1974
+ var message = $t.parent().data( 'message' );
1975
+ if ( _.isEmpty( message ) ) {
1976
+ message = '';
1977
+ }
1978
+
1979
+ this.$( '.so-toolbar .so-status' ).html( message );
1980
+
1981
+ this.filterWidgets( this.filter );
1982
+
1983
+ return false;
1984
+ },
1985
+
1986
+ /**
1987
+ * Handle changes to the search value
1988
+ */
1989
+ searchHandler: function ( e ) {
1990
+ if( e.which === 13 ) {
1991
+ var visibleWidgets = this.$( '.widget-type-list .widget-type:visible' );
1992
+ if( visibleWidgets.length === 1 ) {
1993
+ visibleWidgets.click();
1994
+ }
1995
+ }
1996
+ else {
1997
+ this.filter.search = $( e.target ).val().trim();
1998
+ this.filterWidgets( this.filter );
1999
+ }
2000
+ },
2001
+
2002
+ /**
2003
+ * Filter the widgets that we're displaying
2004
+ * @param filter
2005
+ */
2006
+ filterWidgets: function ( filter ) {
2007
+ if ( _.isUndefined( filter ) ) {
2008
+ filter = {};
2009
+ }
2010
+
2011
+ if ( _.isUndefined( filter.groups ) ) {
2012
+ filter.groups = '';
2013
+ }
2014
+
2015
+ this.$( '.widget-type-list .widget-type' ).each( function () {
2016
+ var $$ = $( this ), showWidget;
2017
+ var widgetClass = $$.data( 'class' );
2018
+
2019
+ var widgetData = (
2020
+ ! _.isUndefined( panelsOptions.widgets[widgetClass] )
2021
+ ) ? panelsOptions.widgets[widgetClass] : null;
2022
+
2023
+ if ( _.isEmpty( filter.groups ) ) {
2024
+ // This filter doesn't specify groups, so show all
2025
+ showWidget = true;
2026
+ } else if ( widgetData !== null && ! _.isEmpty( _.intersection( filter.groups, panelsOptions.widgets[widgetClass].groups ) ) ) {
2027
+ // This widget is in the filter group
2028
+ showWidget = true;
2029
+ } else {
2030
+ // This widget is not in the filter group
2031
+ showWidget = false;
2032
+ }
2033
+
2034
+ // This can probably be done with a more intelligent operator
2035
+ if ( showWidget ) {
2036
+
2037
+ if ( ! _.isUndefined( filter.search ) && filter.search !== '' ) {
2038
+ // Check if the widget title contains the search term
2039
+ if ( widgetData.title.toLowerCase().indexOf( filter.search.toLowerCase() ) === - 1 ) {
2040
+ showWidget = false;
2041
+ }
2042
+ }
2043
+
2044
+ }
2045
+
2046
+ if ( showWidget ) {
2047
+ $$.show();
2048
+ } else {
2049
+ $$.hide();
2050
+ }
2051
+ } );
2052
+
2053
+ // Balance the tags after filtering
2054
+ this.balanceWidgetHeights();
2055
+ },
2056
+
2057
+ /**
2058
+ * Add the widget to the current builder
2059
+ *
2060
+ * @param e
2061
+ */
2062
+ widgetClickHandler: function ( e ) {
2063
+ // Add the history entry
2064
+ this.builder.trigger('before_user_adds_widget');
2065
+ this.builder.addHistoryEntry( 'widget_added' );
2066
+
2067
+ var $w = $( e.currentTarget );
2068
+
2069
+ var widget = new panels.model.widget( {
2070
+ class: $w.data( 'class' )
2071
+ } );
2072
+
2073
+ // Add the widget to the cell model
2074
+ widget.cell = this.builder.getActiveCell();
2075
+ widget.cell.get('widgets').add( widget );
2076
+
2077
+ this.closeDialog();
2078
+ this.builder.model.refreshPanelsData();
2079
+
2080
+ this.builder.trigger('after_user_adds_widget', widget);
2081
+ },
2082
+
2083
+ /**
2084
+ * Balance widgets in a given row so they have enqual height.
2085
+ * @param e
2086
+ */
2087
+ balanceWidgetHeights: function ( e ) {
2088
+ var widgetRows = [[]];
2089
+ var previousWidget = null;
2090
+
2091
+ // Work out how many widgets there are per row
2092
+ var perRow = Math.round( this.$( '.widget-type' ).parent().width() / this.$( '.widget-type' ).width() );
2093
+
2094
+ // Add clears to create balanced rows
2095
+ this.$( '.widget-type' )
2096
+ .css( 'clear', 'none' )
2097
+ .filter( ':visible' )
2098
+ .each( function ( i, el ) {
2099
+ if ( i % perRow === 0 && i !== 0 ) {
2100
+ $( el ).css( 'clear', 'both' );
2101
+ }
2102
+ } );
2103
+
2104
+ // Group the widgets into rows
2105
+ this.$( '.widget-type-wrapper' )
2106
+ .css( 'height', 'auto' )
2107
+ .filter( ':visible' )
2108
+ .each( function ( i, el ) {
2109
+ var $el = $( el );
2110
+ if ( previousWidget !== null && previousWidget.position().top !== $el.position().top ) {
2111
+ widgetRows[widgetRows.length] = [];
2112
+ }
2113
+ previousWidget = $el;
2114
+ widgetRows[widgetRows.length - 1].push( $el );
2115
+ } );
2116
+
2117
+ // Balance the height of the widgets within the row.
2118
+ _.each( widgetRows, function ( row, i ) {
2119
+ var maxHeight = _.max( row.map( function ( el ) {
2120
+ return el.height();
2121
+ } ) );
2122
+ // Set the height of each widget in the row
2123
+ _.each( row, function ( el ) {
2124
+ el.height( maxHeight );
2125
+ } );
2126
+
2127
+ } );
2128
+ }
2129
+ } );
2130
+
2131
+ },{}],11:[function(require,module,exports){
2132
+ module.exports = {
2133
+ /**
2134
+ * Check if we have copy paste available.
2135
+ * @returns {boolean|*}
2136
+ */
2137
+ canCopyPaste: function(){
2138
+ return typeof(Storage) !== "undefined" && panelsOptions.user;
2139
+ },
2140
+
2141
+ /**
2142
+ * Set the model that we're going to store in the clipboard
2143
+ */
2144
+ setModel: function( model ){
2145
+ if( ! this.canCopyPaste() ) {
2146
+ return false;
2147
+ }
2148
+
2149
+ var serial = panels.helpers.serialize.serialize( model );
2150
+ if( model instanceof panels.model.row ) {
2151
+ serial.thingType = 'row-model';
2152
+ } else if( model instanceof panels.model.widget ) {
2153
+ serial.thingType = 'widget-model';
2154
+ }
2155
+
2156
+ // Store this in local storage
2157
+ localStorage[ 'panels_clipboard_' + panelsOptions.user ] = JSON.stringify( serial );
2158
+ return true;
2159
+ },
2160
+
2161
+ /**
2162
+ * Check if the current model stored in the clipboard is the expected type
2163
+ */
2164
+ isModel: function( expected ){
2165
+ if( ! this.canCopyPaste() ) {
2166
+ return false;
2167
+ }
2168
+
2169
+ var clipboardObject = localStorage[ 'panels_clipboard_' + panelsOptions.user ];
2170
+ if( clipboardObject !== undefined ) {
2171
+ clipboardObject = JSON.parse(clipboardObject);
2172
+ return clipboardObject.thingType && clipboardObject.thingType === expected;
2173
+ }
2174
+
2175
+ return false;
2176
+ },
2177
+
2178
+ /**
2179
+ * Get the model currently stored in the clipboard
2180
+ */
2181
+ getModel: function( expected ){
2182
+ if( ! this.canCopyPaste() ) {
2183
+ return null;
2184
+ }
2185
+
2186
+ var clipboardObject = localStorage[ 'panels_clipboard_' + panelsOptions.user ];
2187
+ if( clipboardObject !== undefined ) {
2188
+ clipboardObject = JSON.parse( clipboardObject );
2189
+ if( clipboardObject.thingType && clipboardObject.thingType === expected ) {
2190
+ return panels.helpers.serialize.unserialize( clipboardObject, clipboardObject.thingType, null );
2191
+ }
2192
+ }
2193
+
2194
+ return null;
2195
+ },
2196
+ };
2197
+
2198
+ },{}],12:[function(require,module,exports){
2199
+ module.exports = {
2200
+ /**
2201
+ * Lock window scrolling for the main overlay
2202
+ */
2203
+ lock: function () {
2204
+ if ( jQuery( 'body' ).css( 'overflow' ) === 'hidden' ) {
2205
+ return;
2206
+ }
2207
+
2208
+ // lock scroll position, but retain settings for later
2209
+ var scrollPosition = [
2210
+ self.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
2211
+ self.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
2212
+ ];
2213
+
2214
+ jQuery( 'body' )
2215
+ .data( {
2216
+ 'scroll-position': scrollPosition
2217
+ } )
2218
+ .css( 'overflow', 'hidden' );
2219
+
2220
+ if( ! _.isUndefined( scrollPosition ) ) {
2221
+ window.scrollTo( scrollPosition[0], scrollPosition[1] );
2222
+ }
2223
+ },
2224
+
2225
+ /**
2226
+ * Unlock window scrolling
2227
+ */
2228
+ unlock: function () {
2229
+ if ( jQuery( 'body' ).css( 'overflow' ) !== 'hidden' ) {
2230
+ return;
2231
+ }
2232
+
2233
+ // Check that there are no more dialogs or a live editor
2234
+ if ( ! jQuery( '.so-panels-dialog-wrapper' ).is( ':visible' ) && ! jQuery( '.so-panels-live-editor' ).is( ':visible' ) ) {
2235
+ jQuery( 'body' ).css( 'overflow', 'visible' );
2236
+ var scrollPosition = jQuery( 'body' ).data( 'scroll-position' );
2237
+
2238
+ if( ! _.isUndefined( scrollPosition ) ) {
2239
+ window.scrollTo( scrollPosition[0], scrollPosition[1] );
2240
+ }
2241
+ }
2242
+ },
2243
+ };
2244
+
2245
+ },{}],13:[function(require,module,exports){
2246
+ /*
2247
+ This is a modified version of https://github.com/underdogio/backbone-serialize/
2248
+ */
2249
+
2250
+ /* global Backbone, module, panels */
2251
+
2252
+ module.exports = {
2253
+ serialize: function( thing ){
2254
+ var val;
2255
+
2256
+ if( thing instanceof Backbone.Model ) {
2257
+ var retObj = {};
2258
+ for ( var key in thing.attributes ) {
2259
+ if (thing.attributes.hasOwnProperty( key ) ) {
2260
+ // Skip these to avoid recursion
2261
+ if( key === 'builder' || key === 'collection' ) { continue; }
2262
+
2263
+ // If the value is a Model or a Collection, then serialize them as well
2264
+ val = thing.attributes[key];
2265
+ if ( val instanceof Backbone.Model || val instanceof Backbone.Collection ) {
2266
+ retObj[key] = this.serialize( val );
2267
+ } else {
2268
+ // Otherwise, save the original value
2269
+ retObj[key] = val;
2270
+ }
2271
+ }
2272
+ }
2273
+ return retObj;
2274
+ }
2275
+ else if( thing instanceof Backbone.Collection ) {
2276
+ // Walk over all of our models
2277
+ var retArr = [];
2278
+
2279
+ for ( var i = 0; i < thing.models.length; i++ ) {
2280
+ // If the model is serializable, then serialize it
2281
+ val = thing.models[i];
2282
+
2283
+ if ( val instanceof Backbone.Model || val instanceof Backbone.Collection ) {
2284
+ retArr.push( this.serialize( val ) );
2285
+ } else {
2286
+ // Otherwise (it is an object), return it in its current form
2287
+ retArr.push( val );
2288
+ }
2289
+ }
2290
+
2291
+ // Return the serialized models
2292
+ return retArr;
2293
+ }
2294
+ },
2295
+
2296
+ unserialize: function( thing, thingType, parent ) {
2297
+ var retObj;
2298
+
2299
+ switch( thingType ) {
2300
+ case 'row-model' :
2301
+ retObj = new panels.model.row();
2302
+ retObj.builder = parent;
2303
+ var atts = { style: thing.style };
2304
+ if ( thing.hasOwnProperty( 'label' ) ) {
2305
+ atts.label = thing.label;
2306
+ }
2307
+ if ( thing.hasOwnProperty( 'color_label' ) ) {
2308
+ atts.color_label = thing.color_label;
2309
+ }
2310
+ retObj.set( atts );
2311
+ retObj.setCells( this.unserialize( thing.cells, 'cell-collection', retObj ) );
2312
+ break;
2313
+
2314
+ case 'cell-model' :
2315
+ retObj = new panels.model.cell();
2316
+ retObj.row = parent;
2317
+ retObj.set( 'weight', thing.weight );
2318
+ retObj.set( 'style', thing.style );
2319
+ retObj.set( 'widgets', this.unserialize( thing.widgets, 'widget-collection', retObj ) );
2320
+ break;
2321
+
2322
+ case 'widget-model' :
2323
+ retObj = new panels.model.widget();
2324
+ retObj.cell = parent;
2325
+ for ( var key in thing ) {
2326
+ if ( thing.hasOwnProperty( key ) ) {
2327
+ retObj.set( key, thing[key] );
2328
+ }
2329
+ }
2330
+ retObj.set( 'widget_id', panels.helpers.utils.generateUUID() );
2331
+ break;
2332
+
2333
+ case 'cell-collection':
2334
+ retObj = new panels.collection.cells();
2335
+ for( var i = 0; i < thing.length; i++ ) {
2336
+ retObj.push( this.unserialize( thing[i], 'cell-model', parent ) );
2337
+ }
2338
+ break;
2339
+
2340
+ case 'widget-collection':
2341
+ retObj = new panels.collection.widgets();
2342
+ for( var i = 0; i < thing.length; i++ ) {
2343
+ retObj.push( this.unserialize( thing[i], 'widget-model', parent ) );
2344
+ }
2345
+ break;
2346
+
2347
+ default:
2348
+ console.log( 'Unknown Thing - ' + thingType );
2349
+ break;
2350
+ }
2351
+
2352
+ return retObj;
2353
+ }
2354
+ };
2355
+
2356
+ },{}],14:[function(require,module,exports){
2357
+ module.exports = {
2358
+
2359
+ generateUUID: function(){
2360
+ var d = new Date().getTime();
2361
+ if( window.performance && typeof window.performance.now === "function" ){
2362
+ d += performance.now(); //use high-precision timer if available
2363
+ }
2364
+ var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace( /[xy]/g, function(c) {
2365
+ var r = (d + Math.random()*16)%16 | 0;
2366
+ d = Math.floor(d/16);
2367
+ return ( c == 'x' ? r : (r&0x3|0x8) ).toString(16);
2368
+ } );
2369
+ return uuid;
2370
+ },
2371
+
2372
+ processTemplate: function ( s ) {
2373
+ if ( _.isUndefined( s ) || _.isNull( s ) ) {
2374
+ return '';
2375
+ }
2376
+ s = s.replace( /{{%/g, '<%' );
2377
+ s = s.replace( /%}}/g, '%>' );
2378
+ s = s.trim();
2379
+ return s;
2380
+ },
2381
+
2382
+ // From this SO post: http://stackoverflow.com/questions/6139107/programmatically-select-text-in-a-contenteditable-html-element
2383
+ selectElementContents: function( element ) {
2384
+ var range = document.createRange();
2385
+ range.selectNodeContents( element );
2386
+ var sel = window.getSelection();
2387
+ sel.removeAllRanges();
2388
+ sel.addRange( range );
2389
+ },
2390
+
2391
+ }
2392
+
2393
+ },{}],15:[function(require,module,exports){
2394
+ /* global _, jQuery, panels */
2395
+
2396
+ var panels = window.panels, $ = jQuery;
2397
+
2398
+ module.exports = function ( config, force ) {
2399
+
2400
+ return this.each( function () {
2401
+ var $$ = jQuery( this );
2402
+
2403
+ if ( $$.data( 'soPanelsBuilderWidgetInitialized' ) && ! force ) {
2404
+ return;
2405
+ }
2406
+ var widgetId = $$.closest( 'form' ).find( '.widget-id' ).val();
2407
+
2408
+ // Create a config for this specific widget
2409
+ var thisConfig = $.extend(true, {}, config);
2410
+
2411
+ // Exit if this isn't a real widget
2412
+ if ( ! _.isUndefined( widgetId ) && widgetId.indexOf( '__i__' ) > - 1 ) {
2413
+ return;
2414
+ }
2415
+
2416
+ // Create the main builder model
2417
+ var builderModel = new panels.model.builder();
2418
+
2419
+ // Now for the view to display the builder
2420
+ var builderView = new panels.view.builder( {
2421
+ model: builderModel,
2422
+ config: thisConfig
2423
+ } );
2424
+
2425
+ // Save panels data when we close the dialog, if we're in a dialog
2426
+ var dialog = $$.closest( '.so-panels-dialog-wrapper' ).data( 'view' );
2427
+ if ( ! _.isUndefined( dialog ) ) {
2428
+ dialog.on( 'close_dialog', function () {
2429
+ builderModel.refreshPanelsData();
2430
+ } );
2431
+
2432
+ dialog.on( 'open_dialog_complete', function () {
2433
+ // Make sure the new layout widget is always properly setup
2434
+ builderView.trigger( 'builder_resize' );
2435
+ } );
2436
+
2437
+ dialog.model.on( 'destroy', function () {
2438
+ // Destroy the builder
2439
+ builderModel.emptyRows().destroy();
2440
+ } );
2441
+
2442
+ // Set the parent for all the sub dialogs
2443
+ builderView.setDialogParents( panelsOptions.loc.layout_widget, dialog );
2444
+ }
2445
+
2446
+ // Basic setup for the builder
2447
+ var isWidget = Boolean( $$.closest( '.widget-content' ).length );
2448
+ builderView
2449
+ .render()
2450
+ .attach( {
2451
+ container: $$,
2452
+ dialog: isWidget || $$.data('mode') === 'dialog',
2453
+ type: $$.data( 'type' )
2454
+ } )
2455
+ .setDataField( $$.find( 'input.panels-data' ) );
2456
+
2457
+ if ( isWidget || $$.data('mode') === 'dialog' ) {
2458
+ // Set up the dialog opening
2459
+ builderView.setDialogParents( panelsOptions.loc.layout_widget, builderView.dialog );
2460
+ $$.find( '.siteorigin-panels-display-builder' ).click( function ( e ) {
2461
+ e.preventDefault();
2462
+ builderView.dialog.openDialog();
2463
+ } );
2464
+ } else {
2465
+ // Remove the dialog opener button, this is already being displayed in a page builder dialog.
2466
+ $$.find( '.siteorigin-panels-display-builder' ).parent().remove();
2467
+ }
2468
+
2469
+ // Trigger a global jQuery event after we've setup the builder view
2470
+ $( document ).trigger( 'panels_setup', builderView );
2471
+
2472
+ $$.data( 'soPanelsBuilderWidgetInitialized', true );
2473
+ } );
2474
+ };
2475
+
2476
+ },{}],16:[function(require,module,exports){
2477
+ /**
2478
+ * Everything we need for SiteOrigin Page Builder.
2479
+ *
2480
+ * @copyright Greg Priday 2013 - 2016 - <https://siteorigin.com/>
2481
+ * @license GPL 3.0 http://www.gnu.org/licenses/gpl.html
2482
+ */
2483
+
2484
+ /* global Backbone, _, jQuery, tinyMCE, panelsOptions, plupload, confirm, console, require */
2485
+
2486
+ var panels = {};
2487
+
2488
+ // Store everything globally
2489
+ window.panels = panels;
2490
+ window.siteoriginPanels = panels;
2491
+
2492
+ // Helpers
2493
+ panels.helpers = {};
2494
+ panels.helpers.clipboard = require( './helpers/clipboard' );
2495
+ panels.helpers.utils = require( './helpers/utils' );
2496
+ panels.helpers.serialize = require( './helpers/serialize' );
2497
+ panels.helpers.pageScroll = require( './helpers/page-scroll' );
2498
+
2499
+ // The models
2500
+ panels.model = {};
2501
+ panels.model.widget = require( './model/widget' );
2502
+ panels.model.cell = require( './model/cell' );
2503
+ panels.model.row = require( './model/row' );
2504
+ panels.model.builder = require( './model/builder' );
2505
+ panels.model.historyEntry = require( './model/history-entry' );
2506
+
2507
+ // The collections
2508
+ panels.collection = {};
2509
+ panels.collection.widgets = require( './collection/widgets' );
2510
+ panels.collection.cells = require( './collection/cells' );
2511
+ panels.collection.rows = require( './collection/rows' );
2512
+ panels.collection.historyEntries = require( './collection/history-entries' );
2513
+
2514
+ // The views
2515
+ panels.view = {};
2516
+ panels.view.widget = require( './view/widget' );
2517
+ panels.view.cell = require( './view/cell' );
2518
+ panels.view.row = require( './view/row' );
2519
+ panels.view.builder = require( './view/builder' );
2520
+ panels.view.dialog = require( './view/dialog' );
2521
+ panels.view.styles = require( './view/styles' );
2522
+ panels.view.liveEditor = require( './view/live-editor' );
2523
+
2524
+ // The dialogs
2525
+ panels.dialog = {};
2526
+ panels.dialog.builder = require( './dialog/builder' );
2527
+ panels.dialog.widgets = require( './dialog/widgets' );
2528
+ panels.dialog.widget = require( './dialog/widget' );
2529
+ panels.dialog.prebuilt = require( './dialog/prebuilt' );
2530
+ panels.dialog.row = require( './dialog/row' );
2531
+ panels.dialog.history = require( './dialog/history' );
2532
+
2533
+ // The utils
2534
+ panels.utils = {};
2535
+ panels.utils.menu = require( './utils/menu' );
2536
+
2537
+ // jQuery Plugins
2538
+ jQuery.fn.soPanelsSetupBuilderWidget = require( './jquery/setup-builder-widget' );
2539
+
2540
+
2541
+ // Set up Page Builder if we're on the main interface
2542
+ jQuery( function ( $ ) {
2543
+
2544
+ var container,
2545
+ field,
2546
+ form,
2547
+ builderConfig;
2548
+
2549
+ var $panelsMetabox = $( '#siteorigin-panels-metabox' );
2550
+ form = $( 'form#post' );
2551
+ if ( $panelsMetabox.length && form.length ) {
2552
+ // This is usually the case when we're in the post edit interface
2553
+ container = $panelsMetabox;
2554
+ field = $panelsMetabox.find( '.siteorigin-panels-data-field' );
2555
+
2556
+ builderConfig = {
2557
+ editorType: 'tinyMCE',
2558
+ postId: $( '#post_ID' ).val(),
2559
+ editorId: '#content',
2560
+ builderType: $panelsMetabox.data( 'builder-type' ),
2561
+ builderSupports: $panelsMetabox.data( 'builder-supports' ),
2562
+ loadOnAttach: panelsOptions.loadOnAttach && $( '#auto_draft' ).val() == 1,
2563
+ loadLiveEditor: $panelsMetabox.data('live-editor') == 1,
2564
+ liveEditorPreview: container.data('preview-url')
2565
+ };
2566
+ }
2567
+ else if ( $( '.siteorigin-panels-builder-form' ).length ) {
2568
+ // We're dealing with another interface like the custom home page interface
2569
+ var $$ = $( '.siteorigin-panels-builder-form' );
2570
+
2571
+ container = $$.find( '.siteorigin-panels-builder-container' );
2572
+ field = $$.find( 'input[name="panels_data"]' );
2573
+ form = $$;
2574
+
2575
+ builderConfig = {
2576
+ editorType: 'standalone',
2577
+ postId: $$.data( 'post-id' ),
2578
+ editorId: '#post_content',
2579
+ builderType: $$.data( 'type' ),
2580
+ builderSupports: $$.data( 'builder-supports' ),
2581
+ loadLiveEditor: false,
2582
+ liveEditorPreview: $$.data( 'preview-url' )
2583
+ };
2584
+ }
2585
+
2586
+ if ( ! _.isUndefined( container ) ) {
2587
+ // If we have a container, then set up the main builder
2588
+ var panels = window.siteoriginPanels;
2589
+
2590
+ // Create the main builder model
2591
+ var builderModel = new panels.model.builder();
2592
+
2593
+ // Now for the view to display the builder
2594
+ var builderView = new panels.view.builder( {
2595
+ model: builderModel,
2596
+ config: builderConfig
2597
+ } );
2598
+
2599
+ // Set up the builder view
2600
+ builderView
2601
+ .render()
2602
+ .attach( {
2603
+ container: container
2604
+ } )
2605
+ .setDataField( field )
2606
+ .attachToEditor();
2607
+
2608
+ // When the form is submitted, update the panels data
2609
+ form.submit( function () {
2610
+ // Refresh the data
2611
+ builderModel.refreshPanelsData();
2612
+ } );
2613
+
2614
+ container.removeClass( 'so-panels-loading' );
2615
+
2616
+ // Trigger a global jQuery event after we've setup the builder view. Everything is accessible form there
2617
+ $( document ).trigger( 'panels_setup', builderView, window.panels );
2618
+ }
2619
+
2620
+ // Setup new widgets when they're added in the standard widget interface
2621
+ $( document ).on( 'widget-added', function ( e, widget ) {
2622
+ $( widget ).find( '.siteorigin-page-builder-widget' ).soPanelsSetupBuilderWidget();
2623
+ } );
2624
+
2625
+ // Setup existing widgets on the page (for the widgets interface)
2626
+ if ( ! $( 'body' ).hasClass( 'wp-customizer' ) ) {
2627
+ $( function () {
2628
+ $( '.siteorigin-page-builder-widget' ).soPanelsSetupBuilderWidget();
2629
+ } );
2630
+ }
2631
+
2632
+ // A global escape handler
2633
+ $(window).on('keyup', function(e){
2634
+ // [Esc] to close
2635
+ if ( e.which === 27 ) {
2636
+ // Trigger a click on the last visible Page Builder window
2637
+ $( '.so-panels-dialog-wrapper, .so-panels-live-editor' ).filter(':visible')
2638
+ .last().find('.so-title-bar .so-close, .live-editor-close').click();
2639
+ }
2640
+ });
2641
+ } );
2642
+
2643
+ },{"./collection/cells":1,"./collection/history-entries":2,"./collection/rows":3,"./collection/widgets":4,"./dialog/builder":5,"./dialog/history":6,"./dialog/prebuilt":7,"./dialog/row":8,"./dialog/widget":9,"./dialog/widgets":10,"./helpers/clipboard":11,"./helpers/page-scroll":12,"./helpers/serialize":13,"./helpers/utils":14,"./jquery/setup-builder-widget":15,"./model/builder":17,"./model/cell":18,"./model/history-entry":19,"./model/row":20,"./model/widget":21,"./utils/menu":22,"./view/builder":23,"./view/cell":24,"./view/dialog":25,"./view/live-editor":26,"./view/row":27,"./view/styles":28,"./view/widget":29}],17:[function(require,module,exports){
2644
+ module.exports = Backbone.Model.extend({
2645
+ layoutPosition: {
2646
+ BEFORE: 'before',
2647
+ AFTER: 'after',
2648
+ REPLACE: 'replace',
2649
+ },
2650
+
2651
+ rows: {},
2652
+
2653
+ defaults: {
2654
+ 'data': {
2655
+ 'widgets': [],
2656
+ 'grids': [],
2657
+ 'grid_cells': []
2658
+ }
2659
+ },
2660
+
2661
+ initialize: function () {
2662
+ // These are the main rows in the interface
2663
+ this.set( 'rows', new panels.collection.rows() );
2664
+ },
2665
+
2666
+ /**
2667
+ * Add a new row to this builder.
2668
+ *
2669
+ * @param attrs
2670
+ * @param cells
2671
+ * @param options
2672
+ */
2673
+ addRow: function (attrs, cells, options) {
2674
+ options = _.extend({
2675
+ noAnimate: false
2676
+ }, options);
2677
+
2678
+ var cellCollection = new panels.collection.cells(cells);
2679
+
2680
+ attrs = _.extend({
2681
+ collection: this.get('rows'),
2682
+ cells: cellCollection,
2683
+ }, attrs);
2684
+
2685
+ // Create the actual row
2686
+ var row = new panels.model.row(attrs);
2687
+ row.builder = this;
2688
+
2689
+ this.get('rows').add( row, options );
2690
+
2691
+ return row;
2692
+ },
2693
+
2694
+ /**
2695
+ * Load the panels data into the builder
2696
+ *
2697
+ * @param data Object the layout and widgets data to load.
2698
+ * @param position string Where to place the new layout. Allowed options are 'before', 'after'. Anything else will
2699
+ * cause the new layout to replace the old one.
2700
+ */
2701
+ loadPanelsData: function ( data, position ) {
2702
+ try {
2703
+ if ( position === this.layoutPosition.BEFORE ) {
2704
+ data = this.concatPanelsData( data, this.getPanelsData() );
2705
+ } else if ( position === this.layoutPosition.AFTER ) {
2706
+ data = this.concatPanelsData( this.getPanelsData(), data );
2707
+ }
2708
+
2709
+ // Start by destroying any rows that currently exist. This will in turn destroy cells, widgets and all the associated views
2710
+ this.emptyRows();
2711
+
2712
+ // This will empty out the current rows and reload the builder data.
2713
+ this.set( 'data', JSON.parse( JSON.stringify( data ) ), {silent: true} );
2714
+
2715
+ var cit = 0;
2716
+ var rows = [];
2717
+
2718
+ if ( _.isUndefined( data.grid_cells ) ) {
2719
+ this.trigger( 'load_panels_data' );
2720
+ return;
2721
+ }
2722
+
2723
+ var gi;
2724
+ for ( var ci = 0; ci < data.grid_cells.length; ci ++ ) {
2725
+ gi = parseInt( data.grid_cells[ci].grid );
2726
+ if ( _.isUndefined( rows[gi] ) ) {
2727
+ rows[gi] = [];
2728
+ }
2729
+
2730
+ rows[gi].push( data.grid_cells[ci] );
2731
+ }
2732
+
2733
+ var builderModel = this;
2734
+ _.each( rows, function ( row, i ) {
2735
+ var rowAttrs = {};
2736
+
2737
+ if ( ! _.isUndefined( data.grids[i].style ) ) {
2738
+ rowAttrs.style = data.grids[i].style;
2739
+ }
2740
+
2741
+ if ( ! _.isUndefined( data.grids[i].ratio) ) {
2742
+ rowAttrs.ratio = data.grids[i].ratio;
2743
+ }
2744
+
2745
+ if ( ! _.isUndefined( data.grids[i].ratio_direction) ) {
2746
+ rowAttrs.ratio_direction = data.grids[i].ratio_direction
2747
+ }
2748
+
2749
+ if ( ! _.isUndefined( data.grids[i].color_label) ) {
2750
+ rowAttrs.color_label = data.grids[i].color_label;
2751
+ }
2752
+
2753
+ if ( ! _.isUndefined( data.grids[i].label) ) {
2754
+ rowAttrs.label = data.grids[i].label;
2755
+ }
2756
+ // This will create and add the row model and its cells
2757
+ builderModel.addRow(rowAttrs, row, {noAnimate: true} );
2758
+ } );
2759
+
2760
+
2761
+ if ( _.isUndefined( data.widgets ) ) {
2762
+ return;
2763
+ }
2764
+
2765
+ // Add the widgets
2766
+ _.each( data.widgets, function ( widgetData ) {
2767
+ var panels_info = null;
2768
+ if ( ! _.isUndefined( widgetData.panels_info ) ) {
2769
+ panels_info = widgetData.panels_info;
2770
+ delete widgetData.panels_info;
2771
+ } else {
2772
+ panels_info = widgetData.info;
2773
+ delete widgetData.info;
2774
+ }
2775
+
2776
+ var row = builderModel.get('rows').at( parseInt( panels_info.grid ) );
2777
+ var cell = row.get('cells').at( parseInt( panels_info.cell ) );
2778
+
2779
+ var newWidget = new panels.model.widget( {
2780
+ class: panels_info.class,
2781
+ values: widgetData
2782
+ } );
2783
+
2784
+ if ( ! _.isUndefined( panels_info.style ) ) {
2785
+ newWidget.set( 'style', panels_info.style );
2786
+ }
2787
+
2788
+ if ( ! _.isUndefined( panels_info.read_only ) ) {
2789
+ newWidget.set( 'read_only', panels_info.read_only );
2790
+ }
2791
+ if ( ! _.isUndefined( panels_info.widget_id ) ) {
2792
+ newWidget.set( 'widget_id', panels_info.widget_id );
2793
+ }
2794
+ else {
2795
+ newWidget.set( 'widget_id', panels.helpers.utils.generateUUID() );
2796
+ }
2797
+
2798
+ if ( ! _.isUndefined( panels_info.label ) ) {
2799
+ newWidget.set( 'label', panels_info.label );
2800
+ }
2801
+
2802
+ newWidget.cell = cell;
2803
+ cell.get('widgets').add( newWidget, { noAnimate: true } );
2804
+ } );
2805
+
2806
+ this.trigger( 'load_panels_data' );
2807
+ }
2808
+ catch ( err ) {
2809
+ console.log( 'Error loading data: ' + err.message );
2810
+
2811
+ }
2812
+ },
2813
+
2814
+ /**
2815
+ * Concatenate the second set of Page Builder data to the first. There is some validation of input, but for the most
2816
+ * part it's up to the caller to ensure the Page Builder data is well formed.
2817
+ */
2818
+ concatPanelsData: function ( panelsDataA, panelsDataB ) {
2819
+
2820
+ if ( _.isUndefined( panelsDataB ) || _.isUndefined( panelsDataB.grids ) || _.isEmpty( panelsDataB.grids ) ||
2821
+ _.isUndefined( panelsDataB.grid_cells ) || _.isEmpty( panelsDataB.grid_cells ) ) {
2822
+ return panelsDataA;
2823
+ }
2824
+
2825
+ if ( _.isUndefined( panelsDataA ) || _.isUndefined( panelsDataA.grids ) || _.isEmpty( panelsDataA.grids ) ) {
2826
+ return panelsDataB;
2827
+ }
2828
+
2829
+ var gridsBOffset = panelsDataA.grids.length;
2830
+ var widgetsBOffset = ! _.isUndefined( panelsDataA.widgets ) ? panelsDataA.widgets.length : 0;
2831
+ var newPanelsData = {grids: [], 'grid_cells': [], 'widgets': []};
2832
+
2833
+ // Concatenate grids (rows)
2834
+ newPanelsData.grids = panelsDataA.grids.concat( panelsDataB.grids );
2835
+
2836
+ // Create a copy of panelsDataA grid_cells and widgets
2837
+ if ( ! _.isUndefined( panelsDataA.grid_cells ) ) {
2838
+ newPanelsData.grid_cells = panelsDataA.grid_cells.slice();
2839
+ }
2840
+ if ( ! _.isUndefined( panelsDataA.widgets ) ) {
2841
+ newPanelsData.widgets = panelsDataA.widgets.slice();
2842
+ }
2843
+
2844
+ var i;
2845
+ // Concatenate grid cells (row columns)
2846
+ for ( i = 0; i < panelsDataB.grid_cells.length; i ++ ) {
2847
+ var gridCellB = panelsDataB.grid_cells[i];
2848
+ gridCellB.grid = parseInt( gridCellB.grid ) + gridsBOffset;
2849
+ newPanelsData.grid_cells.push( gridCellB );
2850
+ }
2851
+
2852
+ // Concatenate widgets
2853
+ if ( ! _.isUndefined( panelsDataB.widgets ) ) {
2854
+ for ( i = 0; i < panelsDataB.widgets.length; i ++ ) {
2855
+ var widgetB = panelsDataB.widgets[i];
2856
+ widgetB.panels_info.grid = parseInt( widgetB.panels_info.grid ) + gridsBOffset;
2857
+ widgetB.panels_info.id = parseInt( widgetB.panels_info.id ) + widgetsBOffset;
2858
+ newPanelsData.widgets.push( widgetB );
2859
+ }
2860
+ }
2861
+
2862
+ return newPanelsData;
2863
+ },
2864
+
2865
+ /**
2866
+ * Convert the content of the builder into a object that represents the page builder data
2867
+ */
2868
+ getPanelsData: function () {
2869
+
2870
+ var builder = this;
2871
+
2872
+ var data = {
2873
+ 'widgets': [],
2874
+ 'grids': [],
2875
+ 'grid_cells': []
2876
+ };
2877
+ var widgetId = 0;
2878
+
2879
+ this.get('rows').each( function ( row, ri ) {
2880
+
2881
+ row.get('cells').each( function ( cell, ci ) {
2882
+
2883
+ cell.get('widgets').each( function ( widget, wi ) {
2884
+ // Add the data for the widget, including the panels_info field.
2885
+ var panels_info = {
2886
+ class: widget.get( 'class' ),
2887
+ raw: widget.get( 'raw' ),
2888
+ grid: ri,
2889
+ cell: ci,
2890
+ // Strictly this should be an index
2891
+ id: widgetId ++,
2892
+ widget_id: widget.get( 'widget_id' ),
2893
+ style: widget.get( 'style' ),
2894
+ label: widget.get( 'label' ),
2895
+ };
2896
+
2897
+ if( _.isEmpty( panels_info.widget_id ) ) {
2898
+ panels_info.widget_id = panels.helpers.utils.generateUUID();
2899
+ }
2900
+
2901
+ var values = _.extend( _.clone( widget.get( 'values' ) ), {
2902
+ panels_info: panels_info
2903
+ } );
2904
+ data.widgets.push( values );
2905
+ } );
2906
+
2907
+ // Add the cell info
2908
+ data.grid_cells.push( {
2909
+ grid: ri,
2910
+ index: ci,
2911
+ weight: cell.get( 'weight' ),
2912
+ style: cell.get( 'style' ),
2913
+ } );
2914
+
2915
+ } );
2916
+
2917
+ data.grids.push( {
2918
+ cells: row.get('cells').length,
2919
+ style: row.get( 'style' ),
2920
+ ratio: row.get('ratio'),
2921
+ ratio_direction: row.get('ratio_direction'),
2922
+ color_label: row.get( 'color_label' ),
2923
+ label: row.get( 'label' ),
2924
+ } );
2925
+
2926
+ } );
2927
+
2928
+ return data;
2929
+
2930
+ },
2931
+
2932
+ /**
2933
+ * This will check all the current entries and refresh the panels data
2934
+ */
2935
+ refreshPanelsData: function ( args ) {
2936
+ args = _.extend( {
2937
+ silent: false
2938
+ }, args );
2939
+
2940
+ var oldData = this.get( 'data' );
2941
+ var newData = this.getPanelsData();
2942
+ this.set( 'data', newData, {silent: true} );
2943
+
2944
+ if ( ! args.silent && JSON.stringify( newData ) !== JSON.stringify( oldData ) ) {
2945
+ // The default change event doesn't trigger on deep changes, so we'll trigger our own
2946
+ this.trigger( 'change' );
2947
+ this.trigger( 'change:data' );
2948
+ this.trigger( 'refresh_panels_data', newData, args );
2949
+ }
2950
+ },
2951
+
2952
+ /**
2953
+ * Empty all the rows and the cells/widgets they contain.
2954
+ */
2955
+ emptyRows: function () {
2956
+ _.invoke( this.get('rows').toArray(), 'destroy' );
2957
+ this.get('rows').reset();
2958
+
2959
+ return this;
2960
+ },
2961
+
2962
+ isValidLayoutPosition: function ( position ) {
2963
+ return position === this.layoutPosition.BEFORE ||
2964
+ position === this.layoutPosition.AFTER ||
2965
+ position === this.layoutPosition.REPLACE;
2966
+ },
2967
+
2968
+ /**
2969
+ * Convert HTML into Panels Data
2970
+ * @param html
2971
+ */
2972
+ getPanelsDataFromHtml: function( html, editorClass ){
2973
+ var thisModel = this;
2974
+ var $html = jQuery( '<div id="wrapper">' + html + '</div>' );
2975
+
2976
+ if( $html.find('.panel-layout .panel-grid').length ) {
2977
+ // This looks like Page Builder html, lets try parse it
2978
+ var panels_data = {
2979
+ grids: [],
2980
+ grid_cells: [],
2981
+ widgets: [],
2982
+ };
2983
+
2984
+ // The Regex object that'll match SiteOrigin widgets
2985
+ var re = new RegExp( panelsOptions.siteoriginWidgetRegex , "i" );
2986
+ var decodeEntities = (function() {
2987
+ // this prevents any overhead from creating the object each time
2988
+ var element = document.createElement('div');
2989
+
2990
+ function decodeHTMLEntities (str) {
2991
+ if(str && typeof str === 'string') {
2992
+ // strip script/html tags
2993
+ str = str.replace(/<script[^>]*>([\S\s]*?)<\/script>/gmi, '');
2994
+ str = str.replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/gmi, '');
2995
+ element.innerHTML = str;
2996
+ str = element.textContent;
2997
+ element.textContent = '';
2998
+ }
2999
+
3000
+ return str;
3001
+ }
3002
+
3003
+ return decodeHTMLEntities;
3004
+ })();
3005
+
3006
+ // Remove all wrapping divs from a widget to get its html
3007
+ var getTextWidgetContents = function( $el ){
3008
+ var $divs = $el.find( 'div' );
3009
+ if( ! $divs.length ) {
3010
+ return $el.html();
3011
+ }
3012
+
3013
+ var i;
3014
+ for( i = 0; i < $divs.length - 1; i++ ) {
3015
+ if( jQuery.trim( $divs.eq(i).text() ) != jQuery.trim( $divs.eq(i+1).text() ) ) {
3016
+ break;
3017
+ }
3018
+ }
3019
+
3020
+ var title = $divs.eq( i ).find( '.widget-title:header' ),
3021
+ titleText = '';
3022
+
3023
+ if( title.length ) {
3024
+ titleText = title.html();
3025
+ title.remove();
3026
+ }
3027
+
3028
+ return {
3029
+ title: titleText,
3030
+ text: $divs.eq(i).html(),
3031
+ };
3032
+ };
3033
+
3034
+ var $layout = $html.find( '.panel-layout' ).eq(0);
3035
+ var filterNestedLayout = function( i, el ){
3036
+ return jQuery( el ).closest( '.panel-layout' ).is( $layout );
3037
+ };
3038
+
3039
+ $html.find('> .panel-layout > .panel-grid').filter( filterNestedLayout ).each( function( ri, el ){
3040
+ var $row = jQuery( el ),
3041
+ $cells = $row.find( '.panel-grid-cell' ).filter( filterNestedLayout );
3042
+
3043
+ panels_data.grids.push( {
3044
+ cells: $cells.length,
3045
+ style: $row.data( 'style' ),
3046
+ ratio: $row.data( 'ratio' ),
3047
+ ratio_direction: $row.data( 'ratio-direction' ),
3048
+ color_label: $row.data( 'color-label' ),
3049
+ label: $row.data( 'label' ),
3050
+ } );
3051
+
3052
+ $cells.each( function( ci, el ){
3053
+ var $cell = jQuery( el ),
3054
+ $widgets = $cell.find( '.so-panel' ).filter( filterNestedLayout );
3055
+
3056
+ panels_data.grid_cells.push( {
3057
+ grid: ri,
3058
+ weight: ! _.isUndefined( $cell.data( 'weight' ) ) ? parseFloat( $cell.data( 'weight' ) ) : 1,
3059
+ style: $cell.data( 'style' ),
3060
+ } );
3061
+
3062
+ $widgets.each( function( wi, el ){
3063
+ var $widget = jQuery(el),
3064
+ widgetContent = $widget.find('.panel-widget-style').length ? $widget.find('.panel-widget-style').html() : $widget.html(),
3065
+ panels_info = {
3066
+ grid: ri,
3067
+ cell: ci,
3068
+ style: $widget.data( 'style' ),
3069
+ raw: false,
3070
+ label: $widget.data( 'label' )
3071
+ };
3072
+
3073
+ widgetContent = widgetContent.trim();
3074
+
3075
+ // Check if this is a SiteOrigin Widget
3076
+ var match = re.exec( widgetContent );
3077
+ if( ! _.isNull( match ) && widgetContent.replace( re, '' ).trim() === '' ) {
3078
+ try {
3079
+ var classMatch = /class="(.*?)"/.exec( match[3] ),
3080
+ dataInput = jQuery( match[5] ),
3081
+ data = JSON.parse( decodeEntities( dataInput.val( ) ) ),
3082
+ newWidget = data.instance;
3083
+
3084
+ panels_info.class = classMatch[1].replace( /\\\\+/g, '\\' );
3085
+ panels_info.raw = false;
3086
+
3087
+ newWidget.panels_info = panels_info;
3088
+ panels_data.widgets.push( newWidget );
3089
+ }
3090
+ catch ( err ) {
3091
+ // There was a problem, so treat this as a standard editor widget
3092
+ panels_info.class = editorClass;
3093
+ panels_data.widgets.push( _.extend( getTextWidgetContents( $widget ), {
3094
+ filter: "1",
3095
+ type: "visual",
3096
+ panels_info: panels_info
3097
+ } ) );
3098
+ }
3099
+
3100
+ // Continue
3101
+ return true;
3102
+ }
3103
+ else if( widgetContent.indexOf( 'panel-layout' ) !== -1 ) {
3104
+ // Check if this is a layout widget
3105
+ var $widgetContent = jQuery( '<div>' + widgetContent + '</div>' );
3106
+ if( $widgetContent.find('.panel-layout .panel-grid').length ) {
3107
+ // This is a standard editor class widget
3108
+ panels_info.class = 'SiteOrigin_Panels_Widgets_Layout';
3109
+ panels_data.widgets.push( {
3110
+ panels_data: thisModel.getPanelsDataFromHtml( widgetContent, editorClass ),
3111
+ panels_info: panels_info
3112
+ } );
3113
+
3114
+ // continue
3115
+ return true;
3116
+ }
3117
+ }
3118
+
3119
+ // This is a standard editor class widget
3120
+ panels_info.class = editorClass;
3121
+ panels_data.widgets.push( _.extend( getTextWidgetContents( $widget ), {
3122
+ filter: "1",
3123
+ type: "visual",
3124
+ panels_info: panels_info
3125
+ } ) );
3126
+ return true;
3127
+ } );
3128
+ } );
3129
+ } );
3130
+
3131
+ // Remove all the Page Builder content
3132
+ $html.find('.panel-layout').remove();
3133
+ $html.find('style[data-panels-style-for-post]').remove();
3134
+
3135
+ // If there's anything left, add it to an editor widget at the end of panels_data
3136
+ if( $html.html().replace(/^\s+|\s+$/gm,'').length ) {
3137
+ panels_data.grids.push( {
3138
+ cells: 1,
3139
+ style: {},
3140
+ } );
3141
+ panels_data.grid_cells.push( {
3142
+ grid: panels_data.grids.length - 1,
3143
+ weight: 1,
3144
+ } );
3145
+ panels_data.widgets.push( {
3146
+ filter: "1",
3147
+ text: $html.html().replace(/^\s+|\s+$/gm,''),
3148
+ title: "",
3149
+ type: "visual",
3150
+ panels_info: {
3151
+ class: editorClass,
3152
+ raw: false,
3153
+ grid: panels_data.grids.length - 1,
3154
+ cell: 0
3155
+ }
3156
+ } );
3157
+ }
3158
+
3159
+ return panels_data;
3160
+ }
3161
+ else {
3162
+ // This is probably just old school post content
3163
+ return {
3164
+ grid_cells: [ { grid: 0, weight: 1 } ],
3165
+ grids: [ { cells: 1 } ],
3166
+ widgets: [
3167
+ {
3168
+ filter: "1",
3169
+ text: html,
3170
+ title: "",
3171
+ type: "visual",
3172
+ panels_info: {
3173
+ class: editorClass,
3174
+ raw: false,
3175
+ grid: 0,
3176
+ cell: 0
3177
+ }
3178
+ }
3179
+ ]
3180
+ };
3181
+ }
3182
+ }
3183
+ } );
3184
+
3185
+ },{}],18:[function(require,module,exports){
3186
+ module.exports = Backbone.Model.extend( {
3187
+ /* A collection of widgets */
3188
+ widgets: {},
3189
+
3190
+ /* The row this model belongs to */
3191
+ row: null,
3192
+
3193
+ defaults: {
3194
+ weight: 0,
3195
+ style: {}
3196
+ },
3197
+
3198
+ indexes: null,
3199
+
3200
+ /**
3201
+ * Set up the cell model
3202
+ */
3203
+ initialize: function () {
3204
+ this.set( 'widgets', new panels.collection.widgets() );
3205
+ this.on( 'destroy', this.onDestroy, this );
3206
+ },
3207
+
3208
+ /**
3209
+ * Triggered when we destroy a cell
3210
+ */
3211
+ onDestroy: function () {
3212
+ // Destroy all the widgets
3213
+ _.invoke( this.get('widgets').toArray(), 'destroy' );
3214
+ this.get('widgets').reset();
3215
+ },
3216
+
3217
+ /**
3218
+ * Create a clone of the cell, along with all its widgets
3219
+ */
3220
+ clone: function ( row, cloneOptions ) {
3221
+ if ( _.isUndefined( row ) ) {
3222
+ row = this.row;
3223
+ }
3224
+ cloneOptions = _.extend( {cloneWidgets: true}, cloneOptions );
3225
+
3226
+ var clone = new this.constructor( this.attributes );
3227
+ clone.set( 'collection', row.get('cells'), {silent: true} );
3228
+ clone.row = row;
3229
+
3230
+ if ( cloneOptions.cloneWidgets ) {
3231
+ // Now we're going add all the widgets that belong to this, to the clone
3232
+ this.get('widgets').each( function ( widget ) {
3233
+ clone.get('widgets').add( widget.clone( clone, cloneOptions ), {silent: true} );
3234
+ } );
3235
+ }
3236
+
3237
+ return clone;
3238
+ }
3239
+
3240
+ } );
3241
+
3242
+ },{}],19:[function(require,module,exports){
3243
+ module.exports = Backbone.Model.extend( {
3244
+ defaults: {
3245
+ text: '',
3246
+ data: '',
3247
+ time: null,
3248
+ count: 1
3249
+ }
3250
+ } );
3251
+
3252
+ },{}],20:[function(require,module,exports){
3253
+ module.exports = Backbone.Model.extend( {
3254
+ /* The builder model */
3255
+ builder: null,
3256
+
3257
+ defaults: {
3258
+ style: {}
3259
+ },
3260
+
3261
+ indexes: null,
3262
+
3263
+ /**
3264
+ * Initialize the row model
3265
+ */
3266
+ initialize: function () {
3267
+ if ( _.isEmpty(this.get('cells') ) ) {
3268
+ this.set('cells', new panels.collection.cells());
3269
+ }
3270
+ else {
3271
+ // Make sure that the cells have this row set as their parent
3272
+ this.get('cells').each( function( cell ){
3273
+ cell.row = this;
3274
+ }.bind( this ) );
3275
+ }
3276
+ this.on( 'destroy', this.onDestroy, this );
3277
+ },
3278
+
3279
+ /**
3280
+ * Add cells to the model row
3281
+ *
3282
+ * @param newCells the updated collection of cell models
3283
+ */
3284
+ setCells: function ( newCells ) {
3285
+ var currentCells = this.get('cells') || new panels.collection.cells();
3286
+ var cellsToRemove = [];
3287
+
3288
+ currentCells.each(function (cell, i) {
3289
+ var newCell = newCells.at(i);
3290
+ if(newCell) {
3291
+ cell.set('weight', newCell.get('weight'));
3292
+ } else {
3293
+ var newParentCell = currentCells.at( newCells.length - 1 );
3294
+
3295
+ // First move all the widgets to the new cell
3296
+ var widgetsToMove = cell.get('widgets').models.slice();
3297
+ for ( var j = 0; j < widgetsToMove.length; j++ ) {
3298
+ widgetsToMove[j].moveToCell( newParentCell, { silent: false } );
3299
+ }
3300
+
3301
+ cellsToRemove.push(cell);
3302
+ }
3303
+ });
3304
+
3305
+ _.each(cellsToRemove, function(cell) {
3306
+ currentCells.remove(cell);
3307
+ });
3308
+
3309
+ if( newCells.length > currentCells.length) {
3310
+ _.each(newCells.slice(currentCells.length, newCells.length), function (newCell) {
3311
+ // TODO: make sure row and collection is set correctly when cell is created then we can just add new cells
3312
+ newCell.set({collection: currentCells});
3313
+ newCell.row = this;
3314
+ currentCells.add(newCell);
3315
+ }.bind(this));
3316
+ }
3317
+
3318
+ // Rescale the cells when we add or remove
3319
+ this.reweightCells();
3320
+ },
3321
+
3322
+ /**
3323
+ * Make sure that all the cell weights add up to 1
3324
+ */
3325
+ reweightCells: function () {
3326
+ var totalWeight = 0;
3327
+ var cells = this.get('cells');
3328
+ cells.each( function ( cell ) {
3329
+ totalWeight += cell.get( 'weight' );
3330
+ } );
3331
+
3332
+ cells.each( function ( cell ) {
3333
+ cell.set( 'weight', cell.get( 'weight' ) / totalWeight );
3334
+ } );
3335
+
3336
+ // This is for the row view to hook into and resize
3337
+ this.trigger( 'reweight_cells' );
3338
+ },
3339
+
3340
+ /**
3341
+ * Triggered when the model is destroyed
3342
+ */
3343
+ onDestroy: function () {
3344
+ // Also destroy all the cells
3345
+ _.invoke( this.get('cells').toArray(), 'destroy' );
3346
+ this.get('cells').reset();
3347
+ },
3348
+
3349
+ /**
3350
+ * Create a clone of the row, along with all its cells
3351
+ *
3352
+ * @param {panels.model.builder} builder The builder model to attach this to.
3353
+ *
3354
+ * @return {panels.model.row} The cloned row.
3355
+ */
3356
+ clone: function ( builder ) {
3357
+ if ( _.isUndefined( builder ) ) {
3358
+ builder = this.builder;
3359
+ }
3360
+
3361
+ var clone = new this.constructor( this.attributes );
3362
+ clone.set( 'collection', builder.get('rows'), {silent: true} );
3363
+ clone.builder = builder;
3364
+
3365
+ var cellClones = new panels.collection.cells();
3366
+ this.get('cells').each( function ( cell ) {
3367
+ cellClones.add( cell.clone( clone ), {silent: true} );
3368
+ } );
3369
+
3370
+ clone.set( 'cells', cellClones );
3371
+
3372
+ return clone;
3373
+ }
3374
+ } );
3375
+
3376
+ },{}],21:[function(require,module,exports){
3377
+ /**
3378
+ * Model for an instance of a widget
3379
+ */
3380
+ module.exports = Backbone.Model.extend( {
3381
+
3382
+ cell: null,
3383
+
3384
+ defaults: {
3385
+ // The PHP Class of the widget
3386
+ class: null,
3387
+
3388
+ // Is this class missing? Missing widgets are a special case.
3389
+ missing: false,
3390
+
3391
+ // The values of the widget
3392
+ values: {},
3393
+
3394
+ // Have the current values been passed through the widgets update function
3395
+ raw: false,
3396
+
3397
+ // Visual style fields
3398
+ style: {},
3399
+
3400
+ read_only: false,
3401
+ widget_id: '',
3402
+ },
3403
+
3404
+ indexes: null,
3405
+
3406
+ initialize: function () {
3407
+ var widgetClass = this.get( 'class' );
3408
+ if ( _.isUndefined( panelsOptions.widgets[widgetClass] ) || ! panelsOptions.widgets[widgetClass].installed ) {
3409
+ this.set( 'missing', true );
3410
+ }
3411
+ },
3412
+
3413
+ /**
3414
+ * @param field
3415
+ * @returns {*}
3416
+ */
3417
+ getWidgetField: function ( field ) {
3418
+ if ( _.isUndefined( panelsOptions.widgets[this.get( 'class' )] ) ) {
3419
+ if ( field === 'title' || field === 'description' ) {
3420
+ return panelsOptions.loc.missing_widget[field];
3421
+ } else {
3422
+ return '';
3423
+ }
3424
+ } else if ( this.has( 'label' ) && ! _.isEmpty( this.get( 'label' ) ) ) {
3425
+ // Use the label instead of the actual widget title
3426
+ return this.get( 'label' );
3427
+ } else {
3428
+ return panelsOptions.widgets[ this.get( 'class' ) ][ field ];
3429
+ }
3430
+ },
3431
+
3432
+ /**
3433
+ * Move this widget model to a new cell. Called by the views.
3434
+ *
3435
+ * @param panels.model.cell newCell
3436
+ * @param object options The options passed to the
3437
+ *
3438
+ * @return boolean Indicating if the widget was moved into a different cell
3439
+ */
3440
+ moveToCell: function ( newCell, options, at ) {
3441
+ options = _.extend( {
3442
+ silent: true,
3443
+ }, options );
3444
+
3445
+ this.cell = newCell;
3446
+ this.collection.remove( this, options );
3447
+ newCell.get('widgets').add( this, _.extend( {
3448
+ at: at
3449
+ }, options ) );
3450
+
3451
+ // This should be used by views to reposition everything.
3452
+ this.trigger( 'move_to_cell', newCell, at );
3453
+
3454
+ return this;
3455
+ },
3456
+
3457
+ /**
3458
+ * This is basically a wrapper for set that checks if we need to trigger a change
3459
+ */
3460
+ setValues: function ( values ) {
3461
+ var hasChanged = false;
3462
+ if ( JSON.stringify( values ) !== JSON.stringify( this.get( 'values' ) ) ) {
3463
+ hasChanged = true;
3464
+ }
3465
+
3466
+ this.set( 'values', values, {silent: true} );
3467
+
3468
+ if ( hasChanged ) {
3469
+ // We'll trigger our own change events.
3470
+ // NB: Must include the model being changed (i.e. `this`) as a workaround for a bug in Backbone 1.2.3
3471
+ this.trigger( 'change', this );
3472
+ this.trigger( 'change:values' );
3473
+ }
3474
+ },
3475
+
3476
+ /**
3477
+ * Create a clone of this widget attached to the given cell.
3478
+ *
3479
+ * @param {panels.model.cell} cell The cell model we're attaching this widget clone to.
3480
+ * @returns {panels.model.widget}
3481
+ */
3482
+ clone: function ( cell, options ) {
3483
+ if ( _.isUndefined( cell ) ) {
3484
+ cell = this.cell;
3485
+ }
3486
+
3487
+ var clone = new this.constructor( this.attributes );
3488
+
3489
+ // Create a deep clone of the original values
3490
+ var cloneValues = JSON.parse( JSON.stringify( this.get( 'values' ) ) );
3491
+
3492
+ // We want to exclude any fields that start with _ from the clone. Assuming these are internal.
3493
+ var cleanClone = function ( vals ) {
3494
+ _.each( vals, function ( el, i ) {
3495
+ if ( _.isString( i ) && i[0] === '_' ) {
3496
+ delete vals[i];
3497
+ }
3498
+ else if ( _.isObject( vals[i] ) ) {
3499
+ cleanClone( vals[i] );
3500
+ }
3501
+ } );
3502
+
3503
+ return vals;
3504
+ };
3505
+ cloneValues = cleanClone( cloneValues );
3506
+
3507
+ if ( this.get( 'class' ) === "SiteOrigin_Panels_Widgets_Layout" ) {
3508
+ // Special case of this being a layout widget, it needs a new ID
3509
+ cloneValues.builder_id = Math.random().toString( 36 ).substr( 2 );
3510
+ }
3511
+
3512
+ clone.set( 'widget_id', '' );
3513
+ clone.set( 'values', cloneValues, {silent: true} );
3514
+ clone.set( 'collection', cell.get('widgets'), {silent: true} );
3515
+ clone.cell = cell;
3516
+
3517
+ // This is used to force a form reload later on
3518
+ clone.isDuplicate = true;
3519
+
3520
+ return clone;
3521
+ },
3522
+
3523
+ /**
3524
+ * Gets the value that makes most sense as the title.
3525
+ */
3526
+ getTitle: function () {
3527
+ var widgetData = panelsOptions.widgets[this.get( 'class' )];
3528
+
3529
+ if ( _.isUndefined( widgetData ) ) {
3530
+ return this.get( 'class' ).replace( /_/g, ' ' );
3531
+ }
3532
+ else if ( ! _.isUndefined( widgetData.panels_title ) ) {
3533
+ // This means that the widget has told us which field it wants us to use as a title
3534
+ if ( widgetData.panels_title === false ) {
3535
+ return panelsOptions.widgets[this.get( 'class' )].description;
3536
+ }
3537
+ }
3538
+
3539
+ var values = this.get( 'values' );
3540
+
3541
+ // Create a list of fields to check for a title
3542
+ var titleFields = ['title', 'text'];
3543
+
3544
+ for ( var k in values ) {
3545
+ if(k.charAt(0) === '_' || k === 'so_sidebar_emulator_id' || k === 'option_name'){
3546
+ // Skip Widgets Bundle supporting fields
3547
+ continue;
3548
+ }
3549
+ if ( values.hasOwnProperty( k ) ) {
3550
+ titleFields.push( k );
3551
+ }
3552
+ }
3553
+
3554
+ titleFields = _.uniq( titleFields );
3555
+
3556
+ for ( var i in titleFields ) {
3557
+ if (
3558
+ ! _.isUndefined( values[titleFields[i]] ) &&
3559
+ _.isString( values[titleFields[i]] ) &&
3560
+ values[titleFields[i]] !== '' &&
3561
+ values[titleFields[i]] !== 'on' &&
3562
+ titleFields[i][0] !== '_' && ! jQuery.isNumeric( values[titleFields[i]] )
3563
+ ) {
3564
+ var title = values[titleFields[i]];
3565
+ title = title.replace( /<\/?[^>]+(>|$)/g, "" );
3566
+ var parts = title.split( " " );
3567
+ parts = parts.slice( 0, 20 );
3568
+ return parts.join( ' ' );
3569
+ }
3570
+ }
3571
+
3572
+ // If we still have nothing, then just return the widget description
3573
+ return this.getWidgetField( 'description' );
3574
+ }
3575
+
3576
+ } );
3577
+
3578
+ },{}],22:[function(require,module,exports){
3579
+ var panels = window.panels, $ = jQuery;
3580
+
3581
+ module.exports = Backbone.View.extend( {
3582
+ wrapperTemplate: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-context-menu' ).html() ) ),
3583
+ sectionTemplate: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-context-menu-section' ).html() ) ),
3584
+
3585
+ contexts: [],
3586
+ active: false,
3587
+
3588
+ events: {
3589
+ 'keyup .so-search-wrapper input': 'searchKeyUp'
3590
+ },
3591
+
3592
+ /**
3593
+ * Intialize the context menu
3594
+ */
3595
+ initialize: function () {
3596
+ this.listenContextMenu();
3597
+ this.render();
3598
+ this.attach();
3599
+ },
3600
+
3601
+ /**
3602
+ * Listen for the right click context menu
3603
+ */
3604
+ listenContextMenu: function () {
3605
+ var thisView = this;
3606
+
3607
+ $( window ).on( 'contextmenu', function ( e ) {
3608
+ if ( thisView.active && ! thisView.isOverEl( thisView.$el, e ) ) {
3609
+ thisView.closeMenu();
3610
+ thisView.active = false;
3611
+ e.preventDefault();
3612
+ return false;
3613
+ }
3614
+
3615
+ if ( thisView.active ) {
3616
+ // Lets not double up on the context menu
3617
+ return true;
3618
+ }
3619
+
3620
+ // Other components should listen to activate_context
3621
+ thisView.active = false;
3622
+ thisView.trigger( 'activate_context', e, thisView );
3623
+
3624
+ if ( thisView.active ) {
3625
+ // We don't want the default event to happen.
3626
+ e.preventDefault();
3627
+
3628
+ thisView.openMenu( {
3629
+ left: e.pageX,
3630
+ top: e.pageY
3631
+ } );
3632
+ }
3633
+ } );
3634
+ },
3635
+
3636
+ render: function () {
3637
+ this.setElement( this.wrapperTemplate() );
3638
+ },
3639
+
3640
+ attach: function () {
3641
+ this.$el.appendTo( 'body' );
3642
+ },
3643
+
3644
+ /**
3645
+ * Display the actual context menu.
3646
+ *
3647
+ * @param position
3648
+ */
3649
+ openMenu: function ( position ) {
3650
+ this.trigger( 'open_menu' );
3651
+
3652
+ // Start listening for situations when we should close the menu
3653
+ $( window ).on( 'keyup', {menu: this}, this.keyboardListen );
3654
+ $( window ).on( 'click', {menu: this}, this.clickOutsideListen );
3655
+
3656
+ // Set the maximum height of the menu
3657
+ this.$el.css( 'max-height', $( window ).height() - 20 );
3658
+
3659
+ // Correct the left position
3660
+ if ( position.left + this.$el.outerWidth() + 10 >= $( window ).width() ) {
3661
+ position.left = $( window ).width() - this.$el.outerWidth() - 10;
3662
+ }
3663
+ if ( position.left <= 0 ) {
3664
+ position.left = 10;
3665
+ }
3666
+
3667
+ // Check top position
3668
+ if ( position.top + this.$el.outerHeight() - $( window ).scrollTop() + 10 >= $( window ).height() ) {
3669
+ position.top = $( window ).height() + $( window ).scrollTop() - this.$el.outerHeight() - 10;
3670
+ }
3671
+ if ( position.left <= 0 ) {
3672
+ position.left = 10;
3673
+ }
3674
+
3675
+ // position the contextual menu
3676
+ this.$el.css( {
3677
+ left: position.left + 1,
3678
+ top: position.top + 1
3679
+ } ).show();
3680
+ this.$( '.so-search-wrapper input' ).focus();
3681
+ },
3682
+
3683
+ closeMenu: function () {
3684
+ this.trigger( 'close_menu' );
3685
+
3686
+ // Stop listening for situations when we should close the menu
3687
+ $( window ).off( 'keyup', this.keyboardListen );
3688
+ $( window ).off( 'click', this.clickOutsideListen );
3689
+
3690
+ this.active = false;
3691
+ this.$el.empty().hide();
3692
+ },
3693
+
3694
+ /**
3695
+ * Keyboard events handler
3696
+ */
3697
+ keyboardListen: function ( e ) {
3698
+ var menu = e.data.menu;
3699
+
3700
+ switch ( e.which ) {
3701
+ case 27:
3702
+ menu.closeMenu();
3703
+ break;
3704
+ }
3705
+ },
3706
+
3707
+ /**
3708
+ * Listen for a click outside the menu to close it.
3709
+ * @param e
3710
+ */
3711
+ clickOutsideListen: function ( e ) {
3712
+ var menu = e.data.menu;
3713
+ if ( e.which !== 3 && menu.$el.is( ':visible' ) && ! menu.isOverEl( menu.$el, e ) ) {
3714
+ menu.closeMenu();
3715
+ }
3716
+ },
3717
+
3718
+ /**
3719
+ * Add a new section to the contextual menu.
3720
+ *
3721
+ * @param settings
3722
+ * @param items
3723
+ * @param callback
3724
+ */
3725
+ addSection: function ( id, settings, items, callback ) {
3726
+ var thisView = this;
3727
+ settings = _.extend( {
3728
+ display: 5,
3729
+ defaultDisplay: false,
3730
+ search: true,
3731
+
3732
+ // All the labels
3733
+ sectionTitle: '',
3734
+ searchPlaceholder: '',
3735
+
3736
+ // This is the key to be used in items for the title. Makes it easier to list objects
3737
+ titleKey: 'title'
3738
+ }, settings );
3739
+
3740
+ // Create the new section
3741
+ var section = $( this.sectionTemplate( {
3742
+ settings: settings,
3743
+ items: items
3744
+ } ) ).attr( 'id', 'panels-menu-section-' + id );
3745
+ this.$el.append( section );
3746
+
3747
+ section.find( '.so-item:not(.so-confirm)' ).click( function () {
3748
+ var $$ = $( this );
3749
+ callback( $$.data( 'key' ) );
3750
+ thisView.closeMenu();
3751
+ } );
3752
+
3753
+ section.find( '.so-item.so-confirm' ).click( function () {
3754
+ var $$ = $( this );
3755
+
3756
+ if ( $$.hasClass( 'so-confirming' ) ) {
3757
+ callback( $$.data( 'key' ) );
3758
+ thisView.closeMenu();
3759
+ return;
3760
+ }
3761
+
3762
+ $$
3763
+ .data( 'original-text', $$.html() )
3764
+ .addClass( 'so-confirming' )
3765
+ .html( '<span class="dashicons dashicons-yes"></span> ' + panelsOptions.loc.dropdown_confirm );
3766
+
3767
+ setTimeout( function () {
3768
+ $$.removeClass( 'so-confirming' );
3769
+ $$.html( $$.data( 'original-text' ) );
3770
+ }, 2500 );
3771
+ } );
3772
+
3773
+ section.data( 'settings', settings ).find( '.so-search-wrapper input' ).trigger( 'keyup' );
3774
+
3775
+ this.active = true;
3776
+ },
3777
+
3778
+ /**
3779
+ * Check if a section exists in the current menu.
3780
+ *
3781
+ * @param id
3782
+ * @returns {boolean}
3783
+ */
3784
+ hasSection: function( id ){
3785
+ return this.$el.find( '#panels-menu-section-' + id ).length > 0;
3786
+ },
3787
+
3788
+ /**
3789
+ * Handle searching inside a section.
3790
+ *
3791
+ * @param e
3792
+ * @returns {boolean}
3793
+ */
3794
+ searchKeyUp: function ( e ) {
3795
+ var
3796
+ $$ = $( e.currentTarget ),
3797
+ section = $$.closest( '.so-section' ),
3798
+ settings = section.data( 'settings' );
3799
+
3800
+ if ( e.which === 38 || e.which === 40 ) {
3801
+ // First, lets check if this is an up, down or enter press
3802
+ var
3803
+ items = section.find( 'ul li:visible' ),
3804
+ activeItem = items.filter( '.so-active' ).eq( 0 );
3805
+
3806
+ if ( activeItem.length ) {
3807
+ items.removeClass( 'so-active' );
3808
+
3809
+ var activeIndex = items.index( activeItem );
3810
+
3811
+ if ( e.which === 38 ) {
3812
+ if ( activeIndex - 1 < 0 ) {
3813
+ activeItem = items.last();
3814
+ } else {
3815
+ activeItem = items.eq( activeIndex - 1 );
3816
+ }
3817
+ }
3818
+ else if ( e.which === 40 ) {
3819
+ if ( activeIndex + 1 >= items.length ) {
3820
+ activeItem = items.first();
3821
+ } else {
3822
+ activeItem = items.eq( activeIndex + 1 );
3823
+ }
3824
+ }
3825
+ }
3826
+ else if ( e.which === 38 ) {
3827
+ activeItem = items.last();
3828
+ }
3829
+ else if ( e.which === 40 ) {
3830
+ activeItem = items.first();
3831
+ }
3832
+
3833
+ activeItem.addClass( 'so-active' );
3834
+ return false;
3835
+ }
3836
+ if ( e.which === 13 ) {
3837
+ if ( section.find( 'ul li:visible' ).length === 1 ) {
3838
+ // We'll treat a single visible item as active when enter is clicked
3839
+ section.find( 'ul li:visible' ).trigger( 'click' );
3840
+ return false;
3841
+ }
3842
+ section.find( 'ul li.so-active:visible' ).trigger( 'click' );
3843
+ return false;
3844
+ }
3845
+
3846
+ if ( $$.val() === '' ) {
3847
+ // We'll display the defaultDisplay items
3848
+ if ( settings.defaultDisplay ) {
3849
+ section.find( '.so-item' ).hide();
3850
+ for ( var i = 0; i < settings.defaultDisplay.length; i ++ ) {
3851
+ section.find( '.so-item[data-key="' + settings.defaultDisplay[i] + '"]' ).show();
3852
+ }
3853
+ } else {
3854
+ // We'll just display all the items
3855
+ section.find( '.so-item' ).show();
3856
+ }
3857
+ } else {
3858
+ section.find( '.so-item' ).hide().each( function () {
3859
+ var item = $( this );
3860
+ if ( item.html().toLowerCase().indexOf( $$.val().toLowerCase() ) !== - 1 ) {
3861
+ item.show();
3862
+ }
3863
+ } );
3864
+ }
3865
+
3866
+ // Now, we'll only show the first settings.display visible items
3867
+ section.find( '.so-item:visible:gt(' + (
3868
+ settings.display - 1
3869
+ ) + ')' ).hide();
3870
+
3871
+
3872
+ if ( section.find( '.so-item:visible' ).length === 0 && $$.val() !== '' ) {
3873
+ section.find( '.so-no-results' ).show();
3874
+ } else {
3875
+ section.find( '.so-no-results' ).hide();
3876
+ }
3877
+ },
3878
+
3879
+ /**
3880
+ * Check if the given mouse event is over the element
3881
+ * @param el
3882
+ * @param event
3883
+ */
3884
+ isOverEl: function ( el, event ) {
3885
+ var elPos = [
3886
+ [el.offset().left, el.offset().top],
3887
+ [el.offset().left + el.outerWidth(), el.offset().top + el.outerHeight()]
3888
+ ];
3889
+
3890
+ // Return if this event is over the given element
3891
+ return (
3892
+ event.pageX >= elPos[0][0] && event.pageX <= elPos[1][0] &&
3893
+ event.pageY >= elPos[0][1] && event.pageY <= elPos[1][1]
3894
+ );
3895
+ }
3896
+
3897
+ } );
3898
+
3899
+ },{}],23:[function(require,module,exports){
3900
+ var panels = window.panels, $ = jQuery;
3901
+
3902
+ module.exports = Backbone.View.extend( {
3903
+
3904
+ // Config options
3905
+ config: {},
3906
+
3907
+ template: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-builder' ).html() ) ),
3908
+ dialogs: {},
3909
+ rowsSortable: null,
3910
+ dataField: false,
3911
+ currentData: '',
3912
+
3913
+ attachedToEditor: false,
3914
+ attachedVisible: false,
3915
+ liveEditor: undefined,
3916
+ menu: false,
3917
+
3918
+ activeCell: null,
3919
+
3920
+ events: {
3921
+ 'click .so-tool-button.so-widget-add': 'displayAddWidgetDialog',
3922
+ 'click .so-tool-button.so-row-add': 'displayAddRowDialog',
3923
+ 'click .so-tool-button.so-prebuilt-add': 'displayAddPrebuiltDialog',
3924
+ 'click .so-tool-button.so-history': 'displayHistoryDialog',
3925
+ 'click .so-tool-button.so-live-editor': 'displayLiveEditor'
3926
+ },
3927
+
3928
+ /* A row collection */
3929
+ rows: null,
3930
+
3931
+ /**
3932
+ * Initialize the builder
3933
+ */
3934
+ initialize: function ( options ) {
3935
+ var builder = this;
3936
+
3937
+ this.config = _.extend( {
3938
+ loadLiveEditor: false,
3939
+ builderSupports: {}
3940
+ }, options.config );
3941
+
3942
+ // These are the actions that a user can perform in the builder
3943
+ this.config.builderSupports = _.extend( {
3944
+ addRow: true,
3945
+ editRow: true,
3946
+ deleteRow: true,
3947
+ moveRow: true,
3948
+ addWidget: true,
3949
+ editWidget: true,
3950
+ deleteWidget: true,
3951
+ moveWidget: true,
3952
+ prebuilt: true,
3953
+ history: true,
3954
+ liveEditor: true,
3955
+ revertToEditor: true
3956
+ }, this.config.builderSupports );
3957
+
3958
+ // Automatically load the live editor as soon as it's ready
3959
+ if ( options.config.loadLiveEditor ) {
3960
+ this.on( 'builder_live_editor_added', function () {
3961
+ this.displayLiveEditor();
3962
+ } );
3963
+ }
3964
+
3965
+ // Now lets create all the dialog boxes that the main builder interface uses
3966
+ this.dialogs = {
3967
+ widgets: new panels.dialog.widgets(),
3968
+ row: new panels.dialog.row(),
3969
+ prebuilt: new panels.dialog.prebuilt()
3970
+ };
3971
+
3972
+ // Set the builder for each dialog and render it.
3973
+ _.each( this.dialogs, function ( p, i, d ) {
3974
+ d[ i ].setBuilder( builder );
3975
+ } );
3976
+
3977
+ this.dialogs.row.setRowDialogType( 'create' );
3978
+
3979
+ // This handles a new row being added to the collection - we'll display it in the interface
3980
+ this.listenTo( this.model.get( 'rows' ), 'add', this.onAddRow );
3981
+
3982
+ // Reflow the entire builder when ever the
3983
+ $( window ).resize( function ( e ) {
3984
+ if ( e.target === window ) {
3985
+ builder.trigger( 'builder_resize' );
3986
+ }
3987
+ } );
3988
+
3989
+ // When the data changes in the model, store it in the field
3990
+ this.listenTo( this.model, 'change:data load_panels_data', this.storeModelData );
3991
+ this.listenTo( this.model, 'change:data load_panels_data', this.toggleWelcomeDisplay );
3992
+
3993
+ // Handle a content change
3994
+ this.on( 'content_change', this.handleContentChange, this );
3995
+ this.on( 'display_builder', this.handleDisplayBuilder, this );
3996
+ this.on( 'hide_builder', this.handleHideBuilder, this );
3997
+ this.on( 'builder_rendered builder_resize', this.handleBuilderSizing, this );
3998
+
3999
+ this.on( 'display_builder', this.wrapEditorExpandAdjust, this );
4000
+
4001
+ // Create the context menu for this builder
4002
+ this.menu = new panels.utils.menu( {} );
4003
+ this.listenTo( this.menu, 'activate_context', this.activateContextMenu )
4004
+
4005
+ if ( this.config.loadOnAttach ) {
4006
+ this.on( 'builder_attached_to_editor', function () {
4007
+ this.displayAttachedBuilder( { confirm: false } );
4008
+ }, this );
4009
+ }
4010
+
4011
+ return this;
4012
+ },
4013
+
4014
+ /**
4015
+ * Render the builder interface.
4016
+ *
4017
+ * @return {panels.view.builder}
4018
+ */
4019
+ render: function () {
4020
+ // this.$el.html( this.template() );
4021
+ this.setElement( this.template() );
4022
+ this.$el
4023
+ .attr( 'id', 'siteorigin-panels-builder-' + this.cid )
4024
+ .addClass( 'so-builder-container' );
4025
+
4026
+ this.trigger( 'builder_rendered' );
4027
+
4028
+ return this;
4029
+ },
4030
+
4031
+ /**
4032
+ * Attach the builder to the given container
4033
+ *
4034
+ * @param container
4035
+ * @returns {panels.view.builder}
4036
+ */
4037
+ attach: function ( options ) {
4038
+
4039
+ options = _.extend( {
4040
+ container: false,
4041
+ dialog: false
4042
+ }, options );
4043
+
4044
+ if ( options.dialog ) {
4045
+ // We're going to add this to a dialog
4046
+ this.dialog = new panels.dialog.builder();
4047
+ this.dialog.builder = this;
4048
+ } else {
4049
+ // Attach this in the standard way
4050
+ this.$el.appendTo( options.container );
4051
+ this.metabox = options.container.closest( '.postbox' );
4052
+ this.initSortable();
4053
+ this.trigger( 'attached_to_container', options.container );
4054
+ }
4055
+
4056
+ this.trigger( 'builder_attached' );
4057
+
4058
+ // Add support for components we have
4059
+
4060
+ if ( this.supports( 'liveEditor' ) ) {
4061
+ this.addLiveEditor();
4062
+ }
4063
+ if ( this.supports( 'history' ) ) {
4064
+ this.addHistoryBrowser();
4065
+ }
4066
+
4067
+ // Hide toolbar buttons we don't support
4068
+ var toolbar = this.$( '.so-builder-toolbar' );
4069
+ var welcomeMessageContainer = this.$( '.so-panels-welcome-message' );
4070
+ var welcomeMessage = panelsOptions.loc.welcomeMessage;
4071
+
4072
+ var supportedItems = [];
4073
+
4074
+ if ( !this.supports( 'addWidget' ) ) {
4075
+ toolbar.find( '.so-widget-add' ).hide();
4076
+ } else {
4077
+ supportedItems.push( welcomeMessage.addWidgetButton );
4078
+ }
4079
+ if ( !this.supports( 'addRow' ) ) {
4080
+ toolbar.find( '.so-row-add' ).hide();
4081
+ } else {
4082
+ supportedItems.push( welcomeMessage.addRowButton );
4083
+ }
4084
+ if ( !this.supports( 'prebuilt' ) ) {
4085
+ toolbar.find( '.so-prebuilt-add' ).hide();
4086
+ } else {
4087
+ supportedItems.push( welcomeMessage.addPrebuiltButton );
4088
+ }
4089
+
4090
+ var msg = '';
4091
+ if ( supportedItems.length === 3 ) {
4092
+ msg = welcomeMessage.threeEnabled;
4093
+ } else if ( supportedItems.length === 2 ) {
4094
+ msg = welcomeMessage.twoEnabled;
4095
+ } else if ( supportedItems.length === 1 ) {
4096
+ msg = welcomeMessage.oneEnabled;
4097
+ } else if ( supportedItems.length === 0 ) {
4098
+ msg = welcomeMessage.addingDisabled;
4099
+ }
4100
+
4101
+ var resTemplate = _.template( panels.helpers.utils.processTemplate( msg ) );
4102
+ var msgHTML = resTemplate( { items: supportedItems } ) + ' ' + welcomeMessage.docsMessage;
4103
+ welcomeMessageContainer.find( '.so-message-wrapper' ).html( msgHTML );
4104
+
4105
+ return this;
4106
+ },
4107
+
4108
+ /**
4109
+ * This will move the Page Builder meta box into the editor if we're in the post/page edit interface.
4110
+ *
4111
+ * @returns {panels.view.builder}
4112
+ */
4113
+ attachToEditor: function () {
4114
+ if ( this.config.editorType !== 'tinyMCE' ) {
4115
+ return this;
4116
+ }
4117
+
4118
+ this.attachedToEditor = true;
4119
+ var metabox = this.metabox;
4120
+ var thisView = this;
4121
+
4122
+ // Handle switching between the page builder and other tabs
4123
+ $( '#wp-content-wrap .wp-editor-tabs' )
4124
+ .find( '.wp-switch-editor' )
4125
+ .click( function ( e ) {
4126
+ e.preventDefault();
4127
+ $( '#wp-content-editor-container' ).show();
4128
+
4129
+ // metabox.hide();
4130
+ $( '#wp-content-wrap' ).removeClass( 'panels-active' );
4131
+ $( '#content-resize-handle' ).show();
4132
+
4133
+ // Make sure the word count is visible
4134
+ thisView.trigger( 'hide_builder' );
4135
+ } ).end()
4136
+ .append(
4137
+ $( '<button type="button" id="content-panels" class="hide-if-no-js wp-switch-editor switch-panels">' + metabox.find( '.hndle span' ).html() + '</button>' )
4138
+ .click( function ( e ) {
4139
+ if ( thisView.displayAttachedBuilder( { confirm: true } ) ) {
4140
+ e.preventDefault();
4141
+ }
4142
+ } )
4143
+ );
4144
+
4145
+ // Switch back to the standard editor
4146
+ if ( this.supports( 'revertToEditor' ) ) {
4147
+ metabox.find( '.so-switch-to-standard' ).click( function ( e ) {
4148
+ e.preventDefault();
4149
+
4150
+ if ( !confirm( panelsOptions.loc.confirm_stop_builder ) ) {
4151
+ return;
4152
+ }
4153
+
4154
+ // User is switching to the standard visual editor
4155
+ thisView.addHistoryEntry( 'back_to_editor' );
4156
+ thisView.model.loadPanelsData( false );
4157
+
4158
+ // Switch back to the standard editor
4159
+ $( '#wp-content-wrap' ).show();
4160
+ metabox.hide();
4161
+
4162
+ // Resize to trigger reflow of WordPress editor stuff
4163
+ $( window ).resize();
4164
+
4165
+ thisView.attachedVisible = false;
4166
+ thisView.trigger( 'hide_builder' );
4167
+ } ).show();
4168
+ }
4169
+
4170
+ // Move the panels box into a tab of the content editor
4171
+ metabox.insertAfter( '#wp-content-wrap' ).hide().addClass( 'attached-to-editor' );
4172
+
4173
+ // Switch to the Page Builder interface as soon as we load the page if there are widgets or the normal editor
4174
+ // isn't supported.
4175
+ var data = this.model.get( 'data' );
4176
+ if ( !_.isEmpty( data.widgets ) || !_.isEmpty( data.grids ) || !this.supports( 'revertToEditor' ) ) {
4177
+ this.displayAttachedBuilder( { confirm: false } );
4178
+ }
4179
+
4180
+ // We will also make this sticky if its attached to an editor.
4181
+ var stickToolbar = function () {
4182
+ var toolbar = thisView.$( '.so-builder-toolbar' );
4183
+
4184
+ if ( thisView.$el.hasClass( 'so-display-narrow' ) ) {
4185
+ // In this case, we don't want to stick the toolbar.
4186
+ toolbar.css( {
4187
+ top: 0,
4188
+ left: 0,
4189
+ width: '100%',
4190
+ position: 'absolute'
4191
+ } );
4192
+ thisView.$el.css( 'padding-top', toolbar.outerHeight() );
4193
+ return;
4194
+ }
4195
+
4196
+ var newTop = $( window ).scrollTop() - thisView.$el.offset().top;
4197
+
4198
+ if ( $( '#wpadminbar' ).css( 'position' ) === 'fixed' ) {
4199
+ newTop += $( '#wpadminbar' ).outerHeight();
4200
+ }
4201
+
4202
+ var limits = {
4203
+ top: 0,
4204
+ bottom: thisView.$el.outerHeight() - toolbar.outerHeight() + 20
4205
+ };
4206
+
4207
+ if ( newTop > limits.top && newTop < limits.bottom ) {
4208
+ if ( toolbar.css( 'position' ) !== 'fixed' ) {
4209
+ // The toolbar needs to stick to the top, over the interface
4210
+ toolbar.css( {
4211
+ top: $( '#wpadminbar' ).outerHeight(),
4212
+ left: thisView.$el.offset().left,
4213
+ width: thisView.$el.outerWidth(),
4214
+ position: 'fixed'
4215
+ } );
4216
+ }
4217
+ } else {
4218
+ // The toolbar needs to be at the top or bottom of the interface
4219
+ toolbar.css( {
4220
+ top: Math.min( Math.max( newTop, 0 ), thisView.$el.outerHeight() - toolbar.outerHeight() + 20 ),
4221
+ left: 0,
4222
+ width: '100%',
4223
+ position: 'absolute'
4224
+ } );
4225
+ }
4226
+
4227
+ thisView.$el.css( 'padding-top', toolbar.outerHeight() );
4228
+ };
4229
+
4230
+ this.on( 'builder_resize', stickToolbar, this );
4231
+ $( document ).scroll( stickToolbar );
4232
+ stickToolbar();
4233
+
4234
+ this.trigger( 'builder_attached_to_editor' );
4235
+
4236
+ return this;
4237
+ },
4238
+
4239
+ /**
4240
+ * Display the builder interface when attached to a WordPress editor
4241
+ */
4242
+ displayAttachedBuilder: function ( options ) {
4243
+ options = _.extend( {
4244
+ confirm: true
4245
+ }, options );
4246
+
4247
+ // Switch to the Page Builder interface
4248
+
4249
+ if ( options.confirm ) {
4250
+ var editor = typeof tinyMCE !== 'undefined' ? tinyMCE.get( 'content' ) : false;
4251
+ var editorContent = ( editor && _.isFunction( editor.getContent ) ) ? editor.getContent() : $( 'textarea#content' ).val();
4252
+
4253
+ if ( editorContent !== '' && !confirm( panelsOptions.loc.confirm_use_builder ) ) {
4254
+ return false;
4255
+ }
4256
+ }
4257
+
4258
+ // Hide the standard content editor
4259
+ $( '#wp-content-wrap' ).hide();
4260
+
4261
+
4262
+ $( '#editor-expand-toggle' ).on( 'change.editor-expand', function () {
4263
+ if ( !$( this ).prop( 'checked' ) ) {
4264
+ $( '#wp-content-wrap' ).hide();
4265
+ }
4266
+ } );
4267
+
4268
+ // Show page builder and the inside div
4269
+ this.metabox.show().find( '> .inside' ).show();
4270
+
4271
+ // Triggers full refresh
4272
+ $( window ).resize();
4273
+ $( document ).scroll();
4274
+
4275
+ // Make sure the word count is visible
4276
+ this.attachedVisible = true;
4277
+ this.trigger( 'display_builder' );
4278
+
4279
+ return true;
4280
+ },
4281
+
4282
+ /**
4283
+ * Initialize the row sortables
4284
+ */
4285
+ initSortable: function () {
4286
+ if ( !this.supports( 'moveRow' ) ) {
4287
+ return this;
4288
+ }
4289
+
4290
+ var builderView = this;
4291
+ var builderID = builderView.$el.attr( 'id' );
4292
+
4293
+ // Create the sortable for the rows
4294
+ this.rowsSortable = this.$( '.so-rows-container' ).sortable( {
4295
+ appendTo: '#wpwrap',
4296
+ items: '.so-row-container',
4297
+ handle: '.so-row-move',
4298
+ // For the block editor, where it's possible to have multiple Page Builder blocks on a page.
4299
+ // Also specify builderID when not in the block editor to prevent being able to drop rows from builder in a dialog
4300
+ // into builder on the page under the dialog.
4301
+ connectWith: '#' + builderID + '.so-rows-container,.block-editor .so-rows-container',
4302
+ axis: 'y',
4303
+ tolerance: 'pointer',
4304
+ scroll: false,
4305
+ remove: function ( e, ui ) {
4306
+ builderView.model.get( 'rows' ).remove(
4307
+ $( ui.item ).data( 'view' ).model,
4308
+ { silent: true }
4309
+ );
4310
+ builderView.model.refreshPanelsData();
4311
+ },
4312
+ receive: function ( e, ui ) {
4313
+ builderView.model.get( 'rows' ).add(
4314
+ $( ui.item ).data( 'view' ).model,
4315
+ { silent: true, at: $( ui.item ).index() }
4316
+ );
4317
+ builderView.model.refreshPanelsData();
4318
+ },
4319
+ stop: function ( e, ui ) {
4320
+ var $$ = $( ui.item ),
4321
+ row = $$.data( 'view' ),
4322
+ rows = builderView.model.get( 'rows' );
4323
+
4324
+ // If this hasn't already been removed and added to a different builder.
4325
+ if ( rows.get( row.model ) ) {
4326
+ builderView.addHistoryEntry( 'row_moved' );
4327
+
4328
+ rows.remove( row.model, {
4329
+ 'silent': true
4330
+ } );
4331
+ rows.add( row.model, {
4332
+ 'silent': true,
4333
+ 'at': $$.index()
4334
+ } );
4335
+
4336
+ row.trigger( 'move', $$.index() );
4337
+
4338
+ builderView.model.refreshPanelsData();
4339
+ }
4340
+ }
4341
+ } );
4342
+
4343
+ return this;
4344
+ },
4345
+
4346
+ /**
4347
+ * Refresh the row sortable
4348
+ */
4349
+ refreshSortable: function () {
4350
+ // Refresh the sortable to account for the new row
4351
+ if ( !_.isNull( this.rowsSortable ) ) {
4352
+ this.rowsSortable.sortable( 'refresh' );
4353
+ }
4354
+ },
4355
+
4356
+ /**
4357
+ * Set the field that's used to store the data
4358
+ * @param field
4359
+ * @param options
4360
+ */
4361
+ setDataField: function ( field, options ) {
4362
+ options = _.extend( {
4363
+ load: true
4364
+ }, options );
4365
+
4366
+ this.dataField = field;
4367
+ this.dataField.data( 'builder', this );
4368
+
4369
+ if ( options.load && field.val() !== '' ) {
4370
+ var data = this.dataField.val();
4371
+ try {
4372
+ data = JSON.parse( data );
4373
+ }
4374
+ catch ( err ) {
4375
+ console.log( "Failed to parse Page Builder layout data from supplied data field." );
4376
+ data = {};
4377
+ }
4378
+
4379
+ this.setData( data );
4380
+ }
4381
+
4382
+ return this;
4383
+ },
4384
+
4385
+ /**
4386
+ * Set the current panels data to be used.
4387
+ *
4388
+ * @param data
4389
+ */
4390
+ setData: function( data ) {
4391
+ this.model.loadPanelsData( data );
4392
+ this.currentData = data;
4393
+ this.toggleWelcomeDisplay();
4394
+ },
4395
+
4396
+ /**
4397
+ * Get the current panels data.
4398
+ *
4399
+ */
4400
+ getData: function() {
4401
+ return this.model.get( 'data' );
4402
+ },
4403
+
4404
+ /**
4405
+ * Store the model data in the data html field set in this.setDataField.
4406
+ */
4407
+ storeModelData: function () {
4408
+ var data = JSON.stringify( this.model.get( 'data' ) );
4409
+
4410
+ if ( $( this.dataField ).val() !== data ) {
4411
+ // If the data is different, set it and trigger a content_change event
4412
+ $( this.dataField ).val( data );
4413
+ $( this.dataField ).trigger( 'change' );
4414
+ this.trigger( 'content_change' );
4415
+ }
4416
+ },
4417
+
4418
+ /**
4419
+ * HAndle the visual side of adding a new row to the builder.
4420
+ *
4421
+ * @param row
4422
+ * @param collection
4423
+ * @param options
4424
+ */
4425
+ onAddRow: function ( row, collection, options ) {
4426
+ options = _.extend( { noAnimate: false }, options );
4427
+ // Create a view for the row
4428
+ var rowView = new panels.view.row( { model: row } );
4429
+ rowView.builder = this;
4430
+ rowView.render();
4431
+
4432
+ // Attach the row elements to this builder
4433
+ if ( _.isUndefined( options.at ) || collection.length <= 1 ) {
4434
+ // Insert this at the end of the widgets container
4435
+ rowView.$el.appendTo( this.$( '.so-rows-container' ) );
4436
+ } else {
4437
+ // We need to insert this at a specific position
4438
+ rowView.$el.insertAfter(
4439
+ this.$( '.so-rows-container .so-row-container' ).eq( options.at - 1 )
4440
+ );
4441
+ }
4442
+
4443
+ if ( options.noAnimate === false ) {
4444
+ rowView.visualCreate();
4445
+ }
4446
+
4447
+ this.refreshSortable();
4448
+ rowView.resize();
4449
+ this.trigger( 'row_added' );
4450
+ },
4451
+
4452
+ /**
4453
+ * Display the dialog to add a new widget.
4454
+ *
4455
+ * @returns {boolean}
4456
+ */
4457
+ displayAddWidgetDialog: function () {
4458
+ this.dialogs.widgets.openDialog();
4459
+ },
4460
+
4461
+ /**
4462
+ * Display the dialog to add a new row.
4463
+ */
4464
+ displayAddRowDialog: function () {
4465
+ var row = new panels.model.row();
4466
+ var cells = new panels.collection.cells( [ { weight: 0.5 }, { weight: 0.5 } ] );
4467
+ cells.each( function ( cell ) {
4468
+ cell.row = row;
4469
+ } );
4470
+ row.set( 'cells', cells );
4471
+ row.builder = this.model;
4472
+
4473
+ this.dialogs.row.setRowModel( row );
4474
+ this.dialogs.row.openDialog();
4475
+ },
4476
+
4477
+ /**
4478
+ * Display the dialog to add prebuilt layouts.
4479
+ *
4480
+ * @returns {boolean}
4481
+ */
4482
+ displayAddPrebuiltDialog: function () {
4483
+ this.dialogs.prebuilt.openDialog();
4484
+ },
4485
+
4486
+ /**
4487
+ * Display the history dialog.
4488
+ *
4489
+ * @returns {boolean}
4490
+ */
4491
+ displayHistoryDialog: function () {
4492
+ this.dialogs.history.openDialog();
4493
+ },
4494
+
4495
+ /**
4496
+ * Handle pasting a row into the builder.
4497
+ */
4498
+ pasteRowHandler: function () {
4499
+ var pastedModel = panels.helpers.clipboard.getModel( 'row-model' );
4500
+
4501
+ if ( !_.isEmpty( pastedModel ) && pastedModel instanceof panels.model.row ) {
4502
+ this.addHistoryEntry( 'row_pasted' );
4503
+ pastedModel.builder = this.model;
4504
+ this.model.get( 'rows' ).add( pastedModel, {
4505
+ at: this.model.get( 'rows' ).indexOf( this.model ) + 1
4506
+ } );
4507
+ this.model.refreshPanelsData();
4508
+ }
4509
+ },
4510
+
4511
+ /**
4512
+ * Get the model for the currently selected cell
4513
+ */
4514
+ getActiveCell: function ( options ) {
4515
+ options = _.extend( {
4516
+ createCell: true,
4517
+ }, options );
4518
+
4519
+ if ( !this.model.get( 'rows' ).length ) {
4520
+ // There aren't any rows yet
4521
+ if ( options.createCell ) {
4522
+ // Create a row with a single cell
4523
+ this.model.addRow( {}, [ { weight: 1 } ], { noAnimate: true } );
4524
+ } else {
4525
+ return null;
4526
+ }
4527
+ }
4528
+
4529
+ // Make sure the active cell isn't empty, and it's in a row that exists
4530
+ var activeCell = this.activeCell;
4531
+ if ( _.isEmpty( activeCell ) || this.model.get( 'rows' ).indexOf( activeCell.model.row ) === -1 ) {
4532
+ return this.model.get( 'rows' ).last().get( 'cells' ).first();
4533
+ } else {
4534
+ return activeCell.model;
4535
+ }
4536
+ },
4537
+
4538
+ /**
4539
+ * Add a live editor to the builder
4540
+ *
4541
+ * @returns {panels.view.builder}
4542
+ */
4543
+ addLiveEditor: function () {
4544
+ if ( _.isEmpty( this.config.liveEditorPreview ) ) {
4545
+ return this;
4546
+ }
4547
+
4548
+ // Create the live editor and set the builder to this.
4549
+ this.liveEditor = new panels.view.liveEditor( {
4550
+ builder: this,
4551
+ previewUrl: this.config.liveEditorPreview
4552
+ } );
4553
+
4554
+ // Display the live editor button in the toolbar
4555
+ if ( this.liveEditor.hasPreviewUrl() ) {
4556
+ this.$( '.so-builder-toolbar .so-live-editor' ).show();
4557
+ }
4558
+
4559
+ this.trigger( 'builder_live_editor_added' );
4560
+
4561
+ return this;
4562
+ },
4563
+
4564
+ /**
4565
+ * Show the current live editor
4566
+ */
4567
+ displayLiveEditor: function () {
4568
+ if ( _.isUndefined( this.liveEditor ) ) {
4569
+ return;
4570
+ }
4571
+
4572
+ this.liveEditor.open();
4573
+ },
4574
+
4575
+ /**
4576
+ * Add the history browser.
4577
+ *
4578
+ * @return {panels.view.builder}
4579
+ */
4580
+ addHistoryBrowser: function () {
4581
+ if ( _.isEmpty( this.config.liveEditorPreview ) ) {
4582
+ return this;
4583
+ }
4584
+
4585
+ this.dialogs.history = new panels.dialog.history();
4586
+ this.dialogs.history.builder = this;
4587
+ this.dialogs.history.entries.builder = this.model;
4588
+
4589
+ // Set the revert entry
4590
+ this.dialogs.history.setRevertEntry( this.model );
4591
+
4592
+ // Display the live editor button in the toolbar
4593
+ this.$( '.so-builder-toolbar .so-history' ).show();
4594
+ },
4595
+
4596
+ /**
4597
+ * Add an entry.
4598
+ *
4599
+ * @param text
4600
+ * @param data
4601
+ */
4602
+ addHistoryEntry: function ( text, data ) {
4603
+ if ( _.isUndefined( data ) ) {
4604
+ data = null;
4605
+ }
4606
+
4607
+ if ( !_.isUndefined( this.dialogs.history ) ) {
4608
+ this.dialogs.history.entries.addEntry( text, data );
4609
+ }
4610
+ },
4611
+
4612
+ supports: function ( thing ) {
4613
+
4614
+ if ( thing === 'rowAction' ) {
4615
+ // Check if this supports any row action
4616
+ return this.supports( 'addRow' ) || this.supports( 'editRow' ) || this.supports( 'deleteRow' );
4617
+ } else if ( thing === 'widgetAction' ) {
4618
+ // Check if this supports any widget action
4619
+ return this.supports( 'addWidget' ) || this.supports( 'editWidget' ) || this.supports( 'deleteWidget' );
4620
+ }
4621
+
4622
+ return _.isUndefined( this.config.builderSupports[ thing ] ) ? false : this.config.builderSupports[ thing ];
4623
+ },
4624
+
4625
+ /**
4626
+ * Handle a change of the content
4627
+ */
4628
+ handleContentChange: function () {
4629
+
4630
+ // Make sure we actually need to copy content.
4631
+ if ( panelsOptions.copy_content && this.attachedToEditor && this.$el.is( ':visible' ) ) {
4632
+
4633
+ var panelsData = this.model.getPanelsData();
4634
+ if ( !_.isEmpty( panelsData.widgets ) ) {
4635
+ // We're going to create a copy of page builder content into the post content
4636
+ $.post(
4637
+ panelsOptions.ajaxurl,
4638
+ {
4639
+ action: 'so_panels_builder_content',
4640
+ panels_data: JSON.stringify( panelsData ),
4641
+ post_id: this.config.postId
4642
+ },
4643
+ function ( content ) {
4644
+ if ( content !== '' ) {
4645
+ this.updateEditorContent( content );
4646
+ }
4647
+ }.bind( this )
4648
+ );
4649
+ }
4650
+ }
4651
+ },
4652
+
4653
+ /**
4654
+ * Update editor content with the given content.
4655
+ *
4656
+ * @param content
4657
+ */
4658
+ updateEditorContent: function ( content ) {
4659
+ // Switch back to the standard editor
4660
+ if ( this.config.editorType !== 'tinyMCE' || typeof tinyMCE === 'undefined' || _.isNull( tinyMCE.get( "content" ) ) ) {
4661
+ var $editor = $( this.config.editorId );
4662
+ $editor.val( content ).trigger( 'change' ).trigger( 'keyup' );
4663
+ } else {
4664
+ var contentEd = tinyMCE.get( "content" );
4665
+
4666
+ contentEd.setContent( content );
4667
+
4668
+ contentEd.fire( 'change' );
4669
+ contentEd.fire( 'keyup' );
4670
+ }
4671
+
4672
+ this.triggerYoastSeoChange();
4673
+ },
4674
+
4675
+ /**
4676
+ * Trigger a change on Yoast SEO
4677
+ */
4678
+ triggerYoastSeoChange: function () {
4679
+ if ( $( '#yoast_wpseo_focuskw_text_input' ).length ) {
4680
+ var element = document.getElementById( 'yoast_wpseo_focuskw_text_input' ), event;
4681
+
4682
+ if ( document.createEvent ) {
4683
+ event = document.createEvent( "HTMLEvents" );
4684
+ event.initEvent( "keyup", true, true );
4685
+ } else {
4686
+ event = document.createEventObject();
4687
+ event.eventType = "keyup";
4688
+ }
4689
+
4690
+ event.eventName = "keyup";
4691
+
4692
+ if ( document.createEvent ) {
4693
+ element.dispatchEvent( event );
4694
+ } else {
4695
+ element.fireEvent( "on" + event.eventType, event );
4696
+ }
4697
+ }
4698
+ },
4699
+
4700
+ /**
4701
+ * Handle displaying the builder
4702
+ */
4703
+ handleDisplayBuilder: function () {
4704
+ var editor = typeof tinyMCE !== 'undefined' ? tinyMCE.get( 'content' ) : false;
4705
+ var editorContent = ( editor && _.isFunction( editor.getContent ) ) ? editor.getContent() : $( 'textarea#content' ).val();
4706
+
4707
+ if (
4708
+ (
4709
+ _.isEmpty( this.model.get( 'data' ) ) ||
4710
+ ( _.isEmpty( this.model.get( 'data' ).widgets ) && _.isEmpty( this.model.get( 'data' ).grids ) )
4711
+ ) &&
4712
+ editorContent !== ''
4713
+ ) {
4714
+ var editorClass = panelsOptions.text_widget;
4715
+ // There is a small chance a theme will have removed this, so check
4716
+ if ( _.isEmpty( editorClass ) ) {
4717
+ return;
4718
+ }
4719
+
4720
+ // Create the existing page content in a single widget
4721
+ this.model.loadPanelsData( this.model.getPanelsDataFromHtml( editorContent, editorClass ) );
4722
+ this.model.trigger( 'change' );
4723
+ this.model.trigger( 'change:data' );
4724
+ }
4725
+
4726
+ $( '#post-status-info' ).addClass( 'for-siteorigin-panels' );
4727
+ },
4728
+
4729
+ handleHideBuilder: function () {
4730
+ $( '#post-status-info' ).show().removeClass( 'for-siteorigin-panels' );
4731
+ },
4732
+
4733
+ wrapEditorExpandAdjust: function () {
4734
+ try {
4735
+ var events = ( $.hasData( window ) && $._data( window ) ).events.scroll,
4736
+ event;
4737
+
4738
+ for ( var i = 0; i < events.length; i++ ) {
4739
+ if ( events[ i ].namespace === 'editor-expand' ) {
4740
+ event = events[ i ];
4741
+
4742
+ // Wrap the call
4743
+ $( window ).unbind( 'scroll', event.handler );
4744
+ $( window ).bind( 'scroll', function ( e ) {
4745
+ if ( !this.attachedVisible ) {
4746
+ event.handler( e );
4747
+ }
4748
+ }.bind( this ) );
4749
+
4750
+ break;
4751
+ }
4752
+ }
4753
+ }
4754
+ catch ( e ) {
4755
+ // We tried, we failed
4756
+ return;
4757
+ }
4758
+ },
4759
+
4760
+ /**
4761
+ * Either add or remove the narrow class
4762
+ * @returns {exports}
4763
+ */
4764
+ handleBuilderSizing: function () {
4765
+ var width = this.$el.width();
4766
+
4767
+ if ( !width ) {
4768
+ return this;
4769
+ }
4770
+
4771
+ if ( width < 575 ) {
4772
+ this.$el.addClass( 'so-display-narrow' );
4773
+ } else {
4774
+ this.$el.removeClass( 'so-display-narrow' );
4775
+ }
4776
+
4777
+ return this;
4778
+ },
4779
+
4780
+ /**
4781
+ * Set the parent dialog for all the dialogs in this builder.
4782
+ *
4783
+ * @param text
4784
+ * @param dialog
4785
+ */
4786
+ setDialogParents: function ( text, dialog ) {
4787
+ _.each( this.dialogs, function ( p, i, d ) {
4788
+ d[ i ].setParent( text, dialog );
4789
+ } );
4790
+
4791
+ // For any future dialogs
4792
+ this.on( 'add_dialog', function ( newDialog ) {
4793
+ newDialog.setParent( text, dialog );
4794
+ }, this );
4795
+ },
4796
+
4797
+ /**
4798
+ * This shows or hides the welcome display depending on whether there are any rows in the collection.
4799
+ */
4800
+ toggleWelcomeDisplay: function () {
4801
+ if ( !this.model.get( 'rows' ).isEmpty() ) {
4802
+ this.$( '.so-panels-welcome-message' ).hide();
4803
+ } else {
4804
+ this.$( '.so-panels-welcome-message' ).show();
4805
+ }
4806
+ },
4807
+
4808
+ /**
4809
+ * Activate the contextual menu
4810
+ * @param e
4811
+ * @param menu
4812
+ */
4813
+ activateContextMenu: function ( e, menu ) {
4814
+ var builder = this;
4815
+
4816
+ // Only run this if the event target is a descendant of this builder's DOM element.
4817
+ if ( $.contains( builder.$el.get( 0 ), e.target ) ) {
4818
+ // Get the element we're currently hovering over
4819
+ var over = $( [] )
4820
+ .add( builder.$( '.so-panels-welcome-message:visible' ) )
4821
+ .add( builder.$( '.so-rows-container > .so-row-container' ) )
4822
+ .add( builder.$( '.so-cells > .cell' ) )
4823
+ .add( builder.$( '.cell-wrapper > .so-widget' ) )
4824
+ .filter( function ( i ) {
4825
+ return menu.isOverEl( $( this ), e );
4826
+ } );
4827
+
4828
+ var activeView = over.last().data( 'view' );
4829
+ if ( activeView !== undefined && activeView.buildContextualMenu !== undefined ) {
4830
+ // We'll pass this to the current active view so it can populate the contextual menu
4831
+ activeView.buildContextualMenu( e, menu );
4832
+ }
4833
+ else if ( over.last().hasClass( 'so-panels-welcome-message' ) ) {
4834
+ // The user opened the contextual menu on the welcome message
4835
+ this.buildContextualMenu( e, menu );
4836
+ }
4837
+ }
4838
+ },
4839
+
4840
+ /**
4841
+ * Build the contextual menu for the main builder - before any content has been added.
4842
+ */
4843
+ buildContextualMenu: function ( e, menu ) {
4844
+ var actions = {};
4845
+
4846
+ if ( this.supports( 'addRow' ) ) {
4847
+ actions.add_row = { title: panelsOptions.loc.contextual.add_row };
4848
+ }
4849
+
4850
+ if ( panels.helpers.clipboard.canCopyPaste() ) {
4851
+ if ( panels.helpers.clipboard.isModel( 'row-model' ) && this.supports( 'addRow' ) ) {
4852
+ actions.paste_row = { title: panelsOptions.loc.contextual.row_paste };
4853
+ }
4854
+ }
4855
+
4856
+ if ( !_.isEmpty( actions ) ) {
4857
+ menu.addSection(
4858
+ 'builder-actions',
4859
+ {
4860
+ sectionTitle: panelsOptions.loc.contextual.row_actions,
4861
+ search: false,
4862
+ },
4863
+ actions,
4864
+ function ( c ) {
4865
+ switch ( c ) {
4866
+ case 'add_row':
4867
+ this.displayAddRowDialog();
4868
+ break;
4869
+
4870
+ case 'paste_row':
4871
+ this.pasteRowHandler();
4872
+ break;
4873
+ }
4874
+ }.bind( this )
4875
+ );
4876
+ }
4877
+ },
4878
+ } );
4879
+
4880
+ },{}],24:[function(require,module,exports){
4881
+ var panels = window.panels, $ = jQuery;
4882
+
4883
+ module.exports = Backbone.View.extend( {
4884
+ template: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-builder-cell' ).html() ) ),
4885
+ events: {
4886
+ 'click .cell-wrapper': 'handleCellClick'
4887
+ },
4888
+
4889
+ /* The row view that this cell is a part of */
4890
+ row: null,
4891
+ widgetSortable: null,
4892
+
4893
+ initialize: function () {
4894
+ this.listenTo(this.model.get('widgets'), 'add', this.onAddWidget );
4895
+ },
4896
+
4897
+ /**
4898
+ * Render the actual cell
4899
+ */
4900
+ render: function () {
4901
+ var templateArgs = {
4902
+ weight: this.model.get( 'weight' ),
4903
+ totalWeight: this.row.model.get('cells').totalWeight()
4904
+ };
4905
+
4906
+ this.setElement( this.template( templateArgs ) );
4907
+ this.$el.data( 'view', this );
4908
+
4909
+ // Now lets render any widgets that are currently in the row
4910
+ var thisView = this;
4911
+ this.model.get('widgets').each( function ( widget ) {
4912
+ var widgetView = new panels.view.widget( {model: widget} );
4913
+ widgetView.cell = thisView;
4914
+ widgetView.render();
4915
+
4916
+ widgetView.$el.appendTo( thisView.$( '.widgets-container' ) );
4917
+ } );
4918
+
4919
+ this.initSortable();
4920
+ this.initResizable();
4921
+
4922
+ return this;
4923
+ },
4924
+
4925
+ /**
4926
+ * Initialize the widget sortable
4927
+ */
4928
+ initSortable: function () {
4929
+ if( ! this.row.builder.supports( 'moveWidget' ) ) {
4930
+ return this;
4931
+ }
4932
+
4933
+ var cellView = this;
4934
+ var builder = cellView.row.builder;
4935
+
4936
+ // Go up the view hierarchy until we find the ID attribute
4937
+ var builderID = builder.$el.attr( 'id' );
4938
+ var builderModel = builder.model;
4939
+
4940
+ // Create a widget sortable that's connected with all other cells
4941
+ this.widgetSortable = this.$( '.widgets-container' ).sortable( {
4942
+ placeholder: "so-widget-sortable-highlight",
4943
+ connectWith: '#' + builderID + ' .so-cells .cell .widgets-container,.block-editor .so-cells .cell .widgets-container',
4944
+ tolerance: 'pointer',
4945
+ scroll: false,
4946
+ over: function ( e, ui ) {
4947
+ // This will make all the rows in the current builder resize
4948
+ cellView.row.builder.trigger( 'widget_sortable_move' );
4949
+ },
4950
+ remove: function ( e, ui ) {
4951
+ cellView.model.get( 'widgets' ).remove(
4952
+ $( ui.item ).data( 'view' ).model,
4953
+ { silent: true }
4954
+ );
4955
+ builderModel.refreshPanelsData();
4956
+ },
4957
+ receive: function ( e, ui ) {
4958
+ var widgetModel = $( ui.item ).data( 'view' ).model;
4959
+ widgetModel.cell = cellView.model;
4960
+ cellView.model.get( 'widgets' ).add(
4961
+ widgetModel,
4962
+ { silent: true, at: $( ui.item ).index() }
4963
+ );
4964
+ builderModel.refreshPanelsData();
4965
+ },
4966
+ stop: function ( e, ui ) {
4967
+ var $$ = $( ui.item ),
4968
+ widget = $$.data( 'view' ),
4969
+ targetCell = $$.closest( '.cell' ).data( 'view' );
4970
+
4971
+
4972
+ // If this hasn't already been removed and added to a different builder.
4973
+ if ( cellView.model.get( 'widgets' ).get( widget.model ) ) {
4974
+
4975
+ cellView.row.builder.addHistoryEntry( 'widget_moved' );
4976
+
4977
+ // Move the model and the view to the new cell
4978
+ widget.model.moveToCell( targetCell.model, {}, $$.index() );
4979
+ widget.cell = targetCell;
4980
+
4981
+ builderModel.refreshPanelsData();
4982
+ }
4983
+ },
4984
+ helper: function ( e, el ) {
4985
+ var helper = el.clone()
4986
+ .css( {
4987
+ 'width': el.outerWidth(),
4988
+ 'z-index': 10000,
4989
+ 'position': 'fixed'
4990
+ } )
4991
+ .addClass( 'widget-being-dragged' ).appendTo( 'body' );
4992
+
4993
+ // Center the helper to the mouse cursor.
4994
+ if ( el.outerWidth() > 720 ) {
4995
+ helper.animate( {
4996
+ 'margin-left': e.pageX - el.offset().left - (
4997
+ 480 / 2
4998
+ ),
4999
+ 'width': 480
5000
+ }, 'fast' );
5001
+ }
5002
+
5003
+ return helper;
5004
+ }
5005
+ } );
5006
+
5007
+ return this;
5008
+ },
5009
+
5010
+ /**
5011
+ * Refresh the widget sortable when a new widget is added
5012
+ */
5013
+ refreshSortable: function () {
5014
+ if ( ! _.isNull( this.widgetSortable ) ) {
5015
+ this.widgetSortable.sortable( 'refresh' );
5016
+ }
5017
+ },
5018
+
5019
+ /**
5020
+ * This will make the cell resizble
5021
+ */
5022
+ initResizable: function () {
5023
+ if( ! this.row.builder.supports( 'editRow' ) ) {
5024
+ return this;
5025
+ }
5026
+
5027
+ // var neighbor = this.$el.previous().data('view');
5028
+ var handle = this.$( '.resize-handle' ).css( 'position', 'absolute' );
5029
+ var container = this.row.$el;
5030
+ var cellView = this;
5031
+
5032
+ // The view of the cell to the left is stored when dragging starts.
5033
+ var previousCell;
5034
+
5035
+ handle.draggable( {
5036
+ axis: 'x',
5037
+ containment: container,
5038
+ start: function ( e, ui ) {
5039
+ // Set the containment to the cell parent
5040
+ previousCell = cellView.$el.prev().data( 'view' );
5041
+ if ( _.isUndefined( previousCell ) ) {
5042
+ return;
5043
+ }
5044
+
5045
+ // Create the clone for the current cell
5046
+ var newCellClone = cellView.$el.clone().appendTo( ui.helper ).css( {
5047
+ position: 'absolute',
5048
+ top: '0',
5049
+ width: cellView.$el.outerWidth(),
5050
+ left: 5,
5051
+ height: cellView.$el.outerHeight()
5052
+ } );
5053
+ newCellClone.find( '.resize-handle' ).remove();
5054
+
5055
+ // Create the clone for the previous cell
5056
+ var prevCellClone = previousCell.$el.clone().appendTo( ui.helper ).css( {
5057
+ position: 'absolute',
5058
+ top: '0',
5059
+ width: previousCell.$el.outerWidth(),
5060
+ right: 5,
5061
+ height: previousCell.$el.outerHeight()
5062
+ } );
5063
+ prevCellClone.find( '.resize-handle' ).remove();
5064
+
5065
+ $( this ).data( {
5066
+ 'newCellClone': newCellClone,
5067
+ 'prevCellClone': prevCellClone
5068
+ } );
5069
+ },
5070
+ drag: function ( e, ui ) {
5071
+ // Calculate the new cell and previous cell widths as a percent
5072
+ var containerWidth = cellView.row.$el.width() + 10;
5073
+ var ncw = cellView.model.get( 'weight' ) - (
5074
+ (
5075
+ ui.position.left + handle.outerWidth() / 2
5076
+ ) / containerWidth
5077
+ );
5078
+ var pcw = previousCell.model.get( 'weight' ) + (
5079
+ (
5080
+ ui.position.left + handle.outerWidth() / 2
5081
+ ) / containerWidth
5082
+ );
5083
+
5084
+ $( this ).data( 'newCellClone' ).css( 'width', containerWidth * ncw )
5085
+ .find( '.preview-cell-weight' ).html( Math.round( ncw * 1000 ) / 10 );
5086
+
5087
+ $( this ).data( 'prevCellClone' ).css( 'width', containerWidth * pcw )
5088
+ .find( '.preview-cell-weight' ).html( Math.round( pcw * 1000 ) / 10 );
5089
+ },
5090
+ stop: function ( e, ui ) {
5091
+ // Remove the clones
5092
+ $( this ).data( 'newCellClone' ).remove();
5093
+ $( this ).data( 'prevCellClone' ).remove();
5094
+
5095
+ var containerWidth = cellView.row.$el.width() + 10;
5096
+ var ncw = cellView.model.get( 'weight' ) - (
5097
+ (
5098
+ ui.position.left + handle.outerWidth() / 2
5099
+ ) / containerWidth
5100
+ );
5101
+ var pcw = previousCell.model.get( 'weight' ) + (
5102
+ (
5103
+ ui.position.left + handle.outerWidth() / 2
5104
+ ) / containerWidth
5105
+ );
5106
+
5107
+ if ( ncw > 0.02 && pcw > 0.02 ) {
5108
+ cellView.row.builder.addHistoryEntry( 'cell_resized' );
5109
+ cellView.model.set( 'weight', ncw );
5110
+ previousCell.model.set( 'weight', pcw );
5111
+ cellView.row.resize();
5112
+ }
5113
+
5114
+ ui.helper.css( 'left', - handle.outerWidth() / 2 );
5115
+
5116
+ // Refresh the panels data
5117
+ cellView.row.builder.model.refreshPanelsData();
5118
+ }
5119
+ } );
5120
+
5121
+ return this;
5122
+ },
5123
+
5124
+ /**
5125
+ * This is triggered when ever a widget is added to the row collection.
5126
+ *
5127
+ * @param widget
5128
+ */
5129
+ onAddWidget: function ( widget, collection, options ) {
5130
+ options = _.extend( {noAnimate: false}, options );
5131
+
5132
+ // Create the view for the widget
5133
+ var view = new panels.view.widget( {
5134
+ model: widget
5135
+ } );
5136
+ view.cell = this;
5137
+
5138
+ if ( _.isUndefined( widget.isDuplicate ) ) {
5139
+ widget.isDuplicate = false;
5140
+ }
5141
+
5142
+ // Render and load the form if this is a duplicate
5143
+ view.render( {
5144
+ 'loadForm': widget.isDuplicate
5145
+ } );
5146
+
5147
+ if ( _.isUndefined( options.at ) || collection.length <= 1 ) {
5148
+ // Insert this at the end of the widgets container
5149
+ view.$el.appendTo( this.$( '.widgets-container' ) );
5150
+ } else {
5151
+ // We need to insert this at a specific position
5152
+ view.$el.insertAfter(
5153
+ this.$( '.widgets-container .so-widget' ).eq( options.at - 1 )
5154
+ );
5155
+ }
5156
+
5157
+ if ( options.noAnimate === false ) {
5158
+ // We need an animation
5159
+ view.visualCreate();
5160
+ }
5161
+
5162
+ this.refreshSortable();
5163
+ this.row.resize();
5164
+ this.row.builder.trigger( 'widget_added' );
5165
+ },
5166
+
5167
+ /**
5168
+ * Handle this cell being clicked on
5169
+ *
5170
+ * @param e
5171
+ * @returns {boolean}
5172
+ */
5173
+ handleCellClick: function ( e ) {
5174
+ // Remove all existing selected cell indication for this builder
5175
+ this.row.builder.$el.find( '.so-cells .cell' ).removeClass( 'cell-selected' );
5176
+
5177
+ if( this.row.builder.activeCell === this && ! this.model.get('widgets').length ) {
5178
+ // This is a click on an empty cell
5179
+ this.row.builder.activeCell = null;
5180
+ }
5181
+ else {
5182
+ this.$el.addClass( 'cell-selected' );
5183
+ this.row.builder.activeCell = this;
5184
+ }
5185
+ },
5186
+
5187
+ /**
5188
+ * Insert a widget from the clipboard
5189
+ */
5190
+ pasteHandler: function(){
5191
+ var pastedModel = panels.helpers.clipboard.getModel( 'widget-model' );
5192
+ if( ! _.isEmpty( pastedModel ) && pastedModel instanceof panels.model.widget ) {
5193
+ this.row.builder.addHistoryEntry( 'widget_pasted' );
5194
+ pastedModel.cell = this.model;
5195
+ this.model.get('widgets').add( pastedModel );
5196
+ this.row.builder.model.refreshPanelsData();
5197
+ }
5198
+ },
5199
+
5200
+ /**
5201
+ * Build up the contextual menu for a cell
5202
+ *
5203
+ * @param e
5204
+ * @param menu
5205
+ */
5206
+ buildContextualMenu: function ( e, menu ) {
5207
+ var thisView = this;
5208
+
5209
+ if( ! menu.hasSection( 'add-widget-below' ) ) {
5210
+ menu.addSection(
5211
+ 'add-widget-cell',
5212
+ {
5213
+ sectionTitle: panelsOptions.loc.contextual.add_widget_cell,
5214
+ searchPlaceholder: panelsOptions.loc.contextual.search_widgets,
5215
+ defaultDisplay: panelsOptions.contextual.default_widgets
5216
+ },
5217
+ panelsOptions.widgets,
5218
+ function ( c ) {
5219
+ thisView.row.builder.trigger('before_user_adds_widget')
5220
+ thisView.row.builder.addHistoryEntry( 'widget_added' );
5221
+
5222
+ var widget = new panels.model.widget( {
5223
+ class: c
5224
+ } );
5225
+
5226
+ // Add the widget to the cell model
5227
+ widget.cell = thisView.model;
5228
+ widget.cell.get('widgets').add( widget );
5229
+
5230
+ thisView.row.builder.model.refreshPanelsData();
5231
+ thisView.row.builder.trigger('after_user_adds_widget', widget);
5232
+ }
5233
+ );
5234
+ }
5235
+
5236
+ var actions = {};
5237
+ if ( this.row.builder.supports('addWidget') && panels.helpers.clipboard.isModel( 'widget-model' ) ) {
5238
+ actions.paste = {title: panelsOptions.loc.contextual.cell_paste_widget};
5239
+ }
5240
+
5241
+ if( ! _.isEmpty( actions ) ) {
5242
+ menu.addSection(
5243
+ 'cell-actions',
5244
+ {
5245
+ sectionTitle: panelsOptions.loc.contextual.cell_actions,
5246
+ search: false,
5247
+ },
5248
+ actions,
5249
+ function ( c ) {
5250
+ switch ( c ) {
5251
+ case 'paste':
5252
+ this.pasteHandler();
5253
+ break;
5254
+ }
5255
+
5256
+ this.row.builder.model.refreshPanelsData();
5257
+ }.bind( this )
5258
+ );
5259
+ }
5260
+
5261
+ // Add the contextual menu for the parent row
5262
+ this.row.buildContextualMenu( e, menu );
5263
+ }
5264
+ } );
5265
+
5266
+ },{}],25:[function(require,module,exports){
5267
+ var panels = window.panels, $ = jQuery;
5268
+
5269
+ module.exports = Backbone.View.extend( {
5270
+ dialogTemplate: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-dialog' ).html() ) ),
5271
+ dialogTabTemplate: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-dialog-tab' ).html() ) ),
5272
+
5273
+ tabbed: false,
5274
+ rendered: false,
5275
+ builder: false,
5276
+ className: 'so-panels-dialog-wrapper',
5277
+ dialogClass: '',
5278
+ dialogIcon: '',
5279
+ parentDialog: false,
5280
+ dialogOpen: false,
5281
+ editableLabel: false,
5282
+
5283
+ events: {
5284
+ 'click .so-close': 'closeDialog',
5285
+ 'click .so-nav.so-previous': 'navToPrevious',
5286
+ 'click .so-nav.so-next': 'navToNext',
5287
+ },
5288
+
5289
+ initialize: function () {
5290
+ // The first time this dialog is opened, render it
5291
+ this.once( 'open_dialog', this.render );
5292
+ this.once( 'open_dialog', this.attach );
5293
+ this.once( 'open_dialog', this.setDialogClass );
5294
+
5295
+ this.trigger( 'initialize_dialog', this );
5296
+
5297
+ if ( ! _.isUndefined( this.initializeDialog ) ) {
5298
+ this.initializeDialog();
5299
+ }
5300
+
5301
+ _.bindAll( this, 'initSidebars', 'hasSidebar', 'onResize', 'toggleLeftSideBar', 'toggleRightSideBar' );
5302
+ },
5303
+
5304
+ /**
5305
+ * Returns the next dialog in the sequence. Should be overwritten by a child dialog.
5306
+ * @returns {null}
5307
+ */
5308
+ getNextDialog: function () {
5309
+ return null;
5310
+ },
5311
+
5312
+ /**
5313
+ * Returns the previous dialog in this sequence. Should be overwritten by child dialog.
5314
+ * @returns {null}
5315
+ */
5316
+ getPrevDialog: function () {
5317
+ return null;
5318
+ },
5319
+
5320
+ /**
5321
+ * Adds a dialog class to uniquely identify this dialog type
5322
+ */
5323
+ setDialogClass: function () {
5324
+ if ( this.dialogClass !== '' ) {
5325
+ this.$( '.so-panels-dialog' ).addClass( this.dialogClass );
5326
+ }
5327
+ },
5328
+
5329
+ /**
5330
+ * Set the builder that controls this dialog.
5331
+ * @param {panels.view.builder} builder
5332
+ */
5333
+ setBuilder: function ( builder ) {
5334
+ this.builder = builder;
5335
+
5336
+ // Trigger an add dialog event on the builder so it can modify the dialog in any way
5337
+ builder.trigger( 'add_dialog', this, this.builder );
5338
+
5339
+ return this;
5340
+ },
5341
+
5342
+ /**
5343
+ * Attach the dialog to the window
5344
+ */
5345
+ attach: function () {
5346
+ this.$el.appendTo( 'body' );
5347
+
5348
+ return this;
5349
+ },
5350
+
5351
+ /**
5352
+ * Converts an HTML representation of the dialog into arguments for a dialog box
5353
+ * @param html HTML for the dialog
5354
+ * @param args Arguments passed to the template
5355
+ * @returns {}
5356
+ */
5357
+ parseDialogContent: function ( html, args ) {
5358
+ // Add a CID
5359
+ args = _.extend( {cid: this.cid}, args );
5360
+
5361
+
5362
+ var c = $( (
5363
+ _.template( panels.helpers.utils.processTemplate( html ) )
5364
+ )( args ) );
5365
+ var r = {
5366
+ title: c.find( '.title' ).html(),
5367
+ buttons: c.find( '.buttons' ).html(),
5368
+ content: c.find( '.content' ).html()
5369
+ };
5370
+
5371
+ if ( c.has( '.left-sidebar' ) ) {
5372
+ r.left_sidebar = c.find( '.left-sidebar' ).html();
5373
+ }
5374
+
5375
+ if ( c.has( '.right-sidebar' ) ) {
5376
+ r.right_sidebar = c.find( '.right-sidebar' ).html();
5377
+ }
5378
+
5379
+ return r;
5380
+
5381
+ },
5382
+
5383
+ /**
5384
+ * Render the dialog and initialize the tabs
5385
+ *
5386
+ * @param attributes
5387
+ * @returns {panels.view.dialog}
5388
+ */
5389
+ renderDialog: function ( attributes ) {
5390
+ attributes = _.extend( {
5391
+ editableLabel: this.editableLabel,
5392
+ dialogIcon: this.dialogIcon,
5393
+ }, attributes );
5394
+
5395
+ this.$el.html( this.dialogTemplate( attributes ) ).hide();
5396
+ this.$el.data( 'view', this );
5397
+ this.$el.addClass( 'so-panels-dialog-wrapper' );
5398
+
5399
+ if ( this.parentDialog !== false ) {
5400
+ // Add a link to the parent dialog as a sort of crumbtrail.
5401
+ var dialogParent = $( '<h3 class="so-parent-link"></h3>' ).html( this.parentDialog.text + '<div class="so-separator"></div>' );
5402
+ dialogParent.click( function ( e ) {
5403
+ e.preventDefault();
5404
+ this.closeDialog();
5405
+ this.parentDialog.dialog.openDialog();
5406
+ }.bind(this) );
5407
+ this.$( '.so-title-bar .so-title' ).before( dialogParent );
5408
+ }
5409
+
5410
+ if( this.$( '.so-title-bar .so-title-editable' ).length ) {
5411
+ // Added here because .so-edit-title is only available after the template has been rendered.
5412
+ this.initEditableLabel();
5413
+ }
5414
+
5415
+ setTimeout( this.initSidebars, 1 );
5416
+
5417
+ return this;
5418
+ },
5419
+
5420
+ initSidebars: function () {
5421
+ var $leftButton = this.$( '.so-show-left-sidebar' ).hide();
5422
+ var $rightButton = this.$( '.so-show-right-sidebar' ).hide();
5423
+ var hasLeftSidebar = this.hasSidebar( 'left' );
5424
+ var hasRightSidebar = this.hasSidebar( 'right' );
5425
+ // Set up resize handling
5426
+ if ( hasLeftSidebar || hasRightSidebar ) {
5427
+ $( window ).on( 'resize', this.onResize );
5428
+ if ( hasLeftSidebar ) {
5429
+ $leftButton.show();
5430
+ $leftButton.on( 'click', this.toggleLeftSideBar );
5431
+ }
5432
+ if ( hasRightSidebar ) {
5433
+ $rightButton.show();
5434
+ $rightButton.on( 'click', this.toggleRightSideBar );
5435
+ }
5436
+ }
5437
+
5438
+ this.onResize();
5439
+ },
5440
+
5441
+ /**
5442
+ * Initialize the sidebar tabs
5443
+ */
5444
+ initTabs: function () {
5445
+ var tabs = this.$( '.so-sidebar-tabs li a' );
5446
+
5447
+ if ( tabs.length === 0 ) {
5448
+ return this;
5449
+ }
5450
+
5451
+ var thisDialog = this;
5452
+ tabs.click( function ( e ) {
5453
+ e.preventDefault();
5454
+ var $$ = $( this );
5455
+
5456
+ thisDialog.$( '.so-sidebar-tabs li' ).removeClass( 'tab-active' );
5457
+ thisDialog.$( '.so-content .so-content-tabs > *' ).hide();
5458
+
5459
+ $$.parent().addClass( 'tab-active' );
5460
+
5461
+ var url = $$.attr( 'href' );
5462
+ if ( ! _.isUndefined( url ) && url.charAt( 0 ) === '#' ) {
5463
+ // Display the new tab
5464
+ var tabName = url.split( '#' )[1];
5465
+ thisDialog.$( '.so-content .so-content-tabs .tab-' + tabName ).show();
5466
+ }
5467
+
5468
+ // This lets other dialogs implement their own custom handlers
5469
+ thisDialog.trigger( 'tab_click', $$ );
5470
+
5471
+ } );
5472
+
5473
+ // Trigger a click on the first tab
5474
+ this.$( '.so-sidebar-tabs li a' ).first().click();
5475
+ return this;
5476
+ },
5477
+
5478
+ initToolbar: function () {
5479
+ // Trigger simplified click event for elements marked as toolbar buttons.
5480
+ var buttons = this.$( '.so-toolbar .so-buttons .so-toolbar-button' );
5481
+ buttons.click( function ( e ) {
5482
+ e.preventDefault();
5483
+
5484
+ this.trigger( 'button_click', $( e.currentTarget ) );
5485
+ }.bind( this ) );
5486
+
5487
+ // Handle showing and hiding the dropdown list items
5488
+ var $dropdowns = this.$( '.so-toolbar .so-buttons .so-dropdown-button' );
5489
+ $dropdowns.click( function ( e ) {
5490
+ e.preventDefault();
5491
+ var $dropdownButton = $( e.currentTarget );
5492
+ var $dropdownList = $dropdownButton.siblings( '.so-dropdown-links-wrapper' );
5493
+ if ( $dropdownList.is( '.hidden' ) ) {
5494
+ $dropdownList.removeClass( 'hidden' );
5495
+ } else {
5496
+ $dropdownList.addClass( 'hidden' );
5497
+ }
5498
+
5499
+ }.bind( this ) );
5500
+
5501
+ // Hide dropdown list on click anywhere, unless it's a dropdown option which requires confirmation in it's
5502
+ // unconfirmed state.
5503
+ $( 'html' ).click( function ( e ) {
5504
+ this.$( '.so-dropdown-links-wrapper' ).not( '.hidden' ).each( function ( index, el ) {
5505
+ var $dropdownList = $( el );
5506
+ var $trgt = $( e.target );
5507
+ if ( $trgt.length === 0 || !(
5508
+ (
5509
+ $trgt.is('.so-needs-confirm') && !$trgt.is('.so-confirmed')
5510
+ ) || $trgt.is('.so-dropdown-button')
5511
+ ) ) {
5512
+ $dropdownList.addClass('hidden');
5513
+ }
5514
+ } );
5515
+ }.bind( this ) );
5516
+ },
5517
+
5518
+ /**
5519
+ * Initialize the editable dialog title
5520
+ */
5521
+ initEditableLabel: function(){
5522
+ var $editElt = this.$( '.so-title-bar .so-title-editable' );
5523
+
5524
+ $editElt.keypress( function ( event ) {
5525
+ var enterPressed = event.type === 'keypress' && event.keyCode === 13;
5526
+ if ( enterPressed ) {
5527
+ // Need to make sure tab focus is on another element, otherwise pressing enter multiple times refocuses
5528
+ // the element and allows newlines.
5529
+ var tabbables = $( ':tabbable' );
5530
+ var curTabIndex = tabbables.index( $editElt );
5531
+ tabbables.eq( curTabIndex + 1 ).focus();
5532
+ // After the above, we're somehow left with the first letter of text selected,
5533
+ // so this removes the selection.
5534
+ window.getSelection().removeAllRanges();
5535
+ }
5536
+ return !enterPressed;
5537
+ } ).blur( function () {
5538
+ var newValue = $editElt.text().replace( /^\s+|\s+$/gm, '' );
5539
+ var oldValue = $editElt.data( 'original-value' ).replace( /^\s+|\s+$/gm, '' );
5540
+ if ( newValue !== oldValue ) {
5541
+ $editElt.text( newValue );
5542
+ this.trigger( 'edit_label', newValue );
5543
+ }
5544
+
5545
+ }.bind( this ) );
5546
+
5547
+ $editElt.focus( function() {
5548
+ $editElt.data( 'original-value', $editElt.text() );
5549
+ panels.helpers.utils.selectElementContents( this );
5550
+ } );
5551
+ },
5552
+
5553
+ /**
5554
+ * Quickly setup the dialog by opening and closing it.
5555
+ */
5556
+ setupDialog: function () {
5557
+ this.openDialog();
5558
+ this.closeDialog();
5559
+ },
5560
+
5561
+ /**
5562
+ * Refresh the next and previous buttons.
5563
+ */
5564
+ refreshDialogNav: function () {
5565
+ this.$( '.so-title-bar .so-nav' ).show().removeClass( 'so-disabled' );
5566
+
5567
+ // Lets also hide the next and previous if we don't have a next and previous dialog
5568
+ var nextDialog = this.getNextDialog();
5569
+ var nextButton = this.$( '.so-title-bar .so-next' );
5570
+
5571
+ var prevDialog = this.getPrevDialog();
5572
+ var prevButton = this.$( '.so-title-bar .so-previous' );
5573
+
5574
+ if ( nextDialog === null ) {
5575
+ nextButton.hide();
5576
+ }
5577
+ else if ( nextDialog === false ) {
5578
+ nextButton.addClass( 'so-disabled' );
5579
+ }
5580
+
5581
+ if ( prevDialog === null ) {
5582
+ prevButton.hide();
5583
+ }
5584
+ else if ( prevDialog === false ) {
5585
+ prevButton.addClass( 'so-disabled' );
5586
+ }
5587
+ },
5588
+
5589
+ /**
5590
+ * Open the dialog
5591
+ */
5592
+ openDialog: function ( options ) {
5593
+ options = _.extend( {
5594
+ silent: false
5595
+ }, options );
5596
+
5597
+ if ( ! options.silent ) {
5598
+ this.trigger( 'open_dialog' );
5599
+ }
5600
+
5601
+ this.dialogOpen = true;
5602
+
5603
+ this.refreshDialogNav();
5604
+
5605
+ // Stop scrolling for the main body
5606
+ panels.helpers.pageScroll.lock();
5607
+
5608
+ this.onResize();
5609
+
5610
+ this.$el.show();
5611
+
5612
+ if ( ! options.silent ) {
5613
+ // This triggers once everything is visible
5614
+ this.trigger( 'open_dialog_complete' );
5615
+ this.builder.trigger( 'open_dialog', this );
5616
+ $( document ).trigger( 'open_dialog', this );
5617
+ }
5618
+ },
5619
+
5620
+ /**
5621
+ * Close the dialog
5622
+ *
5623
+ * @param e
5624
+ * @returns {boolean}
5625
+ */
5626
+ closeDialog: function ( options ) {
5627
+ options = _.extend( {
5628
+ silent: false
5629
+ }, options );
5630
+
5631
+ if ( ! options.silent ) {
5632
+ this.trigger( 'close_dialog' );
5633
+ }
5634
+
5635
+ this.dialogOpen = false;
5636
+
5637
+ this.$el.hide();
5638
+ panels.helpers.pageScroll.unlock();
5639
+
5640
+ if ( ! options.silent ) {
5641
+ // This triggers once everything is hidden
5642
+ this.trigger( 'close_dialog_complete' );
5643
+ this.builder.trigger( 'close_dialog', this );
5644
+ }
5645
+ },
5646
+
5647
+ /**
5648
+ * Navigate to the previous dialog
5649
+ */
5650
+ navToPrevious: function () {
5651
+ this.closeDialog();
5652
+
5653
+ var prev = this.getPrevDialog();
5654
+ if ( prev !== null && prev !== false ) {
5655
+ prev.openDialog();
5656
+ }
5657
+ },
5658
+
5659
+ /**
5660
+ * Navigate to the next dialog
5661
+ */
5662
+ navToNext: function () {
5663
+ this.closeDialog();
5664
+
5665
+ var next = this.getNextDialog();
5666
+ if ( next !== null && next !== false ) {
5667
+ next.openDialog();
5668
+ }
5669
+ },
5670
+
5671
+ /**
5672
+ * Get the values from the form and convert them into a data array
5673
+ */
5674
+ getFormValues: function ( formSelector ) {
5675
+ if ( _.isUndefined( formSelector ) ) {
5676
+ formSelector = '.so-content';
5677
+ }
5678
+
5679
+ var $f = this.$( formSelector );
5680
+
5681
+ var data = {}, parts;
5682
+
5683
+ // Find all the named fields in the form
5684
+ $f.find( '[name]' ).each( function () {
5685
+ var $$ = $( this );
5686
+
5687
+ try {
5688
+
5689
+ var name = /([A-Za-z_]+)\[(.*)\]/.exec( $$.attr( 'name' ) );
5690
+ if ( _.isEmpty( name ) ) {
5691
+ return true;
5692
+ }
5693
+
5694
+ // Create an array with the parts of the name
5695
+ if ( _.isUndefined( name[2] ) ) {
5696
+ parts = $$.attr( 'name' );
5697
+ } else {
5698
+ parts = name[2].split( '][' );
5699
+ parts.unshift( name[1] );
5700
+ }
5701
+
5702
+ parts = parts.map( function ( e ) {
5703
+ if ( ! isNaN( parseFloat( e ) ) && isFinite( e ) ) {
5704
+ return parseInt( e );
5705
+ } else {
5706
+ return e;
5707
+ }
5708
+ } );
5709
+
5710
+ var sub = data;
5711
+ var fieldValue = null;
5712
+
5713
+ var fieldType = (
5714
+ _.isString( $$.attr( 'type' ) ) ? $$.attr( 'type' ).toLowerCase() : false
5715
+ );
5716
+
5717
+ // First we need to get the value from the field
5718
+ if ( fieldType === 'checkbox' ) {
5719
+ if ( $$.is( ':checked' ) ) {
5720
+ fieldValue = $$.val() !== '' ? $$.val() : true;
5721
+ } else {
5722
+ fieldValue = null;
5723
+ }
5724
+ }
5725
+ else if ( fieldType === 'radio' ) {
5726
+ if ( $$.is( ':checked' ) ) {
5727
+ fieldValue = $$.val();
5728
+ } else {
5729
+ //skip over unchecked radios
5730
+ return;
5731
+ }
5732
+ }
5733
+ else if ( $$.prop( 'tagName' ) === 'SELECT' ) {
5734
+ var selected = $$.find( 'option:selected' );
5735
+
5736
+ if ( selected.length === 1 ) {
5737
+ fieldValue = $$.find( 'option:selected' ).val();
5738
+ }
5739
+ else if ( selected.length > 1 ) {
5740
+ // This is a mutli-select field
5741
+ fieldValue = _.map( $$.find( 'option:selected' ), function ( n, i ) {
5742
+ return $( n ).val();
5743
+ } );
5744
+ }
5745
+
5746
+ } else {
5747
+ // This is a fallback that will work for most fields
5748
+ fieldValue = $$.val();
5749
+ }
5750
+
5751
+ // Now, we need to filter this value if necessary
5752
+ if ( ! _.isUndefined( $$.data( 'panels-filter' ) ) ) {
5753
+ switch ( $$.data( 'panels-filter' ) ) {
5754
+ case 'json_parse':
5755
+ // Attempt to parse the JSON value of this field
5756
+ try {
5757
+ fieldValue = JSON.parse( fieldValue );
5758
+ }
5759
+ catch ( err ) {
5760
+ fieldValue = '';
5761
+ }
5762
+ break;
5763
+ }
5764
+ }
5765
+
5766
+ // Now convert this into an array
5767
+ if ( fieldValue !== null ) {
5768
+ for ( var i = 0; i < parts.length; i ++ ) {
5769
+ if ( i === parts.length - 1 ) {
5770
+ if ( parts[i] === '' ) {
5771
+ // This needs to be an array
5772
+ sub.push( fieldValue );
5773
+ } else {
5774
+ sub[parts[i]] = fieldValue;
5775
+ }
5776
+ } else {
5777
+ if ( _.isUndefined( sub[parts[i]] ) ) {
5778
+ if ( parts[i + 1] === '' ) {
5779
+ sub[parts[i]] = [];
5780
+ } else {
5781
+ sub[parts[i]] = {};
5782
+ }
5783
+ }
5784
+ sub = sub[parts[i]];
5785
+ }
5786
+ }
5787
+ }
5788
+ }
5789
+ catch ( error ) {
5790
+ // Ignore this error, just log the message for debugging
5791
+ console.log( 'Field [' + $$.attr('name') + '] could not be processed and was skipped - ' + error.message );
5792
+ }
5793
+
5794
+ } ); // End of each through input fields
5795
+
5796
+ return data;
5797
+ },
5798
+
5799
+ /**
5800
+ * Set a status message for the dialog
5801
+ */
5802
+ setStatusMessage: function ( message, loading, error ) {
5803
+ var msg = error ? '<span class="dashicons dashicons-warning"></span>' + message : message;
5804
+ this.$( '.so-toolbar .so-status' ).html( msg );
5805
+ if ( ! _.isUndefined( loading ) && loading ) {
5806
+ this.$( '.so-toolbar .so-status' ).addClass( 'so-panels-loading' );
5807
+ } else {
5808
+ this.$( '.so-toolbar .so-status' ).removeClass( 'so-panels-loading' );
5809
+ }
5810
+ },
5811
+
5812
+ /**
5813
+ * Set the parent after.
5814
+ */
5815
+ setParent: function ( text, dialog ) {
5816
+ this.parentDialog = {
5817
+ text: text,
5818
+ dialog: dialog
5819
+ };
5820
+ },
5821
+
5822
+ onResize: function () {
5823
+ var mediaQuery = window.matchMedia( '(max-width: 980px)' );
5824
+ var sides = [ 'left', 'right' ];
5825
+
5826
+ sides.forEach( function ( side ) {
5827
+ var $sideBar = this.$( '.so-' + side + '-sidebar' );
5828
+ var $showSideBarButton = this.$( '.so-show-' + side + '-sidebar' );
5829
+ if ( this.hasSidebar( side ) ) {
5830
+ $showSideBarButton.hide();
5831
+ if ( mediaQuery.matches ) {
5832
+ $showSideBarButton.show();
5833
+ $showSideBarButton.closest( '.so-title-bar' ).addClass( 'so-has-' + side + '-button' );
5834
+ $sideBar.hide();
5835
+ $sideBar.closest( '.so-panels-dialog' ).removeClass( 'so-panels-dialog-has-' + side + '-sidebar' );
5836
+ } else {
5837
+ $showSideBarButton.hide();
5838
+ $showSideBarButton.closest( '.so-title-bar' ).removeClass( 'so-has-' + side + '-button' );
5839
+ $sideBar.show();
5840
+ $sideBar.closest( '.so-panels-dialog' ).addClass( 'so-panels-dialog-has-' + side + '-sidebar' );
5841
+ }
5842
+ } else {
5843
+ $sideBar.hide();
5844
+ $showSideBarButton.hide();
5845
+ }
5846
+ }.bind( this ) );
5847
+ },
5848
+
5849
+ hasSidebar: function ( side ) {
5850
+ return this.$( '.so-' + side + '-sidebar' ).children().length > 0;
5851
+ },
5852
+
5853
+ toggleLeftSideBar: function () {
5854
+ this.toggleSidebar( 'left' );
5855
+ },
5856
+
5857
+ toggleRightSideBar: function () {
5858
+ this.toggleSidebar( 'right' );
5859
+ },
5860
+
5861
+ toggleSidebar: function ( side ) {
5862
+ var sidebar = this.$( '.so-' + side + '-sidebar' );
5863
+
5864
+ if ( sidebar.is( ':visible' ) ) {
5865
+ sidebar.hide();
5866
+ } else {
5867
+ sidebar.show();
5868
+ }
5869
+ },
5870
+
5871
+ } );
5872
+
5873
+ },{}],26:[function(require,module,exports){
5874
+ var panels = window.panels, $ = jQuery;
5875
+
5876
+ module.exports = Backbone.View.extend( {
5877
+ template: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-live-editor' ).html() ) ),
5878
+
5879
+ previewScrollTop: 0,
5880
+ loadTimes: [],
5881
+ previewFrameId: 1,
5882
+
5883
+ previewUrl: null,
5884
+ previewIframe: null,
5885
+
5886
+ events: {
5887
+ 'click .live-editor-close': 'close',
5888
+ 'click .live-editor-save': 'closeAndSave',
5889
+ 'click .live-editor-collapse': 'collapse',
5890
+ 'click .live-editor-mode': 'mobileToggle'
5891
+ },
5892
+
5893
+ initialize: function ( options ) {
5894
+ options = _.extend( {
5895
+ builder: false,
5896
+ previewUrl: false,
5897
+ }, options );
5898
+
5899
+ if( _.isEmpty( options.previewUrl ) ) {
5900
+ options.previewUrl = panelsOptions.ajaxurl + "&action=so_panels_live_editor_preview";
5901
+ }
5902
+
5903
+ this.builder = options.builder;
5904
+ this.previewUrl = options.previewUrl;
5905
+
5906
+ this.listenTo( this.builder.model, 'refresh_panels_data', this.handleRefreshData );
5907
+ this.listenTo( this.builder.model, 'load_panels_data', this.handleLoadData );
5908
+ },
5909
+
5910
+ /**
5911
+ * Render the live editor
5912
+ */
5913
+ render: function () {
5914
+ this.setElement( this.template() );
5915
+ this.$el.hide();
5916
+
5917
+ if ( $( '#submitdiv #save-post' ).length > 0 ) {
5918
+ var $saveButton = this.$el.find( '.live-editor-save' );
5919
+ $saveButton.text( $saveButton.data( 'save' ) );
5920
+ }
5921
+
5922
+ var isMouseDown = false;
5923
+ $( document )
5924
+ .mousedown( function () {
5925
+ isMouseDown = true;
5926
+ } )
5927
+ .mouseup( function () {
5928
+ isMouseDown = false;
5929
+ } );
5930
+
5931
+ // Handle highlighting the relevant widget in the live editor preview
5932
+ var liveEditorView = this;
5933
+ this.$el.on( 'mouseenter', '.so-widget-wrapper', function () {
5934
+ var $$ = $( this ),
5935
+ previewWidget = $$.data( 'live-editor-preview-widget' );
5936
+
5937
+ if ( ! isMouseDown && previewWidget !== undefined && previewWidget.length && ! liveEditorView.$( '.so-preview-overlay' ).is( ':visible' ) ) {
5938
+ liveEditorView.highlightElement( previewWidget );
5939
+ liveEditorView.scrollToElement( previewWidget );
5940
+ }
5941
+ } );
5942
+
5943
+ this.$el.on( 'mouseleave', '.so-widget-wrapper', function () {
5944
+ this.resetHighlights();
5945
+ }.bind(this) );
5946
+
5947
+ this.listenTo( this.builder, 'open_dialog', function () {
5948
+ this.resetHighlights();
5949
+ } );
5950
+
5951
+ return this;
5952
+ },
5953
+
5954
+ /**
5955
+ * Attach the live editor to the document
5956
+ */
5957
+ attach: function () {
5958
+ this.$el.appendTo( 'body' );
5959
+ },
5960
+
5961
+ /**
5962
+ * Display the live editor
5963
+ */
5964
+ open: function () {
5965
+ if ( this.$el.html() === '' ) {
5966
+ this.render();
5967
+ }
5968
+ if ( this.$el.closest( 'body' ).length === 0 ) {
5969
+ this.attach();
5970
+ }
5971
+
5972
+ // Disable page scrolling
5973
+ panels.helpers.pageScroll.lock();
5974
+
5975
+ if ( this.$el.is( ':visible' ) ) {
5976
+ return this;
5977
+ }
5978
+
5979
+ // Refresh the preview display
5980
+ this.$el.show();
5981
+ this.refreshPreview( this.builder.model.getPanelsData() );
5982
+
5983
+ // Move the builder view into the Live Editor
5984
+ this.originalContainer = this.builder.$el.parent();
5985
+ this.builder.$el.appendTo( this.$( '.so-live-editor-builder' ) );
5986
+ this.builder.$( '.so-tool-button.so-live-editor' ).hide();
5987
+ this.builder.trigger( 'builder_resize' );
5988
+
5989
+
5990
+ if( $('#original_post_status' ).val() === 'auto-draft' && ! this.autoSaved ) {
5991
+ // The live editor requires a saved draft post, so we'll create one for auto-draft posts
5992
+ var thisView = this;
5993
+
5994
+ if ( wp.autosave ) {
5995
+ // Set a temporary post title so the autosave triggers properly
5996
+ if( $('#title[name="post_title"]' ).val() === '' ) {
5997
+ $('#title[name="post_title"]' ).val( panelsOptions.loc.draft ).trigger('keydown');
5998
+ }
5999
+
6000
+ $( document ).one( 'heartbeat-tick.autosave', function(){
6001
+ thisView.autoSaved = true;
6002
+ thisView.refreshPreview( thisView.builder.model.getPanelsData() );
6003
+ } );
6004
+ wp.autosave.server.triggerSave();
6005
+ }
6006
+ }
6007
+ },
6008
+
6009
+ /**
6010
+ * Close the Live Editor
6011
+ */
6012
+ close: function () {
6013
+ if ( ! this.$el.is( ':visible' ) ) {
6014
+ return this;
6015
+ }
6016
+
6017
+ this.$el.hide();
6018
+ panels.helpers.pageScroll.unlock();
6019
+
6020
+ // Move the builder back to its original container
6021
+ this.builder.$el.appendTo( this.originalContainer );
6022
+ this.builder.$( '.so-tool-button.so-live-editor' ).show();
6023
+ this.builder.trigger( 'builder_resize' );
6024
+ },
6025
+
6026
+ /**
6027
+ * Close the Live Editor and save the post.
6028
+ */
6029
+ closeAndSave: function(){
6030
+ this.close();
6031
+ // Finds the submit input for saving without publishing draft posts.
6032
+ $('#submitdiv input[type="submit"][name="save"]').click();
6033
+ },
6034
+
6035
+ /**
6036
+ * Collapse the live editor
6037
+ */
6038
+ collapse: function () {
6039
+ this.$el.toggleClass( 'so-collapsed' );
6040
+ },
6041
+
6042
+ /**
6043
+ * Create an overlay in the preview.
6044
+ *
6045
+ * @param over
6046
+ * @return {*|Object} The item we're hovering over.
6047
+ */
6048
+ highlightElement: function ( over ) {
6049
+ if( ! _.isUndefined( this.resetHighlightTimeout ) ) {
6050
+ clearTimeout( this.resetHighlightTimeout );
6051
+ }
6052
+
6053
+ // Remove any old overlays
6054
+
6055
+ var body = this.previewIframe.contents().find( 'body' );
6056
+ body.find( '.panel-grid .panel-grid-cell .so-panel' )
6057
+ .filter( function () {
6058
+ // Filter to only include non nested
6059
+ return $( this ).parents( '.so-panel' ).length === 0;
6060
+ } )
6061
+ .not( over )
6062
+ .addClass( 'so-panels-faded' );
6063
+
6064
+ over.removeClass( 'so-panels-faded' ).addClass( 'so-panels-highlighted' );
6065
+ },
6066
+
6067
+ /**
6068
+ * Reset highlights in the live preview
6069
+ */
6070
+ resetHighlights: function() {
6071
+
6072
+ var body = this.previewIframe.contents().find( 'body' );
6073
+ this.resetHighlightTimeout = setTimeout( function(){
6074
+ body.find( '.panel-grid .panel-grid-cell .so-panel' )
6075
+ .removeClass( 'so-panels-faded so-panels-highlighted' );
6076
+ }, 100 );
6077
+ },
6078
+
6079
+ /**
6080
+ * Scroll over an element in the live preview
6081
+ * @param over
6082
+ */
6083
+ scrollToElement: function( over ) {
6084
+ var contentWindow = this.$( '.so-preview iframe' )[0].contentWindow;
6085
+ contentWindow.liveEditorScrollTo( over );
6086
+ },
6087
+
6088
+ handleRefreshData: function ( newData ) {
6089
+ if ( ! this.$el.is( ':visible' ) ) {
6090
+ return this;
6091
+ }
6092
+
6093
+ this.refreshPreview( newData );
6094
+ },
6095
+
6096
+ handleLoadData: function () {
6097
+ if ( ! this.$el.is( ':visible' ) ) {
6098
+ return this;
6099
+ }
6100
+
6101
+ this.refreshPreview( this.builder.model.getPanelsData() );
6102
+ },
6103
+
6104
+ /**
6105
+ * Refresh the Live Editor preview.
6106
+ * @returns {exports}
6107
+ */
6108
+ refreshPreview: function ( data ) {
6109
+ var loadTimePrediction = this.loadTimes.length ?
6110
+ _.reduce( this.loadTimes, function ( memo, num ) {
6111
+ return memo + num;
6112
+ }, 0 ) / this.loadTimes.length : 1000;
6113
+
6114
+ // Store the last preview iframe position
6115
+ if( ! _.isNull( this.previewIframe ) ) {
6116
+ if ( ! this.$( '.so-preview-overlay' ).is( ':visible' ) ) {
6117
+ this.previewScrollTop = this.previewIframe.contents().scrollTop();
6118
+ }
6119
+ }
6120
+
6121
+ // Add a loading bar
6122
+ this.$( '.so-preview-overlay' ).show();
6123
+ this.$( '.so-preview-overlay .so-loading-bar' )
6124
+ .clearQueue()
6125
+ .css( 'width', '0%' )
6126
+ .animate( {width: '100%'}, parseInt( loadTimePrediction ) + 100 );
6127
+
6128
+
6129
+ this.postToIframe(
6130
+ {
6131
+ live_editor_panels_data: JSON.stringify( data ),
6132
+ live_editor_post_ID: this.builder.config.postId
6133
+ },
6134
+ this.previewUrl,
6135
+ this.$('.so-preview')
6136
+ );
6137
+
6138
+ this.previewIframe.data( 'load-start', new Date().getTime() );
6139
+ },
6140
+
6141
+ /**
6142
+ * Use a temporary form to post data to an iframe.
6143
+ *
6144
+ * @param data The data to send
6145
+ * @param url The preview URL
6146
+ * @param target The target iframe
6147
+ */
6148
+ postToIframe: function( data, url, target ){
6149
+ // Store the old preview
6150
+
6151
+ if( ! _.isNull( this.previewIframe ) ) {
6152
+ this.previewIframe.remove();
6153
+ }
6154
+
6155
+ var iframeId = 'siteorigin-panels-live-preview-' + this.previewFrameId;
6156
+
6157
+ // Remove the old preview frame
6158
+ this.previewIframe = $('<iframe src="javascript:false;" />')
6159
+ .attr( {
6160
+ 'id' : iframeId,
6161
+ 'name' : iframeId,
6162
+ } )
6163
+ .appendTo( target );
6164
+
6165
+ this.setupPreviewFrame( this.previewIframe );
6166
+
6167
+ // We can use a normal POST form submit
6168
+ var tempForm = $('<form id="soPostToPreviewFrame" method="post" />')
6169
+ .attr( {
6170
+ id: iframeId,
6171
+ target: this.previewIframe.attr('id'),
6172
+ action: url
6173
+ } )
6174
+ .appendTo( 'body' );
6175
+
6176
+ $.each( data, function( name, value ){
6177
+ $('<input type="hidden" />')
6178
+ .attr( {
6179
+ name: name,
6180
+ value: value
6181
+ } )
6182
+ .appendTo( tempForm );
6183
+ } );
6184
+
6185
+ tempForm
6186
+ .submit()
6187
+ .remove();
6188
+
6189
+ this.previewFrameId++;
6190
+
6191
+ return this.previewIframe;
6192
+ },
6193
+
6194
+ /**
6195
+ * Do all the basic setup for the preview Iframe element
6196
+ * @param iframe
6197
+ */
6198
+ setupPreviewFrame: function( iframe ){
6199
+ var thisView = this;
6200
+ iframe
6201
+ .data( 'iframeready', false )
6202
+ .on( 'iframeready', function () {
6203
+ var $$ = $( this ),
6204
+ $iframeContents = $$.contents();
6205
+
6206
+ if( $$.data( 'iframeready' ) ) {
6207
+ // Skip this if the iframeready function has already run
6208
+ return;
6209
+ }
6210
+
6211
+ $$.data( 'iframeready', true );
6212
+
6213
+ if ( $$.data( 'load-start' ) !== undefined ) {
6214
+ thisView.loadTimes.unshift( new Date().getTime() - $$.data( 'load-start' ) );
6215
+
6216
+ if ( ! _.isEmpty( thisView.loadTimes ) ) {
6217
+ thisView.loadTimes = thisView.loadTimes.slice( 0, 4 );
6218
+ }
6219
+ }
6220
+
6221
+ setTimeout( function(){
6222
+ // Scroll to the correct position
6223
+ $iframeContents.scrollTop( thisView.previewScrollTop );
6224
+ thisView.$( '.so-preview-overlay' ).hide();
6225
+ }, 100 );
6226
+
6227
+
6228
+ // Lets find all the first level grids. This is to account for the Page Builder layout widget.
6229
+ var layoutWrapper = $iframeContents.find( '#pl-' + thisView.builder.config.postId );
6230
+ layoutWrapper.find( '.panel-grid .panel-grid-cell .so-panel' )
6231
+ .filter( function () {
6232
+ // Filter to only include non nested
6233
+ return $( this ).closest( '.panel-layout' ).is( layoutWrapper );
6234
+ } )
6235
+ .each( function ( i, el ) {
6236
+ var $$ = $( el );
6237
+ var widgetEdit = thisView.$( '.so-live-editor-builder .so-widget-wrapper' ).eq( $$.data( 'index' ) );
6238
+ widgetEdit.data( 'live-editor-preview-widget', $$ );
6239
+
6240
+ $$
6241
+ .css( {
6242
+ 'cursor': 'pointer'
6243
+ } )
6244
+ .mouseenter( function () {
6245
+ widgetEdit.parent().addClass( 'so-hovered' );
6246
+ thisView.highlightElement( $$ );
6247
+ } )
6248
+ .mouseleave( function () {
6249
+ widgetEdit.parent().removeClass( 'so-hovered' );
6250
+ thisView.resetHighlights();
6251
+ } )
6252
+ .click( function ( e ) {
6253
+ e.preventDefault();
6254
+ // When we click a widget, send that click to the form
6255
+ widgetEdit.find( '.title h4' ).click();
6256
+ } );
6257
+ } );
6258
+
6259
+ // Prevent default clicks inside the preview iframe
6260
+ $iframeContents.find( "a" ).css( {'pointer-events': 'none'} ).click( function ( e ) {
6261
+ e.preventDefault();
6262
+ } );
6263
+
6264
+ } )
6265
+ .on( 'load', function(){
6266
+ var $$ = $( this );
6267
+ if( ! $$.data( 'iframeready' ) ) {
6268
+ $$.trigger('iframeready');
6269
+ }
6270
+ } );
6271
+ },
6272
+
6273
+ /**
6274
+ * Return true if the live editor has a valid preview URL.
6275
+ * @return {boolean}
6276
+ */
6277
+ hasPreviewUrl: function () {
6278
+ return this.$( 'form.live-editor-form' ).attr( 'action' ) !== '';
6279
+ },
6280
+
6281
+ /**
6282
+ * Toggle the size of the preview iframe to simulate mobile devices.
6283
+ * @param e
6284
+ */
6285
+ mobileToggle: function( e ){
6286
+ var button = $( e.currentTarget );
6287
+ this.$('.live-editor-mode' ).not( button ).removeClass('so-active');
6288
+ button.addClass( 'so-active' );
6289
+
6290
+ this.$el
6291
+ .removeClass( 'live-editor-desktop-mode live-editor-tablet-mode live-editor-mobile-mode' )
6292
+ .addClass( 'live-editor-' + button.data( 'mode' ) + '-mode' );
6293
+
6294
+ }
6295
+ } );
6296
+
6297
+ },{}],27:[function(require,module,exports){
6298
+ var panels = window.panels, $ = jQuery;
6299
+
6300
+ module.exports = Backbone.View.extend( {
6301
+ template: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-builder-row' ).html() ) ),
6302
+
6303
+ events: {
6304
+ 'click .so-row-settings': 'editSettingsHandler',
6305
+ 'click .so-row-duplicate': 'duplicateHandler',
6306
+ 'click .so-row-delete': 'confirmedDeleteHandler',
6307
+ 'click .so-row-color': 'rowColorChangeHandler',
6308
+ },
6309
+
6310
+ builder: null,
6311
+ dialog: null,
6312
+
6313
+ /**
6314
+ * Initialize the row view
6315
+ */
6316
+ initialize: function () {
6317
+
6318
+ var rowCells = this.model.get('cells');
6319
+ this.listenTo(rowCells, 'add', this.handleCellAdd );
6320
+ this.listenTo(rowCells, 'remove', this.handleCellRemove );
6321
+
6322
+ this.listenTo( this.model, 'reweight_cells', this.resize );
6323
+ this.listenTo( this.model, 'destroy', this.onModelDestroy );
6324
+
6325
+ var thisView = this;
6326
+ rowCells.each( function ( cell ) {
6327
+ thisView.listenTo( cell.get('widgets'), 'add', thisView.resize );
6328
+ } );
6329
+
6330
+ // When ever a new cell is added, listen to it for new widgets
6331
+ rowCells.on( 'add', function ( cell ) {
6332
+ thisView.listenTo( cell.get('widgets'), 'add', thisView.resize );
6333
+ }, this );
6334
+
6335
+ this.listenTo( this.model, 'change:label', this.onLabelChange );
6336
+ },
6337
+
6338
+ /**
6339
+ * Render the row.
6340
+ *
6341
+ * @returns {panels.view.row}
6342
+ */
6343
+ render: function () {
6344
+ var rowColorLabel = this.model.has( 'color_label' ) ? this.model.get( 'color_label' ) : 1;
6345
+ var rowLabel = this.model.has( 'label' ) ? this.model.get( 'label' ) : '';
6346
+ this.setElement( this.template( { rowColorLabel: rowColorLabel, rowLabel: rowLabel } ) );
6347
+ this.$el.data( 'view', this );
6348
+
6349
+ // Create views for the cells in this row
6350
+ var thisView = this;
6351
+ this.model.get('cells').each( function ( cell ) {
6352
+ var cellView = new panels.view.cell( {
6353
+ model: cell
6354
+ } );
6355
+ cellView.row = thisView;
6356
+ cellView.render();
6357
+ cellView.$el.appendTo( thisView.$( '.so-cells' ) );
6358
+ } );
6359
+
6360
+ // Remove any unsupported actions
6361
+ if( ! this.builder.supports( 'rowAction' ) ) {
6362
+ this.$('.so-row-toolbar .so-dropdown-wrapper' ).remove();
6363
+ this.$el.addClass('so-row-no-actions');
6364
+ }
6365
+ else {
6366
+ if( ! this.builder.supports( 'editRow' ) ) {
6367
+ this.$('.so-row-toolbar .so-dropdown-links-wrapper .so-row-settings' ).parent().remove();
6368
+ this.$el.addClass('so-row-no-edit');
6369
+ }
6370
+ if( ! this.builder.supports( 'addRow' ) ) {
6371
+ this.$('.so-row-toolbar .so-dropdown-links-wrapper .so-row-duplicate' ).parent().remove();
6372
+ this.$el.addClass('so-row-no-duplicate');
6373
+ }
6374
+ if( ! this.builder.supports( 'deleteRow' ) ) {
6375
+ this.$('.so-row-toolbar .so-dropdown-links-wrapper .so-row-delete' ).parent().remove();
6376
+ this.$el.addClass('so-row-no-delete');
6377
+ }
6378
+ }
6379
+ if( ! this.builder.supports( 'moveRow' ) ) {
6380
+ this.$('.so-row-toolbar .so-row-move' ).remove();
6381
+ this.$el.addClass('so-row-no-move');
6382
+ }
6383
+ if( !$.trim( this.$('.so-row-toolbar').html() ).length ) {
6384
+ this.$('.so-row-toolbar' ).remove();
6385
+ }
6386
+
6387
+ // Resize the rows when ever the widget sortable moves
6388
+ this.listenTo( this.builder, 'widget_sortable_move', this.resize );
6389
+ this.listenTo( this.builder, 'builder_resize', this.resize );
6390
+
6391
+ this.resize();
6392
+
6393
+ return this;
6394
+ },
6395
+
6396
+ /**
6397
+ * Give a visual indication of the creation of this row
6398
+ */
6399
+ visualCreate: function () {
6400
+ this.$el.hide().fadeIn( 'fast' );
6401
+ },
6402
+
6403
+ /**
6404
+ * Visually resize the row so that all cell heights are the same and the widths so that they balance to 100%
6405
+ *
6406
+ * @param e
6407
+ */
6408
+ resize: function ( e ) {
6409
+ // Don't resize this
6410
+ if ( ! this.$el.is( ':visible' ) ) {
6411
+ return;
6412
+ }
6413
+
6414
+ // Reset everything to have an automatic height
6415
+ this.$( '.so-cells .cell-wrapper' ).css( 'min-height', 0 );
6416
+ this.$( '.so-cells .resize-handle' ).css( 'height', 0 );
6417
+
6418
+ // We'll tie the values to the row view, to prevent issue with values going to different rows
6419
+ var height = 0;
6420
+ this.$( '.so-cells .cell' ).each( function () {
6421
+ height = Math.max(
6422
+ height,
6423
+ $( this ).height()
6424
+ );
6425
+
6426
+ $( this ).css(
6427
+ 'width',
6428
+ ( $( this ).data( 'view' ).model.get( 'weight' ) * 100) + "%"
6429
+ );
6430
+ } );
6431
+
6432
+ // Resize all the grids and cell wrappers
6433
+ this.$( '.so-cells .cell-wrapper' ).css( 'min-height', Math.max( height, 63 ) );
6434
+ this.$( '.so-cells .resize-handle' ).css( 'height', this.$( '.so-cells .cell-wrapper' ).outerHeight() );
6435
+ },
6436
+
6437
+ /**
6438
+ * Remove the view from the dom.
6439
+ */
6440
+ onModelDestroy: function () {
6441
+ this.remove();
6442
+ },
6443
+
6444
+ /**
6445
+ * Fade out the view and destroy the model
6446
+ */
6447
+ visualDestroyModel: function () {
6448
+ this.builder.addHistoryEntry( 'row_deleted' );
6449
+ var thisView = this;
6450
+ this.$el.fadeOut( 'normal', function () {
6451
+ thisView.model.destroy();
6452
+ thisView.builder.model.refreshPanelsData();
6453
+ } );
6454
+ },
6455
+
6456
+ onLabelChange: function( model, text ) {
6457
+ if ( this.$('.so-row-label').length == 0 ) {
6458
+ this.$( '.so-row-toolbar' ).prepend( '<h3 class="so-row-label">' + text + '</h3>' );
6459
+ } else {
6460
+ this.$('.so-row-label').text( text );
6461
+ }
6462
+ },
6463
+
6464
+ /**
6465
+ * Duplicate this row.
6466
+ *
6467
+ * @return {boolean}
6468
+ */
6469
+ duplicateHandler: function () {
6470
+ this.builder.addHistoryEntry( 'row_duplicated' );
6471
+
6472
+ var duplicateRow = this.model.clone( this.builder.model );
6473
+
6474
+ this.builder.model.get('rows').add( duplicateRow, {
6475
+ at: this.builder.model.get('rows').indexOf( this.model ) + 1
6476
+ } );
6477
+
6478
+ this.builder.model.refreshPanelsData();
6479
+ },
6480
+
6481
+ /**
6482
+ * Copy the row to a localStorage
6483
+ */
6484
+ copyHandler: function(){
6485
+ panels.helpers.clipboard.setModel( this.model );
6486
+ },
6487
+
6488
+ /**
6489
+ * Create a new row and insert it
6490
+ */
6491
+ pasteHandler: function(){
6492
+ var pastedModel = panels.helpers.clipboard.getModel( 'row-model' );
6493
+
6494
+ if( ! _.isEmpty( pastedModel ) && pastedModel instanceof panels.model.row ) {
6495
+ this.builder.addHistoryEntry( 'row_pasted' );
6496
+ pastedModel.builder = this.builder.model;
6497
+ this.builder.model.get('rows').add( pastedModel, {
6498
+ at: this.builder.model.get('rows').indexOf( this.model ) + 1
6499
+ } );
6500
+ this.builder.model.refreshPanelsData();
6501
+ }
6502
+ },
6503
+
6504
+ /**
6505
+ * Handles deleting the row with a confirmation.
6506
+ */
6507
+ confirmedDeleteHandler: function ( e ) {
6508
+ var $$ = $( e.target );
6509
+
6510
+ // The user clicked on the dashicon
6511
+ if ( $$.hasClass( 'dashicons' ) ) {
6512
+ $$ = $$.parent();
6513
+ }
6514
+
6515
+ if ( $$.hasClass( 'so-confirmed' ) ) {
6516
+ this.visualDestroyModel();
6517
+ } else {
6518
+ var originalText = $$.html();
6519
+
6520
+ $$.addClass( 'so-confirmed' ).html(
6521
+ '<span class="dashicons dashicons-yes"></span>' + panelsOptions.loc.dropdown_confirm
6522
+ );
6523
+
6524
+ setTimeout( function () {
6525
+ $$.removeClass( 'so-confirmed' ).html( originalText );
6526
+ }, 2500 );
6527
+ }
6528
+ },
6529
+
6530
+ /**
6531
+ * Handle displaying the settings dialog
6532
+ */
6533
+ editSettingsHandler: function () {
6534
+ if ( ! this.builder.supports( 'editRow' ) ) {
6535
+ return;
6536
+ }
6537
+ // Lets open up an instance of the settings dialog
6538
+ if ( this.dialog === null ) {
6539
+ // Create the dialog
6540
+ this.dialog = new panels.dialog.row();
6541
+ this.dialog.setBuilder( this.builder ).setRowModel( this.model );
6542
+ this.dialog.rowView = this;
6543
+ }
6544
+
6545
+ this.dialog.openDialog();
6546
+
6547
+ return this;
6548
+ },
6549
+
6550
+ /**
6551
+ * Handle deleting this entire row.
6552
+ */
6553
+ deleteHandler: function () {
6554
+ this.model.destroy();
6555
+ return this;
6556
+ },
6557
+
6558
+ /**
6559
+ * Change the row background color.
6560
+ */
6561
+ rowColorChangeHandler: function ( event ) {
6562
+ this.$( '.so-row-color' ).removeClass( 'so-row-color-selected' );
6563
+ var clickedColorElem = $( event.target );
6564
+ var newColorLabel = clickedColorElem.data( 'color-label' );
6565
+ var oldColorLabel = this.model.has( 'color_label' ) ? this.model.get( 'color_label' ) : 1;
6566
+ clickedColorElem.addClass( 'so-row-color-selected' );
6567
+ this.$el.removeClass( 'so-row-color-' + oldColorLabel );
6568
+ this.$el.addClass( 'so-row-color-' + newColorLabel );
6569
+ this.model.set( 'color_label', newColorLabel );
6570
+ },
6571
+
6572
+ /**
6573
+ * Handle a new cell being added to this row view. For now we'll assume the new cell is always last
6574
+ */
6575
+ handleCellAdd: function ( cell ) {
6576
+ var cellView = new panels.view.cell( {
6577
+ model: cell
6578
+ } );
6579
+ cellView.row = this;
6580
+ cellView.render();
6581
+ cellView.$el.appendTo( this.$( '.so-cells' ) );
6582
+ },
6583
+
6584
+ /**
6585
+ * Handle a cell being removed from this row view
6586
+ */
6587
+ handleCellRemove: function ( cell ) {
6588
+ // Find the view that ties in to the cell we're removing
6589
+ this.$( '.so-cells > .cell' ).each( function () {
6590
+ var view = $( this ).data( 'view' );
6591
+ if ( _.isUndefined( view ) ) {
6592
+ return;
6593
+ }
6594
+
6595
+ if ( view.model.cid === cell.cid ) {
6596
+ // Remove this view
6597
+ view.remove();
6598
+ }
6599
+ } );
6600
+ },
6601
+
6602
+ /**
6603
+ * Build up the contextual menu for a row
6604
+ *
6605
+ * @param e
6606
+ * @param menu
6607
+ */
6608
+ buildContextualMenu: function ( e, menu ) {
6609
+ var options = [];
6610
+ for ( var i = 1; i < 5; i ++ ) {
6611
+ options.push( {
6612
+ title: i + ' ' + panelsOptions.loc.contextual.column
6613
+ } );
6614
+ }
6615
+
6616
+ if( this.builder.supports( 'addRow' ) ) {
6617
+ menu.addSection(
6618
+ 'add-row',
6619
+ {
6620
+ sectionTitle: panelsOptions.loc.contextual.add_row,
6621
+ search: false
6622
+ },
6623
+ options,
6624
+ function ( c ) {
6625
+ this.builder.addHistoryEntry( 'row_added' );
6626
+
6627
+ var columns = Number( c ) + 1;
6628
+ var weights = [];
6629
+ for ( var i = 0; i < columns; i ++ ) {
6630
+ weights.push( {weight: 100 / columns } );
6631
+ }
6632
+
6633
+ // Create the actual row
6634
+ var newRow = new panels.model.row( {
6635
+ collection: this.collection
6636
+ } );
6637
+
6638
+ var cells = new panels.collection.cells(weights);
6639
+ cells.each(function (cell) {
6640
+ cell.row = newRow;
6641
+ });
6642
+ newRow.setCells(cells);
6643
+ newRow.builder = this.builder.model;
6644
+
6645
+ this.builder.model.get('rows').add( newRow, {
6646
+ at: this.builder.model.get('rows').indexOf( this.model ) + 1
6647
+ } );
6648
+
6649
+ this.builder.model.refreshPanelsData();
6650
+ }.bind( this )
6651
+ );
6652
+ }
6653
+
6654
+ var actions = {};
6655
+
6656
+ if( this.builder.supports( 'editRow' ) ) {
6657
+ actions.edit = { title: panelsOptions.loc.contextual.row_edit };
6658
+ }
6659
+
6660
+ // Copy and paste functions
6661
+ if ( panels.helpers.clipboard.canCopyPaste() ) {
6662
+ actions.copy = { title: panelsOptions.loc.contextual.row_copy };
6663
+ if ( this.builder.supports( 'addRow' ) && panels.helpers.clipboard.isModel( 'row-model' ) ) {
6664
+ actions.paste = { title: panelsOptions.loc.contextual.row_paste };
6665
+ }
6666
+ }
6667
+
6668
+ if( this.builder.supports( 'addRow' ) ) {
6669
+ actions.duplicate = { title: panelsOptions.loc.contextual.row_duplicate };
6670
+ }
6671
+
6672
+ if( this.builder.supports( 'deleteRow' ) ) {
6673
+ actions.delete = { title: panelsOptions.loc.contextual.row_delete, confirm: true };
6674
+ }
6675
+
6676
+ if( ! _.isEmpty( actions ) ) {
6677
+ menu.addSection(
6678
+ 'row-actions',
6679
+ {
6680
+ sectionTitle: panelsOptions.loc.contextual.row_actions,
6681
+ search: false,
6682
+ },
6683
+ actions,
6684
+ function ( c ) {
6685
+ switch ( c ) {
6686
+ case 'edit':
6687
+ this.editSettingsHandler();
6688
+ break;
6689
+ case 'copy':
6690
+ this.copyHandler();
6691
+ break;
6692
+ case 'paste':
6693
+ this.pasteHandler();
6694
+ break;
6695
+ case 'duplicate':
6696
+ this.duplicateHandler();
6697
+ break;
6698
+ case 'delete':
6699
+ this.visualDestroyModel();
6700
+ break;
6701
+ }
6702
+ }.bind( this )
6703
+ );
6704
+ }
6705
+ },
6706
+ } );
6707
+
6708
+ },{}],28:[function(require,module,exports){
6709
+ var panels = window.panels, $ = jQuery;
6710
+
6711
+ module.exports = Backbone.View.extend( {
6712
+
6713
+ stylesLoaded: false,
6714
+
6715
+ initialize: function () {
6716
+
6717
+ },
6718
+
6719
+ /**
6720
+ * Render the visual styles object.
6721
+ *
6722
+ * @param stylesType
6723
+ * @param postId
6724
+ * @param args
6725
+ */
6726
+ render: function ( stylesType, postId, args ) {
6727
+ if ( _.isUndefined( stylesType ) ) {
6728
+ return;
6729
+ }
6730
+
6731
+ // Add in the default args
6732
+ args = _.extend( {
6733
+ builderType: '',
6734
+ dialog: null
6735
+ }, args );
6736
+
6737
+ this.$el.addClass( 'so-visual-styles so-' + stylesType + '-styles so-panels-loading' );
6738
+
6739
+ var postArgs = {
6740
+ builderType: args.builderType
6741
+ };
6742
+
6743
+ if ( stylesType === 'cell') {
6744
+ postArgs.index = args.index;
6745
+ }
6746
+
6747
+ // Load the form
6748
+ $.post(
6749
+ panelsOptions.ajaxurl,
6750
+ {
6751
+ action: 'so_panels_style_form',
6752
+ type: stylesType,
6753
+ style: this.model.get( 'style' ),
6754
+ args: JSON.stringify( postArgs ),
6755
+ postId: postId
6756
+ },
6757
+ null,
6758
+ 'html'
6759
+ ).done( function ( response ) {
6760
+ this.$el.html( response );
6761
+ this.setupFields();
6762
+ this.stylesLoaded = true;
6763
+ this.trigger( 'styles_loaded', !_.isEmpty( response ) );
6764
+ if ( !_.isNull( args.dialog ) ) {
6765
+ args.dialog.trigger( 'styles_loaded', !_.isEmpty( response ) );
6766
+ }
6767
+ }.bind( this ) )
6768
+ .fail( function ( error ) {
6769
+ var html;
6770
+ if ( error && error.responseText ) {
6771
+ html = error.responseText;
6772
+ } else {
6773
+ html = panelsOptions.forms.loadingFailed;
6774
+ }
6775
+
6776
+ this.$el.html( html );
6777
+ }.bind( this ) )
6778
+ .always( function () {
6779
+ this.$el.removeClass( 'so-panels-loading' );
6780
+ }.bind( this ) );
6781
+
6782
+ return this;
6783
+ },
6784
+
6785
+ /**
6786
+ * Attach the style view to the DOM.
6787
+ *
6788
+ * @param wrapper
6789
+ */
6790
+ attach: function ( wrapper ) {
6791
+ wrapper.append( this.$el );
6792
+ },
6793
+
6794
+ /**
6795
+ * Detach the styles view from the DOM
6796
+ */
6797
+ detach: function () {
6798
+ this.$el.detach();
6799
+ },
6800
+
6801
+ /**
6802
+ * Setup all the fields
6803
+ */
6804
+ setupFields: function () {
6805
+
6806
+ // Set up the sections as collapsible
6807
+ this.$( '.style-section-wrapper' ).each( function () {
6808
+ var $s = $( this );
6809
+
6810
+ $s.find( '.style-section-head' ).click( function ( e ) {
6811
+ e.preventDefault();
6812
+ $s.find( '.style-section-fields' ).slideToggle( 'fast' );
6813
+ } );
6814
+ } );
6815
+
6816
+ // Set up the color fields
6817
+ if ( ! _.isUndefined( $.fn.wpColorPicker ) ) {
6818
+ if ( _.isObject( panelsOptions.wpColorPickerOptions.palettes ) && ! $.isArray( panelsOptions.wpColorPickerOptions.palettes ) ) {
6819
+ panelsOptions.wpColorPickerOptions.palettes = $.map( panelsOptions.wpColorPickerOptions.palettes, function ( el ) {
6820
+ return el;
6821
+ } );
6822
+ }
6823
+ this.$( '.so-wp-color-field' ).wpColorPicker( panelsOptions.wpColorPickerOptions );
6824
+ }
6825
+
6826
+ // Set up the image select fields
6827
+ this.$( '.style-field-image' ).each( function () {
6828
+ var frame = null;
6829
+ var $s = $( this );
6830
+
6831
+ $s.find( '.so-image-selector' ).click( function ( e ) {
6832
+ e.preventDefault();
6833
+
6834
+ if ( frame === null ) {
6835
+ // Create the media frame.
6836
+ frame = wp.media( {
6837
+ // Set the title of the modal.
6838
+ title: 'choose',
6839
+
6840
+ // Tell the modal to show only images.
6841
+ library: {
6842
+ type: 'image'
6843
+ },
6844
+
6845
+ // Customize the submit button.
6846
+ button: {
6847
+ // Set the text of the button.
6848
+ text: 'Done',
6849
+ close: true
6850
+ }
6851
+ } );
6852
+
6853
+ frame.on( 'select', function () {
6854
+ var attachment = frame.state().get( 'selection' ).first().attributes;
6855
+
6856
+ var url = attachment.url;
6857
+ if ( ! _.isUndefined( attachment.sizes ) ) {
6858
+ try {
6859
+ url = attachment.sizes.thumbnail.url;
6860
+ }
6861
+ catch ( e ) {
6862
+ // We'll use the full image instead
6863
+ url = attachment.sizes.full.url;
6864
+ }
6865
+ }
6866
+ $s.find( '.current-image' ).css( 'background-image', 'url(' + url + ')' );
6867
+
6868
+ // Store the ID
6869
+ $s.find( '.so-image-selector > input' ).val( attachment.id );
6870
+
6871
+ $s.find( '.remove-image' ).removeClass( 'hidden' );
6872
+ } );
6873
+ }
6874
+
6875
+ frame.open();
6876
+
6877
+ } );
6878
+
6879
+ // Handle clicking on remove
6880
+ $s.find( '.remove-image' ).click( function ( e ) {
6881
+ e.preventDefault();
6882
+ $s.find( '.current-image' ).css( 'background-image', 'none' );
6883
+ $s.find( '.so-image-selector > input' ).val( '' );
6884
+ $s.find( '.remove-image' ).addClass( 'hidden' );
6885
+ } );
6886
+ } );
6887
+
6888
+ // Set up all the measurement fields
6889
+ this.$( '.style-field-measurement' ).each( function () {
6890
+ var $$ = $( this );
6891
+
6892
+ var text = $$.find( 'input[type="text"]' );
6893
+ var unit = $$.find( 'select' );
6894
+ var hidden = $$.find( 'input[type="hidden"]' );
6895
+
6896
+ text.focus( function(){
6897
+ $(this).select();
6898
+ } );
6899
+
6900
+ /**
6901
+ * Load value into the visible input fields.
6902
+ * @param value
6903
+ */
6904
+ var loadValue = function( value ) {
6905
+ if( value === '' ) {
6906
+ return;
6907
+ }
6908
+
6909
+ var re = /(?:([0-9\.,\-]+)(.*))+/;
6910
+ var valueList = hidden.val().split( ' ' );
6911
+ var valueListValue = [];
6912
+ for ( var i in valueList ) {
6913
+ var match = re.exec( valueList[i] );
6914
+ if ( ! _.isNull( match ) && ! _.isUndefined( match[1] ) && ! _.isUndefined( match[2] ) ) {
6915
+ valueListValue.push( match[1] );
6916
+ unit.val( match[2] );
6917
+ }
6918
+ }
6919
+
6920
+ if( text.length === 1 ) {
6921
+ // This is a single input text field
6922
+ text.val( valueListValue.join( ' ' ) );
6923
+ }
6924
+ else {
6925
+ // We're dealing with a multiple field
6926
+ if( valueListValue.length === 1 ) {
6927
+ valueListValue = [ valueListValue[0], valueListValue[0], valueListValue[0], valueListValue[0] ];
6928
+ }
6929
+ else if( valueListValue.length === 2 ) {
6930
+ valueListValue = [ valueListValue[0], valueListValue[1], valueListValue[0], valueListValue[1] ];
6931
+ }
6932
+ else if( valueListValue.length === 3 ) {
6933
+ valueListValue = [ valueListValue[0], valueListValue[1], valueListValue[2], valueListValue[1] ];
6934
+ }
6935
+
6936
+ // Store this in the visible fields
6937
+ text.each( function( i, el ) {
6938
+ $( el ).val( valueListValue[i] );
6939
+ } );
6940
+ }
6941
+ };
6942
+ loadValue( hidden.val() );
6943
+
6944
+ /**
6945
+ * Set value of the hidden field based on inputs
6946
+ */
6947
+ var setValue = function( e ){
6948
+ var i;
6949
+
6950
+ if( text.length === 1 ) {
6951
+ // We're dealing with a single measurement
6952
+ var fullString = text
6953
+ .val()
6954
+ .split( ' ' )
6955
+ .filter( function ( value ) {
6956
+ return value !== '';
6957
+ } )
6958
+ .map( function ( value ) {
6959
+ return value + unit.val();
6960
+ } )
6961
+ .join( ' ' );
6962
+ hidden.val( fullString );
6963
+ }
6964
+ else {
6965
+ var target = $( e.target ),
6966
+ valueList = [],
6967
+ emptyIndex = [],
6968
+ fullIndex = [];
6969
+
6970
+ text.each( function( i, el ) {
6971
+ var value = $( el ).val( ) !== '' ? parseFloat( $( el ).val( ) ) : null;
6972
+ valueList.push( value );
6973
+
6974
+ if( value === null ) {
6975
+ emptyIndex.push( i );
6976
+ }
6977
+ else {
6978
+ fullIndex.push( i );
6979
+ }
6980
+ } );
6981
+
6982
+ if( emptyIndex.length === 3 && fullIndex[0] === text.index( target ) ) {
6983
+ text.val( target.val() );
6984
+ valueList = [ target.val(), target.val(), target.val(), target.val() ];
6985
+ }
6986
+
6987
+ if( JSON.stringify( valueList ) === JSON.stringify( [ null, null, null, null ] ) ) {
6988
+ hidden.val('');
6989
+ }
6990
+ else {
6991
+ hidden.val( valueList.map( function( k ){
6992
+ return ( k === null ? 0 : k ) + unit.val();
6993
+ } ).join( ' ' ) );
6994
+ }
6995
+ }
6996
+ };
6997
+
6998
+ // Set the value when ever anything changes
6999
+ text.change( setValue );
7000
+ unit.change( setValue );
7001
+ } );
7002
+ }
7003
+
7004
+ } );
7005
+
7006
+ },{}],29:[function(require,module,exports){
7007
+ var panels = window.panels, $ = jQuery;
7008
+
7009
+ module.exports = Backbone.View.extend( {
7010
+ template: _.template( panels.helpers.utils.processTemplate( $( '#siteorigin-panels-builder-widget' ).html() ) ),
7011
+
7012
+ // The cell view that this widget belongs to
7013
+ cell: null,
7014
+
7015
+ // The edit dialog
7016
+ dialog: null,
7017
+
7018
+ events: {
7019
+ 'click .widget-edit': 'editHandler',
7020
+ 'click .title h4': 'editHandler',
7021
+ 'click .actions .widget-duplicate': 'duplicateHandler',
7022
+ 'click .actions .widget-delete': 'deleteHandler'
7023
+ },
7024
+
7025
+ /**
7026
+ * Initialize the widget
7027
+ */
7028
+ initialize: function () {
7029
+ this.listenTo(this.model, 'destroy', this.onModelDestroy);
7030
+ this.listenTo(this.model, 'change:values', this.onModelChange);
7031
+ this.listenTo(this.model, 'change:label', this.onLabelChange);
7032
+ },
7033
+
7034
+ /**
7035
+ * Render the widget
7036
+ */
7037
+ render: function ( options ) {
7038
+ options = _.extend( {'loadForm': false}, options );
7039
+
7040
+ this.setElement( this.template( {
7041
+ title: this.model.getWidgetField( 'title' ),
7042
+ description: this.model.getTitle(),
7043
+ widget_class: this.model.attributes.class
7044
+ } ) );
7045
+
7046
+ this.$el.data( 'view', this );
7047
+
7048
+ // Remove any unsupported actions
7049
+ if( ! this.cell.row.builder.supports( 'editWidget' ) || this.model.get( 'read_only' ) ) {
7050
+ this.$( '.actions .widget-edit' ).remove();
7051
+ this.$el.addClass('so-widget-no-edit');
7052
+ }
7053
+ if( ! this.cell.row.builder.supports( 'addWidget' ) ) {
7054
+ this.$( '.actions .widget-duplicate' ).remove();
7055
+ this.$el.addClass('so-widget-no-duplicate');
7056
+ }
7057
+ if( ! this.cell.row.builder.supports( 'deleteWidget' ) ) {
7058
+ this.$( '.actions .widget-delete' ).remove();
7059
+ this.$el.addClass('so-widget-no-delete');
7060
+ }
7061
+ if( ! this.cell.row.builder.supports( 'moveWidget' ) ) {
7062
+ this.$el.addClass('so-widget-no-move');
7063
+ }
7064
+ if( !$.trim( this.$('.actions').html() ).length ) {
7065
+ this.$( '.actions' ).remove();
7066
+ }
7067
+
7068
+ if( this.model.get( 'read_only' ) ) {
7069
+ this.$el.addClass('so-widget-read-only');
7070
+ }
7071
+
7072
+ if ( _.size( this.model.get( 'values' ) ) === 0 || options.loadForm ) {
7073
+ // If this widget doesn't have a value, create a form and save it
7074
+ var dialog = this.getEditDialog();
7075
+
7076
+ // Save the widget as soon as the form is loaded
7077
+ dialog.once( 'form_loaded', dialog.saveWidget, dialog );
7078
+
7079
+ // Setup the dialog to load the form
7080
+ dialog.setupDialog();
7081
+ }
7082
+
7083
+ // Add the global builder listeners
7084
+ this.listenTo(this.cell.row.builder, 'after_user_adds_widget', this.afterUserAddsWidgetHandler);
7085
+
7086
+ return this;
7087
+ },
7088
+
7089
+ /**
7090
+ * Display an animation that implies creation using a visual animation
7091
+ */
7092
+ visualCreate: function () {
7093
+ this.$el.hide().fadeIn( 'fast' );
7094
+ },
7095
+
7096
+ /**
7097
+ * Get the dialog view of the form that edits this widget
7098
+ *
7099
+ * @returns {null}
7100
+ */
7101
+ getEditDialog: function () {
7102
+ if ( this.dialog === null ) {
7103
+ this.dialog = new panels.dialog.widget( {
7104
+ model: this.model
7105
+ } );
7106
+ this.dialog.setBuilder( this.cell.row.builder );
7107
+
7108
+ // Store the widget view
7109
+ this.dialog.widgetView = this;
7110
+ }
7111
+ return this.dialog;
7112
+ },
7113
+
7114
+ /**
7115
+ * Handle clicking on edit widget.
7116
+ */
7117
+ editHandler: function () {
7118
+ // Create a new dialog for editing this
7119
+ if ( ! this.cell.row.builder.supports( 'editWidget' ) || this.model.get( 'read_only' ) ) {
7120
+ return this;
7121
+ }
7122
+
7123
+ this.getEditDialog().openDialog();
7124
+ return this;
7125
+ },
7126
+
7127
+ /**
7128
+ * Handle clicking on duplicate.
7129
+ *
7130
+ * @returns {boolean}
7131
+ */
7132
+ duplicateHandler: function () {
7133
+ // Add the history entry
7134
+ this.cell.row.builder.addHistoryEntry( 'widget_duplicated' );
7135
+
7136
+ // Create the new widget and connect it to the widget collection for the current row
7137
+ var newWidget = this.model.clone( this.model.cell );
7138
+
7139
+ this.cell.model.get('widgets').add( newWidget, {
7140
+ // Add this after the existing model
7141
+ at: this.model.collection.indexOf( this.model ) + 1
7142
+ } );
7143
+
7144
+ this.cell.row.builder.model.refreshPanelsData();
7145
+ return this;
7146
+ },
7147
+
7148
+ /**
7149
+ * Copy the row to a cookie based clipboard
7150
+ */
7151
+ copyHandler: function(){
7152
+ panels.helpers.clipboard.setModel( this.model );
7153
+ },
7154
+
7155
+ /**
7156
+ * Handle clicking on delete.
7157
+ *
7158
+ * @returns {boolean}
7159
+ */
7160
+ deleteHandler: function () {
7161
+ this.visualDestroyModel();
7162
+ return this;
7163
+ },
7164
+
7165
+ onModelChange: function () {
7166
+ // Update the description when ever the model changes
7167
+ this.$( '.description' ).html( this.model.getTitle() );
7168
+ },
7169
+
7170
+ onLabelChange: function( model ) {
7171
+ this.$( '.title > h4' ).text( model.getWidgetField( 'title' ) );
7172
+ },
7173
+
7174
+ /**
7175
+ * When the model is destroyed, fade it out
7176
+ */
7177
+ onModelDestroy: function () {
7178
+ this.remove();
7179
+ },
7180
+
7181
+ /**
7182
+ * Visually destroy a model
7183
+ */
7184
+ visualDestroyModel: function () {
7185
+ // Add the history entry
7186
+ this.cell.row.builder.addHistoryEntry( 'widget_deleted' );
7187
+
7188
+ this.$el.fadeOut( 'fast', function () {
7189
+ this.cell.row.resize();
7190
+ this.model.destroy();
7191
+ this.cell.row.builder.model.refreshPanelsData();
7192
+ this.remove();
7193
+ }.bind(this) );
7194
+
7195
+ return this;
7196
+ },
7197
+
7198
+ /**
7199
+ * Build up the contextual menu for a widget
7200
+ *
7201
+ * @param e
7202
+ * @param menu
7203
+ */
7204
+ buildContextualMenu: function ( e, menu ) {
7205
+ if( this.cell.row.builder.supports( 'addWidget' ) ) {
7206
+ menu.addSection(
7207
+ 'add-widget-below',
7208
+ {
7209
+ sectionTitle: panelsOptions.loc.contextual.add_widget_below,
7210
+ searchPlaceholder: panelsOptions.loc.contextual.search_widgets,
7211
+ defaultDisplay: panelsOptions.contextual.default_widgets
7212
+ },
7213
+ panelsOptions.widgets,
7214
+ function ( c ) {
7215
+ this.cell.row.builder.trigger('before_user_adds_widget');
7216
+ this.cell.row.builder.addHistoryEntry( 'widget_added' );
7217
+
7218
+ var widget = new panels.model.widget( {
7219
+ class: c
7220
+ } );
7221
+ widget.cell = this.cell.model;
7222
+
7223
+ // Insert the new widget below
7224
+ this.cell.model.get('widgets').add( widget, {
7225
+ // Add this after the existing model
7226
+ at: this.model.collection.indexOf( this.model ) + 1
7227
+ } );
7228
+
7229
+ this.cell.row.builder.model.refreshPanelsData();
7230
+
7231
+ this.cell.row.builder.trigger('after_user_adds_widget', widget);
7232
+ }.bind( this )
7233
+ );
7234
+ }
7235
+
7236
+ var actions = {};
7237
+
7238
+ if( this.cell.row.builder.supports( 'editWidget' ) && ! this.model.get( 'read_only' ) ) {
7239
+ actions.edit = { title: panelsOptions.loc.contextual.widget_edit };
7240
+ }
7241
+
7242
+ // Copy and paste functions
7243
+ if ( panels.helpers.clipboard.canCopyPaste() ) {
7244
+ actions.copy = {title: panelsOptions.loc.contextual.widget_copy};
7245
+ }
7246
+
7247
+ if( this.cell.row.builder.supports( 'addWidget' ) ) {
7248
+ actions.duplicate = { title: panelsOptions.loc.contextual.widget_duplicate };
7249
+ }
7250
+
7251
+ if( this.cell.row.builder.supports( 'deleteWidget' ) ) {
7252
+ actions.delete = { title: panelsOptions.loc.contextual.widget_delete, confirm: true };
7253
+ }
7254
+
7255
+ if( ! _.isEmpty( actions ) ) {
7256
+ menu.addSection(
7257
+ 'widget-actions',
7258
+ {
7259
+ sectionTitle: panelsOptions.loc.contextual.widget_actions,
7260
+ search: false,
7261
+ },
7262
+ actions,
7263
+ function ( c ) {
7264
+ switch ( c ) {
7265
+ case 'edit':
7266
+ this.editHandler();
7267
+ break;
7268
+ case 'copy':
7269
+ this.copyHandler();
7270
+ break;
7271
+ case 'duplicate':
7272
+ this.duplicateHandler();
7273
+ break;
7274
+ case 'delete':
7275
+ this.visualDestroyModel();
7276
+ break;
7277
+ }
7278
+ }.bind( this )
7279
+ );
7280
+ }
7281
+
7282
+ // Lets also add the contextual menu for the entire row
7283
+ this.cell.buildContextualMenu( e, menu );
7284
+ },
7285
+
7286
+ /**
7287
+ * Handler for any action after the user adds a new widget.
7288
+ * @param widget
7289
+ */
7290
+ afterUserAddsWidgetHandler: function( widget ) {
7291
+ if( this.model === widget && panelsOptions.instant_open ) {
7292
+ setTimeout(this.editHandler.bind(this), 350);
7293
+ }
7294
+ }
7295
+
7296
+ } );
7297
+
7298
+ },{}],30:[function(require,module,exports){
7299
+ var $ = jQuery;
7300
+
7301
+ var customHtmlWidget = {
7302
+ addWidget: function( idBase, widgetContainer, widgetId ) {
7303
+ var component = wp.customHtmlWidgets;
7304
+
7305
+ var fieldContainer = $( '<div></div>' );
7306
+ var syncContainer = widgetContainer.find( '.widget-content:first' );
7307
+ syncContainer.before( fieldContainer );
7308
+
7309
+ var widgetControl = new component.CustomHtmlWidgetControl( {
7310
+ el: fieldContainer,
7311
+ syncContainer: syncContainer,
7312
+ } );
7313
+
7314
+ widgetControl.initializeEditor();
7315
+
7316
+ // HACK: To ensure CodeMirror resize for the gutter.
7317
+ widgetControl.editor.codemirror.refresh();
7318
+
7319
+ return widgetControl;
7320
+ }
7321
+ };
7322
+
7323
+ module.exports = customHtmlWidget;
7324
+
7325
+ },{}],31:[function(require,module,exports){
7326
+ var customHtmlWidget = require( './custom-html-widget' );
7327
+ var mediaWidget = require( './media-widget' );
7328
+ var textWidget = require( './text-widget' );
7329
+
7330
+ var jsWidget = {
7331
+ CUSTOM_HTML: 'custom_html',
7332
+ MEDIA_AUDIO: 'media_audio',
7333
+ MEDIA_GALLERY: 'media_gallery',
7334
+ MEDIA_IMAGE: 'media_image',
7335
+ MEDIA_VIDEO: 'media_video',
7336
+ TEXT: 'text',
7337
+
7338
+ addWidget: function( widgetContainer, widgetId ) {
7339
+ var idBase = widgetContainer.find( '> .id_base' ).val();
7340
+ var widget;
7341
+
7342
+ switch ( idBase ) {
7343
+ case this.CUSTOM_HTML:
7344
+ widget = customHtmlWidget;
7345
+ break;
7346
+ case this.MEDIA_AUDIO:
7347
+ case this.MEDIA_GALLERY:
7348
+ case this.MEDIA_IMAGE:
7349
+ case this.MEDIA_VIDEO:
7350
+ widget = mediaWidget;
7351
+ break;
7352
+ case this.TEXT:
7353
+ widget = textWidget;
7354
+ break
7355
+ }
7356
+
7357
+ widget.addWidget( idBase, widgetContainer, widgetId );
7358
+ },
7359
+ };
7360
+
7361
+ module.exports = jsWidget;
7362
+
7363
+ },{"./custom-html-widget":30,"./media-widget":32,"./text-widget":33}],32:[function(require,module,exports){
7364
+ var $ = jQuery;
7365
+
7366
+ var mediaWidget = {
7367
+ addWidget: function( idBase, widgetContainer, widgetId ) {
7368
+ var component = wp.mediaWidgets;
7369
+
7370
+ var ControlConstructor = component.controlConstructors[ idBase ];
7371
+ if ( ! ControlConstructor ) {
7372
+ return;
7373
+ }
7374
+
7375
+ var ModelConstructor = component.modelConstructors[ idBase ] || component.MediaWidgetModel;
7376
+ var syncContainer = widgetContainer.find( '> .widget-content' );
7377
+ var controlContainer = $( '<div class="media-widget-control"></div>' );
7378
+ syncContainer.before( controlContainer );
7379
+
7380
+ var modelAttributes = {};
7381
+ syncContainer.find( '.media-widget-instance-property' ).each( function() {
7382
+ var input = $( this );
7383
+ modelAttributes[ input.data( 'property' ) ] = input.val();
7384
+ });
7385
+ modelAttributes.widget_id = widgetId;
7386
+
7387
+ var widgetModel = new ModelConstructor( modelAttributes );
7388
+
7389
+ var widgetControl = new ControlConstructor({
7390
+ el: controlContainer,
7391
+ syncContainer: syncContainer,
7392
+ model: widgetModel,
7393
+ });
7394
+
7395
+ widgetControl.render();
7396
+
7397
+ return widgetControl;
7398
+ }
7399
+ };
7400
+
7401
+ module.exports = mediaWidget;
7402
+
7403
+ },{}],33:[function(require,module,exports){
7404
+ var $ = jQuery;
7405
+
7406
+ var textWidget = {
7407
+ addWidget: function( idBase, widgetContainer, widgetId ) {
7408
+ var component = wp.textWidgets;
7409
+
7410
+ var options = {};
7411
+ var visualField = widgetContainer.find( '.visual' );
7412
+ // 'visual' field and syncContainer were introduced together in 4.8.1
7413
+ if ( visualField.length > 0 ) {
7414
+ // If 'visual' field has no value it's a legacy text widget.
7415
+ if ( ! visualField.val() ) {
7416
+ return null;
7417
+ }
7418
+
7419
+ var fieldContainer = $( '<div></div>' );
7420
+ var syncContainer = widgetContainer.find( '.widget-content:first' );
7421
+ syncContainer.before( fieldContainer );
7422
+
7423
+ options = {
7424
+ el: fieldContainer,
7425
+ syncContainer: syncContainer,
7426
+ };
7427
+ } else {
7428
+ options = { el: widgetContainer };
7429
+ }
7430
+
7431
+ var widgetControl = new component.TextWidgetControl( options );
7432
+ var wpEditor = wp.oldEditor ? wp.oldEditor : wp.editor;
7433
+ if ( wpEditor && wpEditor.hasOwnProperty( 'autop' ) ) {
7434
+ wp.editor.autop = wpEditor.autop;
7435
+ wp.editor.removep = wpEditor.removep;
7436
+ wp.editor.initialize = wpEditor.initialize
7437
+ }
7438
+
7439
+ widgetControl.initializeEditor();
7440
+
7441
+ return widgetControl;
7442
+ }
7443
+ };
7444
+
7445
+ module.exports = textWidget;
7446
+
7447
+ },{}]},{},[16]);
js/siteorigin-panels-2104.min.js ADDED
@@ -0,0 +1 @@
 
1
+ !function o(n,a,r){function d(t,e){if(!a[t]){if(!n[t]){var i="function"==typeof require&&require;if(!e&&i)return i(t,!0);if(h)return h(t,!0);var s=new Error("Cannot find module '"+t+"'");throw s.code="MODULE_NOT_FOUND",s}var l=a[t]={exports:{}};n[t][0].call(l.exports,function(e){return d(n[t][1][e]||e)},l,l.exports,o,n,a,r)}return a[t].exports}for(var h="function"==typeof require&&require,e=0;e<r.length;e++)d(r[e]);return d}({1:[function(e,t,i){var s=window.panels;t.exports=Backbone.Collection.extend({model:s.model.cell,initialize:function(){},totalWeight:function(){var t=0;return this.each(function(e){t+=e.get("weight")}),t}})},{}],2:[function(e,t,i){var s=window.panels;t.exports=Backbone.Collection.extend({model:s.model.historyEntry,builder:null,maxSize:12,initialize:function(){this.on("add",this.onAddEntry,this)},addEntry:function(e,t){_.isEmpty(t)&&(t=this.builder.getPanelsData());var i=new s.model.historyEntry({text:e,data:JSON.stringify(t),time:parseInt((new Date).getTime()/1e3),collection:this});this.add(i)},onAddEntry:function(e){if(1<this.models.length){var t=this.at(this.models.length-2);(e.get("text")===t.get("text")&&e.get("time")-t.get("time")<15||e.get("data")===t.get("data"))&&(this.remove(e),t.set("count",t.get("count")+1))}for(;this.models.length>this.maxSize;)this.shift()}})},{}],3:[function(e,t,i){var s=window.panels;t.exports=Backbone.Collection.extend({model:s.model.row,empty:function(){for(var e;;){if(!(e=this.collection.first()))break;e.destroy()}}})},{}],4:[function(e,t,i){var s=window.panels;t.exports=Backbone.Collection.extend({model:s.model.widget,initialize:function(){}})},{}],5:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=s.view.dialog.extend({dialogClass:"so-panels-dialog-add-builder",render:function(){this.renderDialog(this.parseDialogContent(l("#siteorigin-panels-dialog-builder").html(),{})),this.$(".so-content .siteorigin-panels-builder").append(this.builder.$el)},initializeDialog:function(){var e=this;this.once("open_dialog_complete",function(){e.builder.initSortable()}),this.on("open_dialog_complete",function(){e.builder.trigger("builder_resize")})}})},{}],6:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=s.view.dialog.extend({historyEntryTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-dialog-history-entry").html())),entries:{},currentEntry:null,revertEntry:null,selectedEntry:null,previewScrollTop:null,dialogClass:"so-panels-dialog-history",dialogIcon:"history",events:{"click .so-close":"closeDialog","click .so-restore":"restoreSelectedEntry"},initializeDialog:function(){this.entries=new s.collection.historyEntries,this.on("open_dialog",this.setCurrentEntry,this),this.on("open_dialog",this.renderHistoryEntries,this)},render:function(){var t=this;this.renderDialog(this.parseDialogContent(l("#siteorigin-panels-dialog-history").html(),{})),this.$("iframe.siteorigin-panels-history-iframe").load(function(){var e=l(this);e.show(),e.contents().scrollTop(t.previewScrollTop)})},setRevertEntry:function(e){this.revertEntry=new s.model.historyEntry({data:JSON.stringify(e.getPanelsData()),time:parseInt((new Date).getTime()/1e3)})},setCurrentEntry:function(){this.currentEntry=new s.model.historyEntry({data:JSON.stringify(this.builder.model.getPanelsData()),time:parseInt((new Date).getTime()/1e3)}),this.selectedEntry=this.currentEntry,this.previewEntry(this.currentEntry),this.$(".so-buttons .so-restore").addClass("disabled")},renderHistoryEntries:function(){var i=this,s=this.$(".history-entries").empty();this.currentEntry.get("data")===this.revertEntry.get("data")&&_.isEmpty(this.entries.models)||l(this.historyEntryTemplate({title:panelsOptions.loc.history.revert,count:1})).data("historyEntry",this.revertEntry).prependTo(s),this.entries.each(function(e){var t=i.historyEntryTemplate({title:panelsOptions.loc.history[e.get("text")],count:e.get("count")});l(t).data("historyEntry",e).prependTo(s)}),l(this.historyEntryTemplate({title:panelsOptions.loc.history.current,count:1})).data("historyEntry",this.currentEntry).addClass("so-selected").prependTo(s),s.find(".history-entry").click(function(){var e=jQuery(this);s.find(".history-entry").not(e).removeClass("so-selected"),e.addClass("so-selected");var t=e.data("historyEntry");i.selectedEntry=t,i.selectedEntry.cid!==i.currentEntry.cid?i.$(".so-buttons .so-restore").removeClass("disabled"):i.$(".so-buttons .so-restore").addClass("disabled"),i.previewEntry(t)}),this.updateEntryTimes()},previewEntry:function(e){var t=this.$("iframe.siteorigin-panels-history-iframe");t.hide(),this.previewScrollTop=t.contents().scrollTop(),this.$('form.history-form input[name="live_editor_panels_data"]').val(e.get("data")),this.$('form.history-form input[name="live_editor_post_ID"]').val(this.builder.config.postId),this.$("form.history-form").submit()},restoreSelectedEntry:function(){return this.$(".so-buttons .so-restore").hasClass("disabled")||(this.currentEntry.get("data")===this.selectedEntry.get("data")||("restore"!==this.selectedEntry.get("text")&&this.builder.addHistoryEntry("restore",this.builder.model.getPanelsData()),this.builder.model.loadPanelsData(JSON.parse(this.selectedEntry.get("data")))),this.closeDialog()),!1},updateEntryTimes:function(){var s=this;this.$(".history-entries .history-entry").each(function(){var e=jQuery(this),t=e.find(".timesince"),i=e.data("historyEntry");t.html(s.timeSince(i.get("time")))})},timeSince:function(e){var t,i=parseInt((new Date).getTime()/1e3)-e,s=[];return 3600<i&&(1===(t=Math.floor(i/3600))?s.push(panelsOptions.loc.time.hour.replace("%d",t)):s.push(panelsOptions.loc.time.hours.replace("%d",t)),i-=3600*t),60<i&&(1===(t=Math.floor(i/60))?s.push(panelsOptions.loc.time.minute.replace("%d",t)):s.push(panelsOptions.loc.time.minutes.replace("%d",t)),i-=60*t),0<i&&(1===i?s.push(panelsOptions.loc.time.second.replace("%d",i)):s.push(panelsOptions.loc.time.seconds.replace("%d",i))),_.isEmpty(s)?panelsOptions.loc.time.now:panelsOptions.loc.time.ago.replace("%s",s.slice(0,2).join(", "))}})},{}],7:[function(e,t,i){var s=window.panels,r=jQuery;t.exports=s.view.dialog.extend({directoryTemplate:_.template(s.helpers.utils.processTemplate(r("#siteorigin-panels-directory-items").html())),builder:null,dialogClass:"so-panels-dialog-prebuilt-layouts",dialogIcon:"layouts",layoutCache:{},currentTab:!1,directoryPage:1,events:{"click .so-close":"closeDialog","click .so-sidebar-tabs li a":"tabClickHandler","click .so-content .layout":"layoutClickHandler","keyup .so-sidebar-search":"searchHandler","click .so-screenshot, .so-title":"directoryItemClickHandler"},initializeDialog:function(){var e=this;this.on("open_dialog",function(){e.$(".so-sidebar-tabs li a").first().click(),e.$(".so-status").removeClass("so-panels-loading")}),this.on("button_click",this.toolbarButtonClick,this)},render:function(){this.renderDialog(this.parseDialogContent(r("#siteorigin-panels-dialog-prebuilt").html(),{})),this.initToolbar()},tabClickHandler:function(e){e.preventDefault(),this.selectedLayoutItem=null,this.uploadedLayout=null,this.updateButtonState(!1),this.$(".so-sidebar-tabs li").removeClass("tab-active");var t=r(e.target),i=t.attr("href").split("#")[1];t.parent().addClass("tab-active");this.$(".so-content").empty(),"import"==(this.currentTab=i)?this.displayImportExport():this.displayLayoutDirectory("",1,i),this.$(".so-sidebar-search").val("")},displayImportExport:function(){var e=this.$(".so-content").empty().removeClass("so-panels-loading");e.html(r("#siteorigin-panels-dialog-prebuilt-importexport").html());var l=this,o=l.$(".import-upload-ui"),t=new plupload.Uploader({runtimes:"html5,silverlight,flash,html4",browse_button:o.find(".file-browse-button").get(0),container:o.get(0),drop_element:o.find(".drag-upload-area").get(0),file_data_name:"panels_import_data",multiple_queues:!1,max_file_size:panelsOptions.plupload.max_file_size,url:panelsOptions.plupload.url,flash_swf_url:panelsOptions.plupload.flash_swf_url,silverlight_xap_url:panelsOptions.plupload.silverlight_xap_url,filters:[{title:panelsOptions.plupload.filter_title,extensions:"json"}],multipart_params:{action:"so_panels_import_layout"},init:{PostInit:function(e){e.features.dragdrop&&o.addClass("has-drag-drop"),o.find(".progress-precent").css("width","0%")},FilesAdded:function(e){o.find(".file-browse-button").blur(),o.find(".drag-upload-area").removeClass("file-dragover"),o.find(".progress-bar").fadeIn("fast"),l.$(".js-so-selected-file").text(panelsOptions.loc.prebuilt_loading),e.start()},UploadProgress:function(e,t){o.find(".progress-precent").css("width",t.percent+"%")},FileUploaded:function(e,t,i){var s=JSON.parse(i.response);_.isUndefined(s.widgets)?alert(panelsOptions.plupload.error_message):(l.uploadedLayout=s,o.find(".progress-bar").hide(),l.$(".js-so-selected-file").text(panelsOptions.loc.ready_to_insert.replace("%s",t.name)),l.updateButtonState(!0))},Error:function(){alert(panelsOptions.plupload.error_message)}}});t.init(),/Edge\/\d./i.test(navigator.userAgent)&&setTimeout(function(){t.refresh()},250),o.find(".drag-upload-area").on("dragover",function(){r(this).addClass("file-dragover")}).on("dragleave",function(){r(this).removeClass("file-dragover")}),e.find(".so-export").submit(function(e){var t=r(this),i=l.builder.model.getPanelsData(),s=r('input[name="post_title"]').val();s||(s=r('input[name="post_ID"]').val()),i.name=s,t.find('input[name="panels_export_data"]').val(JSON.stringify(i))})},displayLayoutDirectory:function(s,l,o){var n=this,a=this.$(".so-content").empty().addClass("so-panels-loading");if(void 0===s&&(s=""),void 0===l&&(l=1),void 0===o&&(o="directory-siteorigin"),o.match("^directory-")&&!panelsOptions.directory_enabled)return a.removeClass("so-panels-loading").html(r("#siteorigin-panels-directory-enable").html()),void a.find(".so-panels-enable-directory").click(function(e){e.preventDefault(),r.get(panelsOptions.ajaxurl,{action:"so_panels_directory_enable"},function(){}),panelsOptions.directory_enabled=!0,a.addClass("so-panels-loading"),n.displayLayoutDirectory(s,l,o)});r.get(panelsOptions.ajaxurl,{action:"so_panels_layouts_query",search:s,page:l,type:o},function(e){if(n.currentTab===o){a.removeClass("so-panels-loading").html(n.directoryTemplate(e));var t=a.find(".so-previous"),i=a.find(".so-next");l<=1?t.addClass("button-disabled"):t.click(function(e){e.preventDefault(),n.displayLayoutDirectory(s,l-1,n.currentTab)}),l===e.max_num_pages||0===e.max_num_pages?i.addClass("button-disabled"):i.click(function(e){e.preventDefault(),n.displayLayoutDirectory(s,l+1,n.currentTab)}),a.find(".so-screenshot").each(function(){var e=r(this),t=e.find(".so-screenshot-wrapper");if(t.css("height",t.width()/4*3+"px").addClass("so-loading"),""!==e.data("src"))var i=r("<img/>").attr("src",e.data("src")).load(function(){t.removeClass("so-loading").css("height","auto"),i.appendTo(t).hide().fadeIn("fast")});else r("<img/>").attr("src",panelsOptions.prebuiltDefaultScreenshot).appendTo(t).hide().fadeIn("fast")}),a.find(".so-directory-browse").html(e.title)}},"json")},directoryItemClickHandler:function(e){var t=this.$(e.target).closest(".so-directory-item");this.$(".so-directory-items").find(".selected").removeClass("selected"),t.addClass("selected"),this.selectedLayoutItem={lid:t.data("layout-id"),type:t.data("layout-type")},this.updateButtonState(!0)},toolbarButtonClick:function(e){if(!this.canAddLayout())return!1;var t=e.data("value");if(_.isUndefined(t))return!1;if(this.updateButtonState(!1),e.hasClass("so-needs-confirm")&&!e.hasClass("so-confirmed")){if(this.updateButtonState(!0),e.hasClass("so-confirming"))return;e.addClass("so-confirming");var i=e.html();return e.html('<span class="dashicons dashicons-yes"></span>'+e.data("confirm")),setTimeout(function(){e.removeClass("so-confirmed").html(i)},2500),setTimeout(function(){e.removeClass("so-confirming"),e.addClass("so-confirmed")},200),!1}this.addingLayout=!0,"import"===this.currentTab?this.addLayoutToBuilder(this.uploadedLayout,t):this.loadSelectedLayout().then(function(e){this.addLayoutToBuilder(e,t)}.bind(this))},canAddLayout:function(){return(this.selectedLayoutItem||this.uploadedLayout)&&!this.addingLayout},loadSelectedLayout:function(){this.setStatusMessage(panelsOptions.loc.prebuilt_loading,!0);var e=_.extend(this.selectedLayoutItem,{action:"so_panels_get_layout"}),i=new r.Deferred;return r.get(panelsOptions.ajaxurl,e,function(e){var t="";e.success?i.resolve(e.data):(t=e.data.message,i.reject(e.data)),this.setStatusMessage(t,!1,!e.success),this.updateButtonState(!0)}.bind(this)),i.promise()},searchHandler:function(e){13===e.keyCode&&this.displayLayoutDirectory(r(e.currentTarget).val(),1,this.currentTab)},updateButtonState:function(e){e=e&&(this.selectedLayoutItem||this.uploadedLayout);var t=this.$(".so-import-layout");t.prop("disabled",!e),e?t.removeClass("disabled"):t.addClass("disabled")},addLayoutToBuilder:function(e,t){this.builder.addHistoryEntry("prebuilt_loaded"),this.builder.model.loadPanelsData(e,t),this.addingLayout=!1,this.closeDialog()}})},{}],8:[function(e,t,i){var a=window.panels,h=jQuery;t.exports=a.view.dialog.extend({cellPreviewTemplate:_.template(a.helpers.utils.processTemplate(h("#siteorigin-panels-dialog-row-cell-preview").html())),editableLabel:!0,events:{"click .so-close":"closeDialog","click .so-toolbar .so-save":"saveHandler","click .so-toolbar .so-insert":"insertHandler","click .so-toolbar .so-delete":"deleteHandler","click .so-toolbar .so-duplicate":"duplicateHandler","change .row-set-form > *":"setCellsFromForm","click .row-set-form button.set-row":"setCellsFromForm"},rowView:null,dialogIcon:"add-row",dialogClass:"so-panels-dialog-row-edit",styleType:"row",dialogType:"edit",row:{cells:null,style:{}},cellStylesCache:[],initializeDialog:function(){this.on("open_dialog",function(){_.isUndefined(this.model)||_.isEmpty(this.model.get("cells"))?this.setRowModel(null):this.setRowModel(this.model),this.regenerateRowPreview(),this.renderStyles()},this),this.row={cells:new a.collection.cells([{weight:.5},{weight:.5}]),style:{}},this.dialogFormsLoaded=0;var e=this;this.on("form_loaded styles_loaded",function(){this.dialogFormsLoaded++,2===this.dialogFormsLoaded&&e.updateModel({refreshArgs:{silent:!0}})}),this.on("close_dialog",this.closeHandler),this.on("edit_label",function(e){if(e!==panelsOptions.loc.row.add&&e!==panelsOptions.loc.row.edit||(e=""),this.model.set("label",e),_.isEmpty(e)){var t="create"===this.dialogType?panelsOptions.loc.row.add:panelsOptions.loc.row.edit;this.$(".so-title").text(t)}}.bind(this))},setRowDialogType:function(e){this.dialogType=e},render:function(){var e="create"===this.dialogType?panelsOptions.loc.row.add:panelsOptions.loc.row.edit;this.renderDialog(this.parseDialogContent(h("#siteorigin-panels-dialog-row").html(),{title:e,dialogType:this.dialogType}));var t=this.$(".so-title");return this.model.has("label")&&!_.isEmpty(this.model.get("label"))&&t.text(this.model.get("label")),this.$(".so-edit-title").val(t.text()),this.builder.supports("addRow")||this.$(".so-buttons .so-duplicate").remove(),this.builder.supports("deleteRow")||this.$(".so-buttons .so-delete").remove(),_.isUndefined(this.model)||(this.$('input[name="cells"].so-row-field').val(this.model.get("cells").length),this.model.has("ratio")&&this.$('select[name="ratio"].so-row-field').val(this.model.get("ratio")),this.model.has("ratio_direction")&&this.$('select[name="ratio_direction"].so-row-field').val(this.model.get("ratio_direction"))),this.$("input.so-row-field").keyup(function(){h(this).trigger("change")}),this},renderStyles:function(){this.styles&&(this.styles.off("styles_loaded"),this.styles.remove()),this.styles=new a.view.styles,this.styles.model=this.model,this.styles.render("row",this.builder.config.postId,{builderType:this.builder.config.builderType,dialog:this});var t=this.$(".so-sidebar.so-right-sidebar");this.styles.attach(t),this.styles.on("styles_loaded",function(e){e||(this.styles.remove(),0===t.children().length&&(t.closest(".so-panels-dialog").removeClass("so-panels-dialog-has-right-sidebar"),t.hide()))},this)},setRowModel:function(e){return this.model=e,_.isEmpty(this.model)||(this.row={cells:this.model.get("cells").clone(),style:{},ratio:this.model.get("ratio"),ratio_direction:this.model.get("ratio_direction")},this.$('input[name="cells"].so-row-field').val(this.model.get("cells").length),this.model.has("ratio")&&this.$('select[name="ratio"].so-row-field').val(this.model.get("ratio")),this.model.has("ratio_direction")&&this.$('select[name="ratio_direction"].so-row-field').val(this.model.get("ratio_direction")),this.clearCellStylesCache()),this},regenerateRowPreview:function(){var t,r=this,d=this.$(".row-preview"),s=this.getSelectedCellIndex();d.empty(),this.row.cells.each(function(i,n){var o=h(this.cellPreviewTemplate({weight:i.get("weight")}));d.append(o),n==s&&o.find(".preview-cell-in").addClass("cell-selected");var e,a=o.prev();a.length&&((e=h('<div class="resize-handle"></div>')).appendTo(o).dblclick(function(){var e=r.row.cells.at(n-1),t=i.get("weight")+e.get("weight");i.set("weight",t/2),e.set("weight",t/2),r.scaleRowWidths()}),e.draggable({axis:"x",containment:d,start:function(e,t){var i=o.clone().appendTo(t.helper).css({position:"absolute",top:"0",width:o.outerWidth(),left:6,height:o.outerHeight()});i.find(".resize-handle").remove();var s=a.clone().appendTo(t.helper).css({position:"absolute",top:"0",width:a.outerWidth(),right:6,height:a.outerHeight()});s.find(".resize-handle").remove(),h(this).data({newCellClone:i,prevCellClone:s}),o.find("> .preview-cell-in").css("visibility","hidden"),a.find("> .preview-cell-in").css("visibility","hidden")},drag:function(e,t){var i=r.row.cells.at(n).get("weight"),s=r.row.cells.at(n-1).get("weight"),l=i-(t.position.left+6)/d.width(),o=s+(t.position.left+6)/d.width();t.helper.offset().left,d.offset().left;h(this).data("newCellClone").css("width",d.width()*l).find(".preview-cell-weight").html(Math.round(1e3*l)/10),h(this).data("prevCellClone").css("width",d.width()*o).find(".preview-cell-weight").html(Math.round(1e3*o)/10)},stop:function(e,t){h(this).data("newCellClone").remove(),h(this).data("prevCellClone").remove(),o.find(".preview-cell-in").css("visibility","visible"),a.find(".preview-cell-in").css("visibility","visible");var i=(t.position.left+6)/d.width(),s=r.row.cells.at(n),l=r.row.cells.at(n-1);.02<s.get("weight")-i&&.02<l.get("weight")+i&&(s.set("weight",s.get("weight")-i),l.set("weight",l.get("weight")+i)),r.scaleRowWidths(),t.helper.css("left",-6)}})),o.click(function(e){if(h(e.target).is(".preview-cell")||h(e.target).is(".preview-cell-in")){var t=h(e.target);t.closest(".row-preview").find(".preview-cell .preview-cell-in").removeClass("cell-selected"),t.addClass("cell-selected"),this.openSelectedCellStyles()}}.bind(this)),o.find(".preview-cell-weight").click(function(e){r.$(".resize-handle").css("pointer-event","none").draggable("disable"),d.find(".preview-cell-weight").each(function(){var e=jQuery(this).hide();h('<input type="text" class="preview-cell-weight-input no-user-interacted" />').val(parseFloat(e.html())).insertAfter(e).focus(function(){clearTimeout(t)}).keyup(function(e){9!==e.keyCode&&h(this).removeClass("no-user-interacted"),13===e.keyCode&&(e.preventDefault(),h(this).blur())}).keydown(function(e){if(9===e.keyCode){e.preventDefault();var t=d.find(".preview-cell-weight-input"),i=t.index(h(this));i===t.length-1?t.eq(0).focus().select():t.eq(i+1).focus().select()}}).blur(function(){d.find(".preview-cell-weight-input").each(function(e,t){isNaN(parseFloat(h(t).val()))&&h(t).val(Math.floor(1e3*r.row.cells.at(e).get("weight"))/10)}),t=setTimeout(function(){if(0===d.find(".preview-cell-weight-input").length)return!1;var l=[],o=[],n=0,a=0;if(d.find(".preview-cell-weight-input").each(function(e,t){var i=parseFloat(h(t).val());i=isNaN(i)?1/r.row.cells.length:Math.round(10*i)/1e3;var s=!h(t).hasClass("no-user-interacted");l.push(i),o.push(s),s?n+=i:a+=i}),0<n&&0<a&&0<1-n)for(var e=0;e<l.length;e++)o[e]||(l[e]=l[e]/a*(1-n));var t=_.reduce(l,function(e,t){return e+t});l=l.map(function(e){return e/t}),.01<Math.min.apply(Math,l)&&r.row.cells.each(function(e,t){e.set("weight",l[t])}),d.find(".preview-cell").each(function(e,t){var i=r.row.cells.at(e).get("weight");h(t).animate({width:Math.round(1e3*i)/10+"%"},250),h(t).find(".preview-cell-weight-input").val(Math.round(1e3*i)/10)}),d.find(".preview-cell").css("overflow","visible"),setTimeout(r.regenerateRowPreview.bind(r),260)},100)}).click(function(){h(this).select()})}),h(this).siblings(".preview-cell-weight-input").select()})},this),this.openSelectedCellStyles(),this.trigger("form_loaded",this)},getSelectedCellIndex:function(){var i=-1;return this.$(".preview-cell .preview-cell-in").each(function(e,t){h(t).is(".cell-selected")&&(i=e)}),i},openSelectedCellStyles:function(){if(!_.isUndefined(this.cellStyles)){if(this.cellStyles.stylesLoaded){var e={};try{e=this.getFormValues(".so-sidebar .so-visual-styles.so-cell-styles").style}catch(e){console.log("Error retrieving cell styles - "+e.message)}this.cellStyles.model.set("style",e)}this.cellStyles.detach()}if(this.cellStyles=this.getSelectedCellStyles(),this.cellStyles){var t=this.$(".so-sidebar.so-right-sidebar");this.cellStyles.attach(t),this.cellStyles.on("styles_loaded",function(e){e&&(t.closest(".so-panels-dialog").addClass("so-panels-dialog-has-right-sidebar"),t.show())})}},getSelectedCellStyles:function(){var e=this.getSelectedCellIndex();if(-1<e){var t=this.cellStylesCache[e];t||((t=new a.view.styles).model=this.row.cells.at(e),t.render("cell",this.builder.config.postId,{builderType:this.builder.config.builderType,dialog:this,index:e}),this.cellStylesCache[e]=t)}return t},clearCellStylesCache:function(){this.cellStylesCache.forEach(function(e){e.remove()}),this.cellStylesCache=[]},scaleRowWidths:function(){var s=this;this.$(".row-preview .preview-cell").each(function(e,t){var i=s.row.cells.at(e);h(t).css("width",100*i.get("weight")+"%").find(".preview-cell-weight").html(Math.round(1e3*i.get("weight"))/10)})},setCellsFromForm:function(){try{var e={cells:parseInt(this.$('.row-set-form input[name="cells"]').val()),ratio:parseFloat(this.$('.row-set-form select[name="ratio"]').val()),direction:this.$('.row-set-form select[name="ratio_direction"]').val()};_.isNaN(e.cells)&&(e.cells=1),isNaN(e.ratio)&&(e.ratio=1),e.cells<1?(e.cells=1,this.$('.row-set-form input[name="cells"]').val(e.cells)):12<e.cells&&(e.cells=12,this.$('.row-set-form input[name="cells"]').val(e.cells)),this.$('.row-set-form select[name="ratio"]').val(e.ratio);for(var t=[],i=this.row.cells.length!==e.cells,s=1,l=0;l<e.cells;l++)t.push(s),s*=e.ratio;var o=_.reduce(t,function(e,t){return e+t});if(t=_.map(t,function(e){return e/o}),t=_.filter(t,function(e){return.01<e}),"left"===e.direction&&(t=t.reverse()),this.row.cells=new a.collection.cells(this.row.cells.first(t.length)),_.each(t,function(e,t){var i=this.row.cells.at(t);i?i.set("weight",e):(i=new a.model.cell({weight:e,row:this.model}),this.row.cells.add(i))}.bind(this)),this.row.ratio=e.ratio,this.row.ratio_direction=e.direction,i)this.regenerateRowPreview();else{var n=this;this.$(".preview-cell").each(function(e,t){var i=n.row.cells.at(e).get("weight");h(t).animate({width:Math.round(1e3*i)/10+"%"},250),h(t).find(".preview-cell-weight").html(Math.round(1e3*i)/10)}),this.$(".preview-cell").css("overflow","visible"),setTimeout(n.regenerateRowPreview.bind(n),260)}}catch(e){console.log("Error setting cells - "+e.message)}this.$(".row-set-form .so-button-row-set").removeClass("button-primary")},tabClickHandler:function(e){"#row-layout"===e.attr("href")?this.$(".so-panels-dialog").addClass("so-panels-dialog-has-right-sidebar"):this.$(".so-panels-dialog").removeClass("so-panels-dialog-has-right-sidebar")},updateModel:function(e){if(e=_.extend({refresh:!0,refreshArgs:null},e),_.isEmpty(this.model)||(this.model.setCells(this.row.cells),this.model.set("ratio",this.row.ratio),this.model.set("ratio_direction",this.row.ratio_direction)),!_.isUndefined(this.styles)&&this.styles.stylesLoaded){var t={};try{t=this.getFormValues(".so-sidebar .so-visual-styles.so-row-styles").style}catch(e){console.log("Error retrieving row styles - "+e.message)}this.model.set("style",t)}if(!_.isUndefined(this.cellStyles)&&this.cellStyles.stylesLoaded){t={};try{t=this.getFormValues(".so-sidebar .so-visual-styles.so-cell-styles").style}catch(e){console.log("Error retrieving cell styles - "+e.message)}this.cellStyles.model.set("style",t)}e.refresh&&this.builder.model.refreshPanelsData(e.refreshArgs)},insertHandler:function(){this.builder.addHistoryEntry("row_added"),this.updateModel();var e=this.builder.getActiveCell({createCell:!1}),t={};return null!==e&&(t.at=this.builder.model.get("rows").indexOf(e.row)+1),this.model.collection=this.builder.model.get("rows"),this.builder.model.get("rows").add(this.model,t),this.closeDialog(),this.builder.model.refreshPanelsData(),!1},saveHandler:function(){return this.builder.addHistoryEntry("row_edited"),this.updateModel(),this.closeDialog(),this.builder.model.refreshPanelsData(),!1},deleteHandler:function(){return this.rowView.visualDestroyModel(),this.closeDialog({silent:!0}),!1},duplicateHandler:function(){this.builder.addHistoryEntry("row_duplicated");var e=this.model.clone(this.builder.model);return this.builder.model.get("rows").add(e,{at:this.builder.model.get("rows").indexOf(this.model)+1}),this.closeDialog({silent:!0}),!1},closeHandler:function(){this.clearCellStylesCache(),_.isUndefined(this.cellStyles)||(this.cellStyles=void 0)}})},{}],9:[function(e,t,i){var s=window.panels,l=jQuery,o=e("../view/widgets/js-widget");t.exports=s.view.dialog.extend({builder:null,sidebarWidgetTemplate:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-dialog-widget-sidebar-widget").html())),dialogClass:"so-panels-dialog-edit-widget",dialogIcon:"add-widget",widgetView:!1,savingWidget:!1,editableLabel:!0,events:{"click .so-close":"saveHandler","click .so-nav.so-previous":"navToPrevious","click .so-nav.so-next":"navToNext","click .so-toolbar .so-delete":"deleteHandler","click .so-toolbar .so-duplicate":"duplicateHandler"},initializeDialog:function(){var e=this;this.listenTo(this.model,"change:values",this.handleChangeValues),this.listenTo(this.model,"destroy",this.remove),this.dialogFormsLoaded=0,this.on("form_loaded styles_loaded",function(){this.dialogFormsLoaded++,2===this.dialogFormsLoaded&&e.updateModel({refreshArgs:{silent:!0}})}),this.on("edit_label",function(e){e===panelsOptions.widgets[this.model.get("class")].title&&(e=""),this.model.set("label",e),_.isEmpty(e)&&this.$(".so-title").text(this.model.getWidgetField("title"))}.bind(this))},render:function(){this.renderDialog(this.parseDialogContent(l("#siteorigin-panels-dialog-widget").html(),{})),this.loadForm();var e=this.model.getWidgetField("title");this.$(".so-title .widget-name").html(e),this.$(".so-edit-title").val(e),this.builder.supports("addWidget")||this.$(".so-buttons .so-duplicate").remove(),this.builder.supports("deleteWidget")||this.$(".so-buttons .so-delete").remove(),this.styles=new s.view.styles,this.styles.model=this.model,this.styles.render("widget",this.builder.config.postId,{builderType:this.builder.config.builderType,dialog:this});var t=this.$(".so-sidebar.so-right-sidebar");this.styles.attach(t),this.styles.on("styles_loaded",function(e){e||(t.closest(".so-panels-dialog").removeClass("so-panels-dialog-has-right-sidebar"),t.remove())},this)},getPrevDialog:function(){var e=this.builder.$(".so-cells .cell .so-widget");if(e.length<=1)return!1;var t,i=e.index(this.widgetView.$el);if(0===i)return!1;do{if(t=e.eq(--i).data("view"),!_.isUndefined(t)&&!t.model.get("read_only"))return t.getEditDialog()}while(!_.isUndefined(t)&&0<i);return!1},getNextDialog:function(){var e=this.builder.$(".so-cells .cell .so-widget");if(e.length<=1)return!1;var t,i=e.index(this.widgetView.$el);if(i===e.length-1)return!1;do{if(t=e.eq(++i).data("view"),!_.isUndefined(t)&&!t.model.get("read_only"))return t.getEditDialog()}while(!_.isUndefined(t));return!1},loadForm:function(){if(this.$("> *").length){this.$(".so-content").addClass("so-panels-loading");var e={action:"so_panels_widget_form",widget:this.model.get("class"),instance:JSON.stringify(this.model.get("values")),raw:this.model.get("raw")},i=this.$(".so-content");l.post(panelsOptions.ajaxurl,e,null,"html").done(function(e){var t=e.replace(/{\$id}/g,this.model.cid);i.removeClass("so-panels-loading").html(t),this.trigger("form_loaded",this),this.$(".panel-dialog").trigger("panelsopen"),this.on("close_dialog",this.updateModel,this),0<i.find("> .widget-content").length&&o.addWidget(i,this.model.widget_id)}.bind(this)).fail(function(e){var t;t=e&&e.responseText?e.responseText:panelsOptions.forms.loadingFailed,i.removeClass("so-panels-loading").html(t)})}},updateModel:function(e){if(e=_.extend({refresh:!0,refreshArgs:null},e),this.savingWidget=!0,!this.model.get("missing")){var t=this.getFormValues();t=_.isUndefined(t.widgets)?{}:(t=t.widgets)[Object.keys(t)[0]],this.model.setValues(t),this.model.set("raw",!0)}if(this.styles.stylesLoaded){var i={};try{i=this.getFormValues(".so-sidebar .so-visual-styles").style}catch(e){}this.model.set("style",i)}this.savingWidget=!1,e.refresh&&this.builder.model.refreshPanelsData(e.refreshArgs)},handleChangeValues:function(){this.savingWidget||this.loadForm()},saveHandler:function(){this.builder.addHistoryEntry("widget_edited"),this.closeDialog()},deleteHandler:function(){return this.widgetView.visualDestroyModel(),this.closeDialog({silent:!0}),this.builder.model.refreshPanelsData(),!1},duplicateHandler:function(){return this.widgetView.duplicateHandler(),this.closeDialog({silent:!0}),this.builder.model.refreshPanelsData(),!1}})},{"../view/widgets/js-widget":31}],10:[function(e,t,i){var s=window.panels,o=jQuery;t.exports=s.view.dialog.extend({builder:null,widgetTemplate:_.template(s.helpers.utils.processTemplate(o("#siteorigin-panels-dialog-widgets-widget").html())),filter:{},dialogClass:"so-panels-dialog-add-widget",dialogIcon:"add-widget",events:{"click .so-close":"closeDialog","click .widget-type":"widgetClickHandler","keyup .so-sidebar-search":"searchHandler"},initializeDialog:function(){this.on("open_dialog",function(){this.filter.search="",this.filterWidgets(this.filter)},this),this.on("open_dialog_complete",function(){this.$(".so-sidebar-search").val("").focus(),this.balanceWidgetHeights()}),this.on("tab_click",this.tabClickHandler,this)},render:function(){this.renderDialog(this.parseDialogContent(o("#siteorigin-panels-dialog-widgets").html(),{})),_.each(panelsOptions.widgets,function(e){var t=o(this.widgetTemplate({title:e.title,description:e.description}));_.isUndefined(e.icon)&&(e.icon="dashicons dashicons-admin-generic"),o('<span class="widget-icon" />').addClass(e.icon).prependTo(t.find(".widget-type-wrapper")),t.data("class",e.class).appendTo(this.$(".widget-type-list"))},this);var t=this.$(".so-sidebar-tabs");_.each(panelsOptions.widget_dialog_tabs,function(e){o(this.dialogTabTemplate({title:e.title})).data({message:e.message,filter:e.filter}).appendTo(t)},this),this.initTabs();var e=this;o(window).resize(function(){e.balanceWidgetHeights()})},tabClickHandler:function(e){this.filter=e.parent().data("filter"),this.filter.search=this.$(".so-sidebar-search").val();var t=e.parent().data("message");return _.isEmpty(t)&&(t=""),this.$(".so-toolbar .so-status").html(t),this.filterWidgets(this.filter),!1},searchHandler:function(e){if(13===e.which){var t=this.$(".widget-type-list .widget-type:visible");1===t.length&&t.click()}else this.filter.search=o(e.target).val().trim(),this.filterWidgets(this.filter)},filterWidgets:function(l){_.isUndefined(l)&&(l={}),_.isUndefined(l.groups)&&(l.groups=""),this.$(".widget-type-list .widget-type").each(function(){var e,t=o(this),i=t.data("class"),s=_.isUndefined(panelsOptions.widgets[i])?null:panelsOptions.widgets[i];(e=!!_.isEmpty(l.groups)||null!==s&&!_.isEmpty(_.intersection(l.groups,panelsOptions.widgets[i].groups)))&&(_.isUndefined(l.search)||""===l.search||-1===s.title.toLowerCase().indexOf(l.search.toLowerCase())&&(e=!1)),e?t.show():t.hide()}),this.balanceWidgetHeights()},widgetClickHandler:function(e){this.builder.trigger("before_user_adds_widget"),this.builder.addHistoryEntry("widget_added");var t=o(e.currentTarget),i=new s.model.widget({class:t.data("class")});i.cell=this.builder.getActiveCell(),i.cell.get("widgets").add(i),this.closeDialog(),this.builder.model.refreshPanelsData(),this.builder.trigger("after_user_adds_widget",i)},balanceWidgetHeights:function(e){var s=[[]],l=null,i=Math.round(this.$(".widget-type").parent().width()/this.$(".widget-type").width());this.$(".widget-type").css("clear","none").filter(":visible").each(function(e,t){e%i==0&&0!==e&&o(t).css("clear","both")}),this.$(".widget-type-wrapper").css("height","auto").filter(":visible").each(function(e,t){var i=o(t);null!==l&&l.position().top!==i.position().top&&(s[s.length]=[]),l=i,s[s.length-1].push(i)}),_.each(s,function(e,t){var i=_.max(e.map(function(e){return e.height()}));_.each(e,function(e){e.height(i)})})}})},{}],11:[function(e,t,i){t.exports={canCopyPaste:function(){return"undefined"!=typeof Storage&&panelsOptions.user},setModel:function(e){if(!this.canCopyPaste())return!1;var t=panels.helpers.serialize.serialize(e);return e instanceof panels.model.row?t.thingType="row-model":e instanceof panels.model.widget&&(t.thingType="widget-model"),localStorage["panels_clipboard_"+panelsOptions.user]=JSON.stringify(t),!0},isModel:function(e){if(!this.canCopyPaste())return!1;var t=localStorage["panels_clipboard_"+panelsOptions.user];return void 0!==t&&((t=JSON.parse(t)).thingType&&t.thingType===e)},getModel:function(e){if(!this.canCopyPaste())return null;var t=localStorage["panels_clipboard_"+panelsOptions.user];return void 0!==t&&(t=JSON.parse(t)).thingType&&t.thingType===e?panels.helpers.serialize.unserialize(t,t.thingType,null):null}}},{}],12:[function(e,t,i){t.exports={lock:function(){if("hidden"!==jQuery("body").css("overflow")){var e=[self.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft,self.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop];jQuery("body").data({"scroll-position":e}).css("overflow","hidden"),_.isUndefined(e)||window.scrollTo(e[0],e[1])}},unlock:function(){if("hidden"===jQuery("body").css("overflow")&&!jQuery(".so-panels-dialog-wrapper").is(":visible")&&!jQuery(".so-panels-live-editor").is(":visible")){jQuery("body").css("overflow","visible");var e=jQuery("body").data("scroll-position");_.isUndefined(e)||window.scrollTo(e[0],e[1])}}}},{}],13:[function(e,t,i){t.exports={serialize:function(e){var t;if(e instanceof Backbone.Model){var i={};for(var s in e.attributes)if(e.attributes.hasOwnProperty(s)){if("builder"===s||"collection"===s)continue;(t=e.attributes[s])instanceof Backbone.Model||t instanceof Backbone.Collection?i[s]=this.serialize(t):i[s]=t}return i}if(e instanceof Backbone.Collection){for(var l=[],o=0;o<e.models.length;o++)(t=e.models[o])instanceof Backbone.Model||t instanceof Backbone.Collection?l.push(this.serialize(t)):l.push(t);return l}},unserialize:function(e,t,i){var s;switch(t){case"row-model":(s=new panels.model.row).builder=i;var l={style:e.style};e.hasOwnProperty("label")&&(l.label=e.label),e.hasOwnProperty("color_label")&&(l.color_label=e.color_label),s.set(l),s.setCells(this.unserialize(e.cells,"cell-collection",s));break;case"cell-model":(s=new panels.model.cell).row=i,s.set("weight",e.weight),s.set("style",e.style),s.set("widgets",this.unserialize(e.widgets,"widget-collection",s));break;case"widget-model":for(var o in(s=new panels.model.widget).cell=i,e)e.hasOwnProperty(o)&&s.set(o,e[o]);s.set("widget_id",panels.helpers.utils.generateUUID());break;case"cell-collection":s=new panels.collection.cells;for(var n=0;n<e.length;n++)s.push(this.unserialize(e[n],"cell-model",i));break;case"widget-collection":s=new panels.collection.widgets;for(n=0;n<e.length;n++)s.push(this.unserialize(e[n],"widget-model",i));break;default:console.log("Unknown Thing - "+t)}return s}}},{}],14:[function(e,t,i){t.exports={generateUUID:function(){var i=(new Date).getTime();return window.performance&&"function"==typeof window.performance.now&&(i+=performance.now()),"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(e){var t=(i+16*Math.random())%16|0;return i=Math.floor(i/16),("x"==e?t:3&t|8).toString(16)})},processTemplate:function(e){return _.isUndefined(e)||_.isNull(e)?"":e=(e=(e=e.replace(/{{%/g,"<%")).replace(/%}}/g,"%>")).trim()},selectElementContents:function(e){var t=document.createRange();t.selectNodeContents(e);var i=window.getSelection();i.removeAllRanges(),i.addRange(t)}}},{}],15:[function(e,t,i){var d=window.panels,h=jQuery;t.exports=function(a,r){return this.each(function(){var e=jQuery(this);if(!e.data("soPanelsBuilderWidgetInitialized")||r){var t=e.closest("form").find(".widget-id").val(),i=h.extend(!0,{},a);if(_.isUndefined(t)||!(-1<t.indexOf("__i__"))){var s=new d.model.builder,l=new d.view.builder({model:s,config:i}),o=e.closest(".so-panels-dialog-wrapper").data("view");_.isUndefined(o)||(o.on("close_dialog",function(){s.refreshPanelsData()}),o.on("open_dialog_complete",function(){l.trigger("builder_resize")}),o.model.on("destroy",function(){s.emptyRows().destroy()}),l.setDialogParents(panelsOptions.loc.layout_widget,o));var n=Boolean(e.closest(".widget-content").length);l.render().attach({container:e,dialog:n||"dialog"===e.data("mode"),type:e.data("type")}).setDataField(e.find("input.panels-data")),n||"dialog"===e.data("mode")?(l.setDialogParents(panelsOptions.loc.layout_widget,l.dialog),e.find(".siteorigin-panels-display-builder").click(function(e){e.preventDefault(),l.dialog.openDialog()})):e.find(".siteorigin-panels-display-builder").parent().remove(),h(document).trigger("panels_setup",l),e.data("soPanelsBuilderWidgetInitialized",!0)}}})}},{}],16:[function(e,t,i){var s={};window.panels=s,(window.siteoriginPanels=s).helpers={},s.helpers.clipboard=e("./helpers/clipboard"),s.helpers.utils=e("./helpers/utils"),s.helpers.serialize=e("./helpers/serialize"),s.helpers.pageScroll=e("./helpers/page-scroll"),s.model={},s.model.widget=e("./model/widget"),s.model.cell=e("./model/cell"),s.model.row=e("./model/row"),s.model.builder=e("./model/builder"),s.model.historyEntry=e("./model/history-entry"),s.collection={},s.collection.widgets=e("./collection/widgets"),s.collection.cells=e("./collection/cells"),s.collection.rows=e("./collection/rows"),s.collection.historyEntries=e("./collection/history-entries"),s.view={},s.view.widget=e("./view/widget"),s.view.cell=e("./view/cell"),s.view.row=e("./view/row"),s.view.builder=e("./view/builder"),s.view.dialog=e("./view/dialog"),s.view.styles=e("./view/styles"),s.view.liveEditor=e("./view/live-editor"),s.dialog={},s.dialog.builder=e("./dialog/builder"),s.dialog.widgets=e("./dialog/widgets"),s.dialog.widget=e("./dialog/widget"),s.dialog.prebuilt=e("./dialog/prebuilt"),s.dialog.row=e("./dialog/row"),s.dialog.history=e("./dialog/history"),s.utils={},s.utils.menu=e("./utils/menu"),jQuery.fn.soPanelsSetupBuilderWidget=e("./jquery/setup-builder-widget"),jQuery(function(i){var e,t,s,l,o=i("#siteorigin-panels-metabox");if(s=i("form#post"),o.length&&s.length)t=(e=o).find(".siteorigin-panels-data-field"),l={editorType:"tinyMCE",postId:i("#post_ID").val(),editorId:"#content",builderType:o.data("builder-type"),builderSupports:o.data("builder-supports"),loadOnAttach:panelsOptions.loadOnAttach&&1==i("#auto_draft").val(),loadLiveEditor:1==o.data("live-editor"),liveEditorPreview:e.data("preview-url")};else if(i(".siteorigin-panels-builder-form").length){var n=i(".siteorigin-panels-builder-form");e=n.find(".siteorigin-panels-builder-container"),t=n.find('input[name="panels_data"]'),l={editorType:"standalone",postId:(s=n).data("post-id"),editorId:"#post_content",builderType:n.data("type"),builderSupports:n.data("builder-supports"),loadLiveEditor:!1,liveEditorPreview:n.data("preview-url")}}if(!_.isUndefined(e)){var a=window.siteoriginPanels,r=new a.model.builder,d=new a.view.builder({model:r,config:l});d.render().attach({container:e}).setDataField(t).attachToEditor(),s.submit(function(){r.refreshPanelsData()}),e.removeClass("so-panels-loading"),i(document).trigger("panels_setup",d,window.panels)}i(document).on("widget-added",function(e,t){i(t).find(".siteorigin-page-builder-widget").soPanelsSetupBuilderWidget()}),i("body").hasClass("wp-customizer")||i(function(){i(".siteorigin-page-builder-widget").soPanelsSetupBuilderWidget()}),i(window).on("keyup",function(e){27===e.which&&i(".so-panels-dialog-wrapper, .so-panels-live-editor").filter(":visible").last().find(".so-title-bar .so-close, .live-editor-close").click()})})},{"./collection/cells":1,"./collection/history-entries":2,"./collection/rows":3,"./collection/widgets":4,"./dialog/builder":5,"./dialog/history":6,"./dialog/prebuilt":7,"./dialog/row":8,"./dialog/widget":9,"./dialog/widgets":10,"./helpers/clipboard":11,"./helpers/page-scroll":12,"./helpers/serialize":13,"./helpers/utils":14,"./jquery/setup-builder-widget":15,"./model/builder":17,"./model/cell":18,"./model/history-entry":19,"./model/row":20,"./model/widget":21,"./utils/menu":22,"./view/builder":23,"./view/cell":24,"./view/dialog":25,"./view/live-editor":26,"./view/row":27,"./view/styles":28,"./view/widget":29}],17:[function(e,t,i){t.exports=Backbone.Model.extend({layoutPosition:{BEFORE:"before",AFTER:"after",REPLACE:"replace"},rows:{},defaults:{data:{widgets:[],grids:[],grid_cells:[]}},initialize:function(){this.set("rows",new panels.collection.rows)},addRow:function(e,t,i){i=_.extend({noAnimate:!1},i);var s=new panels.collection.cells(t);e=_.extend({collection:this.get("rows"),cells:s},e);var l=new panels.model.row(e);return(l.builder=this).get("rows").add(l,i),l},loadPanelsData:function(s,e){try{e===this.layoutPosition.BEFORE?s=this.concatPanelsData(s,this.getPanelsData()):e===this.layoutPosition.AFTER&&(s=this.concatPanelsData(this.getPanelsData(),s)),this.emptyRows(),this.set("data",JSON.parse(JSON.stringify(s)),{silent:!0});var t,i=[];if(_.isUndefined(s.grid_cells))return void this.trigger("load_panels_data");for(var l=0;l<s.grid_cells.length;l++)t=parseInt(s.grid_cells[l].grid),_.isUndefined(i[t])&&(i[t]=[]),i[t].push(s.grid_cells[l]);var o=this;if(_.each(i,function(e,t){var i={};_.isUndefined(s.grids[t].style)||(i.style=s.grids[t].style),_.isUndefined(s.grids[t].ratio)||(i.ratio=s.grids[t].ratio),_.isUndefined(s.grids[t].ratio_direction)||(i.ratio_direction=s.grids[t].ratio_direction),_.isUndefined(s.grids[t].color_label)||(i.color_label=s.grids[t].color_label),_.isUndefined(s.grids[t].label)||(i.label=s.grids[t].label),o.addRow(i,e,{noAnimate:!0})}),_.isUndefined(s.widgets))return;_.each(s.widgets,function(e){var t=null;_.isUndefined(e.panels_info)?(t=e.info,delete e.info):(t=e.panels_info,delete e.panels_info);var i=o.get("rows").at(parseInt(t.grid)).get("cells").at(parseInt(t.cell)),s=new panels.model.widget({class:t.class,values:e});_.isUndefined(t.style)||s.set("style",t.style),_.isUndefined(t.read_only)||s.set("read_only",t.read_only),_.isUndefined(t.widget_id)?s.set("widget_id",panels.helpers.utils.generateUUID()):s.set("widget_id",t.widget_id),_.isUndefined(t.label)||s.set("label",t.label),(s.cell=i).get("widgets").add(s,{noAnimate:!0})}),this.trigger("load_panels_data")}catch(e){console.log("Error loading data: "+e.message)}},concatPanelsData:function(e,t){if(_.isUndefined(t)||_.isUndefined(t.grids)||_.isEmpty(t.grids)||_.isUndefined(t.grid_cells)||_.isEmpty(t.grid_cells))return e;if(_.isUndefined(e)||_.isUndefined(e.grids)||_.isEmpty(e.grids))return t;var i,s=e.grids.length,l=_.isUndefined(e.widgets)?0:e.widgets.length,o={grids:[],grid_cells:[],widgets:[]};for(o.grids=e.grids.concat(t.grids),_.isUndefined(e.grid_cells)||(o.grid_cells=e.grid_cells.slice()),_.isUndefined(e.widgets)||(o.widgets=e.widgets.slice()),i=0;i<t.grid_cells.length;i++){var n=t.grid_cells[i];n.grid=parseInt(n.grid)+s,o.grid_cells.push(n)}if(!_.isUndefined(t.widgets))for(i=0;i<t.widgets.length;i++){var a=t.widgets[i];a.panels_info.grid=parseInt(a.panels_info.grid)+s,a.panels_info.id=parseInt(a.panels_info.id)+l,o.widgets.push(a)}return o},getPanelsData:function(){var n={widgets:[],grids:[],grid_cells:[]},a=0;return this.get("rows").each(function(e,o){e.get("cells").each(function(e,l){e.get("widgets").each(function(e,t){var i={class:e.get("class"),raw:e.get("raw"),grid:o,cell:l,id:a++,widget_id:e.get("widget_id"),style:e.get("style"),label:e.get("label")};_.isEmpty(i.widget_id)&&(i.widget_id=panels.helpers.utils.generateUUID());var s=_.extend(_.clone(e.get("values")),{panels_info:i});n.widgets.push(s)}),n.grid_cells.push({grid:o,index:l,weight:e.get("weight"),style:e.get("style")})}),n.grids.push({cells:e.get("cells").length,style:e.get("style"),ratio:e.get("ratio"),ratio_direction:e.get("ratio_direction"),color_label:e.get("color_label"),label:e.get("label")})}),n},refreshPanelsData:function(e){e=_.extend({silent:!1},e);var t=this.get("data"),i=this.getPanelsData();this.set("data",i,{silent:!0}),e.silent||JSON.stringify(i)===JSON.stringify(t)||(this.trigger("change"),this.trigger("change:data"),this.trigger("refresh_panels_data",i,e))},emptyRows:function(){return _.invoke(this.get("rows").toArray(),"destroy"),this.get("rows").reset(),this},isValidLayoutPosition:function(e){return e===this.layoutPosition.BEFORE||e===this.layoutPosition.AFTER||e===this.layoutPosition.REPLACE},getPanelsDataFromHtml:function(e,c){var t,u=this,i=jQuery('<div id="wrapper">'+e+"</div>");if(i.find(".panel-layout .panel-grid").length){var p={grids:[],grid_cells:[],widgets:[]},g=new RegExp(panelsOptions.siteoriginWidgetRegex,"i"),f=(t=document.createElement("div"),function(e){return e&&"string"==typeof e&&(e=(e=e.replace(/<script[^>]*>([\S\s]*?)<\/script>/gim,"")).replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/gim,""),t.innerHTML=e,e=t.textContent,t.textContent=""),e}),w=function(e){var t,i=e.find("div");if(!i.length)return e.html();for(t=0;t<i.length-1&&jQuery.trim(i.eq(t).text())==jQuery.trim(i.eq(t+1).text());t++);var s=i.eq(t).find(".widget-title:header"),l="";return s.length&&(l=s.html(),s.remove()),{title:l,text:i.eq(t).html()}},s=i.find(".panel-layout").eq(0),l=function(e,t){return jQuery(t).closest(".panel-layout").is(s)};return i.find("> .panel-layout > .panel-grid").filter(l).each(function(h,e){var t=jQuery(e),i=t.find(".panel-grid-cell").filter(l);p.grids.push({cells:i.length,style:t.data("style"),ratio:t.data("ratio"),ratio_direction:t.data("ratio-direction"),color_label:t.data("color-label"),label:t.data("label")}),i.each(function(d,e){var t=jQuery(e),i=t.find(".so-panel").filter(l);p.grid_cells.push({grid:h,weight:_.isUndefined(t.data("weight"))?1:parseFloat(t.data("weight")),style:t.data("style")}),i.each(function(e,t){var i=jQuery(t),s=i.find(".panel-widget-style").length?i.find(".panel-widget-style").html():i.html(),l={grid:h,cell:d,style:i.data("style"),raw:!1,label:i.data("label")};s=s.trim();var o=g.exec(s);if(_.isNull(o)||""!==s.replace(g,"").trim())return-1!==s.indexOf("panel-layout")&&jQuery("<div>"+s+"</div>").find(".panel-layout .panel-grid").length?(l.class="SiteOrigin_Panels_Widgets_Layout",p.widgets.push({panels_data:u.getPanelsDataFromHtml(s,c),panels_info:l})):(l.class=c,p.widgets.push(_.extend(w(i),{filter:"1",type:"visual",panels_info:l}))),!0;try{var n=/class="(.*?)"/.exec(o[3]),a=jQuery(o[5]),r=JSON.parse(f(a.val())).instance;l.class=n[1].replace(/\\\\+/g,"\\"),l.raw=!1,r.panels_info=l,p.widgets.push(r)}catch(e){l.class=c,p.widgets.push(_.extend(w(i),{filter:"1",type:"visual",panels_info:l}))}return!0})})}),i.find(".panel-layout").remove(),i.find("style[data-panels-style-for-post]").remove(),i.html().replace(/^\s+|\s+$/gm,"").length&&(p.grids.push({cells:1,style:{}}),p.grid_cells.push({grid:p.grids.length-1,weight:1}),p.widgets.push({filter:"1",text:i.html().replace(/^\s+|\s+$/gm,""),title:"",type:"visual",panels_info:{class:c,raw:!1,grid:p.grids.length-1,cell:0}})),p}return{grid_cells:[{grid:0,weight:1}],grids:[{cells:1}],widgets:[{filter:"1",text:e,title:"",type:"visual",panels_info:{class:c,raw:!1,grid:0,cell:0}}]}}})},{}],18:[function(e,t,i){t.exports=Backbone.Model.extend({widgets:{},row:null,defaults:{weight:0,style:{}},indexes:null,initialize:function(){this.set("widgets",new panels.collection.widgets),this.on("destroy",this.onDestroy,this)},onDestroy:function(){_.invoke(this.get("widgets").toArray(),"destroy"),this.get("widgets").reset()},clone:function(e,t){_.isUndefined(e)&&(e=this.row),t=_.extend({cloneWidgets:!0},t);var i=new this.constructor(this.attributes);return i.set("collection",e.get("cells"),{silent:!0}),i.row=e,t.cloneWidgets&&this.get("widgets").each(function(e){i.get("widgets").add(e.clone(i,t),{silent:!0})}),i}})},{}],19:[function(e,t,i){t.exports=Backbone.Model.extend({defaults:{text:"",data:"",time:null,count:1}})},{}],20:[function(e,t,i){t.exports=Backbone.Model.extend({builder:null,defaults:{style:{}},indexes:null,initialize:function(){_.isEmpty(this.get("cells"))?this.set("cells",new panels.collection.cells):this.get("cells").each(function(e){e.row=this}.bind(this)),this.on("destroy",this.onDestroy,this)},setCells:function(n){var a=this.get("cells")||new panels.collection.cells,r=[];a.each(function(e,t){var i=n.at(t);if(i)e.set("weight",i.get("weight"));else{for(var s=a.at(n.length-1),l=e.get("widgets").models.slice(),o=0;o<l.length;o++)l[o].moveToCell(s,{silent:!1});r.push(e)}}),_.each(r,function(e){a.remove(e)}),n.length>a.length&&_.each(n.slice(a.length,n.length),function(e){e.set({collection:a}),e.row=this,a.add(e)}.bind(this)),this.reweightCells()},reweightCells:function(){var t=0,e=this.get("cells");e.each(function(e){t+=e.get("weight")}),e.each(function(e){e.set("weight",e.get("weight")/t)}),this.trigger("reweight_cells")},onDestroy:function(){_.invoke(this.get("cells").toArray(),"destroy"),this.get("cells").reset()},clone:function(e){_.isUndefined(e)&&(e=this.builder);var t=new this.constructor(this.attributes);t.set("collection",e.get("rows"),{silent:!0}),t.builder=e;var i=new panels.collection.cells;return this.get("cells").each(function(e){i.add(e.clone(t),{silent:!0})}),t.set("cells",i),t}})},{}],21:[function(e,t,i){t.exports=Backbone.Model.extend({cell:null,defaults:{class:null,missing:!1,values:{},raw:!1,style:{},read_only:!1,widget_id:""},indexes:null,initialize:function(){var e=this.get("class");!_.isUndefined(panelsOptions.widgets[e])&&panelsOptions.widgets[e].installed||this.set("missing",!0)},getWidgetField:function(e){return _.isUndefined(panelsOptions.widgets[this.get("class")])?"title"===e||"description"===e?panelsOptions.loc.missing_widget[e]:"":this.has("label")&&!_.isEmpty(this.get("label"))?this.get("label"):panelsOptions.widgets[this.get("class")][e]},moveToCell:function(e,t,i){return t=_.extend({silent:!0},t),this.cell=e,this.collection.remove(this,t),e.get("widgets").add(this,_.extend({at:i},t)),this.trigger("move_to_cell",e,i),this},setValues:function(e){var t=!1;JSON.stringify(e)!==JSON.stringify(this.get("values"))&&(t=!0),this.set("values",e,{silent:!0}),t&&(this.trigger("change",this),this.trigger("change:values"))},clone:function(e,t){_.isUndefined(e)&&(e=this.cell);var i=new this.constructor(this.attributes),s=JSON.parse(JSON.stringify(this.get("values"))),l=function(i){return _.each(i,function(e,t){_.isString(t)&&"_"===t[0]?delete i[t]:_.isObject(i[t])&&l(i[t])}),i};return s=l(s),"SiteOrigin_Panels_Widgets_Layout"===this.get("class")&&(s.builder_id=Math.random().toString(36).substr(2)),i.set("widget_id",""),i.set("values",s,{silent:!0}),i.set("collection",e.get("widgets"),{silent:!0}),i.cell=e,i.isDuplicate=!0,i},getTitle:function(){var e=panelsOptions.widgets[this.get("class")];if(_.isUndefined(e))return this.get("class").replace(/_/g," ");if(!_.isUndefined(e.panels_title)&&!1===e.panels_title)return panelsOptions.widgets[this.get("class")].description;var t=this.get("values"),i=["title","text"];for(var s in t)"_"!==s.charAt(0)&&"so_sidebar_emulator_id"!==s&&"option_name"!==s&&t.hasOwnProperty(s)&&i.push(s);for(var l in i=_.uniq(i))if(!_.isUndefined(t[i[l]])&&_.isString(t[i[l]])&&""!==t[i[l]]&&"on"!==t[i[l]]&&"_"!==i[l][0]&&!jQuery.isNumeric(t[i[l]])){var o=t[i[l]],n=(o=o.replace(/<\/?[^>]+(>|$)/g,"")).split(" ");return(n=n.slice(0,20)).join(" ")}return this.getWidgetField("description")}})},{}],22:[function(e,t,i){var s=window.panels,r=jQuery;t.exports=Backbone.View.extend({wrapperTemplate:_.template(s.helpers.utils.processTemplate(r("#siteorigin-panels-context-menu").html())),sectionTemplate:_.template(s.helpers.utils.processTemplate(r("#siteorigin-panels-context-menu-section").html())),contexts:[],active:!1,events:{"keyup .so-search-wrapper input":"searchKeyUp"},initialize:function(){this.listenContextMenu(),this.render(),this.attach()},listenContextMenu:function(){var t=this;r(window).on("contextmenu",function(e){return t.active&&!t.isOverEl(t.$el,e)?(t.closeMenu(),t.active=!1,e.preventDefault(),!1):!!t.active||(t.active=!1,t.trigger("activate_context",e,t),void(t.active&&(e.preventDefault(),t.openMenu({left:e.pageX,top:e.pageY}))))})},render:function(){this.setElement(this.wrapperTemplate())},attach:function(){this.$el.appendTo("body")},openMenu:function(e){this.trigger("open_menu"),r(window).on("keyup",{menu:this},this.keyboardListen),r(window).on("click",{menu:this},this.clickOutsideListen),this.$el.css("max-height",r(window).height()-20),e.left+this.$el.outerWidth()+10>=r(window).width()&&(e.left=r(window).width()-this.$el.outerWidth()-10),e.left<=0&&(e.left=10),e.top+this.$el.outerHeight()-r(window).scrollTop()+10>=r(window).height()&&(e.top=r(window).height()+r(window).scrollTop()-this.$el.outerHeight()-10),e.left<=0&&(e.left=10),this.$el.css({left:e.left+1,top:e.top+1}).show(),this.$(".so-search-wrapper input").focus()},closeMenu:function(){this.trigger("close_menu"),r(window).off("keyup",this.keyboardListen),r(window).off("click",this.clickOutsideListen),this.active=!1,this.$el.empty().hide()},keyboardListen:function(e){var t=e.data.menu;switch(e.which){case 27:t.closeMenu()}},clickOutsideListen:function(e){var t=e.data.menu;3!==e.which&&t.$el.is(":visible")&&!t.isOverEl(t.$el,e)&&t.closeMenu()},addSection:function(e,t,i,s){var l=this;t=_.extend({display:5,defaultDisplay:!1,search:!0,sectionTitle:"",searchPlaceholder:"",titleKey:"title"},t);var o=r(this.sectionTemplate({settings:t,items:i})).attr("id","panels-menu-section-"+e);this.$el.append(o),o.find(".so-item:not(.so-confirm)").click(function(){var e=r(this);s(e.data("key")),l.closeMenu()}),o.find(".so-item.so-confirm").click(function(){var e=r(this);if(e.hasClass("so-confirming"))return s(e.data("key")),void l.closeMenu();e.data("original-text",e.html()).addClass("so-confirming").html('<span class="dashicons dashicons-yes"></span> '+panelsOptions.loc.dropdown_confirm),setTimeout(function(){e.removeClass("so-confirming"),e.html(e.data("original-text"))},2500)}),o.data("settings",t).find(".so-search-wrapper input").trigger("keyup"),this.active=!0},hasSection:function(e){return 0<this.$el.find("#panels-menu-section-"+e).length},searchKeyUp:function(e){var t=r(e.currentTarget),i=t.closest(".so-section"),s=i.data("settings");if(38===e.which||40===e.which){var l=i.find("ul li:visible"),o=l.filter(".so-active").eq(0);if(o.length){l.removeClass("so-active");var n=l.index(o);38===e.which?o=n-1<0?l.last():l.eq(n-1):40===e.which&&(o=n+1>=l.length?l.first():l.eq(n+1))}else 38===e.which?o=l.last():40===e.which&&(o=l.first());return o.addClass("so-active"),!1}if(13===e.which)return 1===i.find("ul li:visible").length?i.find("ul li:visible").trigger("click"):i.find("ul li.so-active:visible").trigger("click"),!1;if(""===t.val())if(s.defaultDisplay){i.find(".so-item").hide();for(var a=0;a<s.defaultDisplay.length;a++)i.find('.so-item[data-key="'+s.defaultDisplay[a]+'"]').show()}else i.find(".so-item").show();else i.find(".so-item").hide().each(function(){var e=r(this);-1!==e.html().toLowerCase().indexOf(t.val().toLowerCase())&&e.show()});i.find(".so-item:visible:gt("+(s.display-1)+")").hide(),0===i.find(".so-item:visible").length&&""!==t.val()?i.find(".so-no-results").show():i.find(".so-no-results").hide()},isOverEl:function(e,t){var i=[[e.offset().left,e.offset().top],[e.offset().left+e.outerWidth(),e.offset().top+e.outerHeight()]];return t.pageX>=i[0][0]&&t.pageX<=i[1][0]&&t.pageY>=i[0][1]&&t.pageY<=i[1][1]}})},{}],23:[function(e,t,i){var a=window.panels,n=jQuery;t.exports=Backbone.View.extend({config:{},template:_.template(a.helpers.utils.processTemplate(n("#siteorigin-panels-builder").html())),dialogs:{},rowsSortable:null,dataField:!1,currentData:"",attachedToEditor:!1,attachedVisible:!1,liveEditor:void 0,menu:!1,activeCell:null,events:{"click .so-tool-button.so-widget-add":"displayAddWidgetDialog","click .so-tool-button.so-row-add":"displayAddRowDialog","click .so-tool-button.so-prebuilt-add":"displayAddPrebuiltDialog","click .so-tool-button.so-history":"displayHistoryDialog","click .so-tool-button.so-live-editor":"displayLiveEditor"},rows:null,initialize:function(e){var s=this;return this.config=_.extend({loadLiveEditor:!1,builderSupports:{}},e.config),this.config.builderSupports=_.extend({addRow:!0,editRow:!0,deleteRow:!0,moveRow:!0,addWidget:!0,editWidget:!0,deleteWidget:!0,moveWidget:!0,prebuilt:!0,history:!0,liveEditor:!0,revertToEditor:!0},this.config.builderSupports),e.config.loadLiveEditor&&this.on("builder_live_editor_added",function(){this.displayLiveEditor()}),this.dialogs={widgets:new a.dialog.widgets,row:new a.dialog.row,prebuilt:new a.dialog.prebuilt},_.each(this.dialogs,function(e,t,i){i[t].setBuilder(s)}),this.dialogs.row.setRowDialogType("create"),this.listenTo(this.model.get("rows"),"add",this.onAddRow),n(window).resize(function(e){e.target===window&&s.trigger("builder_resize")}),this.listenTo(this.model,"change:data load_panels_data",this.storeModelData),this.listenTo(this.model,"change:data load_panels_data",this.toggleWelcomeDisplay),this.on("content_change",this.handleContentChange,this),this.on("display_builder",this.handleDisplayBuilder,this),this.on("hide_builder",this.handleHideBuilder,this),this.on("builder_rendered builder_resize",this.handleBuilderSizing,this),this.on("display_builder",this.wrapEditorExpandAdjust,this),this.menu=new a.utils.menu({}),this.listenTo(this.menu,"activate_context",this.activateContextMenu),this.config.loadOnAttach&&this.on("builder_attached_to_editor",function(){this.displayAttachedBuilder({confirm:!1})},this),this},render:function(){return this.setElement(this.template()),this.$el.attr("id","siteorigin-panels-builder-"+this.cid).addClass("so-builder-container"),this.trigger("builder_rendered"),this},attach:function(e){(e=_.extend({container:!1,dialog:!1},e)).dialog?(this.dialog=new a.dialog.builder,this.dialog.builder=this):(this.$el.appendTo(e.container),this.metabox=e.container.closest(".postbox"),this.initSortable(),this.trigger("attached_to_container",e.container)),this.trigger("builder_attached"),this.supports("liveEditor")&&this.addLiveEditor(),this.supports("history")&&this.addHistoryBrowser();var t=this.$(".so-builder-toolbar"),i=this.$(".so-panels-welcome-message"),s=panelsOptions.loc.welcomeMessage,l=[];this.supports("addWidget")?l.push(s.addWidgetButton):t.find(".so-widget-add").hide(),this.supports("addRow")?l.push(s.addRowButton):t.find(".so-row-add").hide(),this.supports("prebuilt")?l.push(s.addPrebuiltButton):t.find(".so-prebuilt-add").hide();var o="";3===l.length?o=s.threeEnabled:2===l.length?o=s.twoEnabled:1===l.length?o=s.oneEnabled:0===l.length&&(o=s.addingDisabled);var n=_.template(a.helpers.utils.processTemplate(o))({items:l})+" "+s.docsMessage;return i.find(".so-message-wrapper").html(n),this},attachToEditor:function(){if("tinyMCE"!==this.config.editorType)return this;this.attachedToEditor=!0;var t=this.metabox,l=this;n("#wp-content-wrap .wp-editor-tabs").find(".wp-switch-editor").click(function(e){e.preventDefault(),n("#wp-content-editor-container").show(),n("#wp-content-wrap").removeClass("panels-active"),n("#content-resize-handle").show(),l.trigger("hide_builder")}).end().append(n('<button type="button" id="content-panels" class="hide-if-no-js wp-switch-editor switch-panels">'+t.find(".hndle span").html()+"</button>").click(function(e){l.displayAttachedBuilder({confirm:!0})&&e.preventDefault()})),this.supports("revertToEditor")&&t.find(".so-switch-to-standard").click(function(e){e.preventDefault(),confirm(panelsOptions.loc.confirm_stop_builder)&&(l.addHistoryEntry("back_to_editor"),l.model.loadPanelsData(!1),n("#wp-content-wrap").show(),t.hide(),n(window).resize(),l.attachedVisible=!1,l.trigger("hide_builder"))}).show(),t.insertAfter("#wp-content-wrap").hide().addClass("attached-to-editor");var e=this.model.get("data");_.isEmpty(e.widgets)&&_.isEmpty(e.grids)&&this.supports("revertToEditor")||this.displayAttachedBuilder({confirm:!1});var i=function(){var e=l.$(".so-builder-toolbar");if(l.$el.hasClass("so-display-narrow"))return e.css({top:0,left:0,width:"100%",position:"absolute"}),void l.$el.css("padding-top",e.outerHeight());var t=n(window).scrollTop()-l.$el.offset().top;"fixed"===n("#wpadminbar").css("position")&&(t+=n("#wpadminbar").outerHeight());var i=0,s=l.$el.outerHeight()-e.outerHeight()+20;i<t&&t<s?"fixed"!==e.css("position")&&e.css({top:n("#wpadminbar").outerHeight(),left:l.$el.offset().left,width:l.$el.outerWidth(),position:"fixed"}):e.css({top:Math.min(Math.max(t,0),l.$el.outerHeight()-e.outerHeight()+20),left:0,width:"100%",position:"absolute"}),l.$el.css("padding-top",e.outerHeight())};return this.on("builder_resize",i,this),n(document).scroll(i),i(),this.trigger("builder_attached_to_editor"),this},displayAttachedBuilder:function(e){if((e=_.extend({confirm:!0},e)).confirm){var t="undefined"!=typeof tinyMCE&&tinyMCE.get("content");if(""!==(t&&_.isFunction(t.getContent)?t.getContent():n("textarea#content").val())&&!confirm(panelsOptions.loc.confirm_use_builder))return!1}return n("#wp-content-wrap").hide(),n("#editor-expand-toggle").on("change.editor-expand",function(){n(this).prop("checked")||n("#wp-content-wrap").hide()}),this.metabox.show().find("> .inside").show(),n(window).resize(),n(document).scroll(),this.attachedVisible=!0,this.trigger("display_builder"),!0},initSortable:function(){if(!this.supports("moveRow"))return this;var o=this,e=o.$el.attr("id");return this.rowsSortable=this.$(".so-rows-container").sortable({appendTo:"#wpwrap",items:".so-row-container",handle:".so-row-move",connectWith:"#"+e+".so-rows-container,.block-editor .so-rows-container",axis:"y",tolerance:"pointer",scroll:!1,remove:function(e,t){o.model.get("rows").remove(n(t.item).data("view").model,{silent:!0}),o.model.refreshPanelsData()},receive:function(e,t){o.model.get("rows").add(n(t.item).data("view").model,{silent:!0,at:n(t.item).index()}),o.model.refreshPanelsData()},stop:function(e,t){var i=n(t.item),s=i.data("view"),l=o.model.get("rows");l.get(s.model)&&(o.addHistoryEntry("row_moved"),l.remove(s.model,{silent:!0}),l.add(s.model,{silent:!0,at:i.index()}),s.trigger("move",i.index()),o.model.refreshPanelsData())}}),this},refreshSortable:function(){_.isNull(this.rowsSortable)||this.rowsSortable.sortable("refresh")},setDataField:function(e,t){if(t=_.extend({load:!0},t),this.dataField=e,this.dataField.data("builder",this),t.load&&""!==e.val()){var i=this.dataField.val();try{i=JSON.parse(i)}catch(e){console.log("Failed to parse Page Builder layout data from supplied data field."),i={}}this.setData(i)}return this},setData:function(e){this.model.loadPanelsData(e),this.currentData=e,this.toggleWelcomeDisplay()},getData:function(){return this.model.get("data")},storeModelData:function(){var e=JSON.stringify(this.model.get("data"));n(this.dataField).val()!==e&&(n(this.dataField).val(e),n(this.dataField).trigger("change"),this.trigger("content_change"))},onAddRow:function(e,t,i){i=_.extend({noAnimate:!1},i);var s=new a.view.row({model:e});s.builder=this,s.render(),_.isUndefined(i.at)||t.length<=1?s.$el.appendTo(this.$(".so-rows-container")):s.$el.insertAfter(this.$(".so-rows-container .so-row-container").eq(i.at-1)),!1===i.noAnimate&&s.visualCreate(),this.refreshSortable(),s.resize(),this.trigger("row_added")},displayAddWidgetDialog:function(){this.dialogs.widgets.openDialog()},displayAddRowDialog:function(){var t=new a.model.row,e=new a.collection.cells([{weight:.5},{weight:.5}]);e.each(function(e){e.row=t}),t.set("cells",e),t.builder=this.model,this.dialogs.row.setRowModel(t),this.dialogs.row.openDialog()},displayAddPrebuiltDialog:function(){this.dialogs.prebuilt.openDialog()},displayHistoryDialog:function(){this.dialogs.history.openDialog()},pasteRowHandler:function(){var e=a.helpers.clipboard.getModel("row-model");!_.isEmpty(e)&&e instanceof a.model.row&&(this.addHistoryEntry("row_pasted"),e.builder=this.model,this.model.get("rows").add(e,{at:this.model.get("rows").indexOf(this.model)+1}),this.model.refreshPanelsData())},getActiveCell:function(e){if(e=_.extend({createCell:!0},e),!this.model.get("rows").length){if(!e.createCell)return null;this.model.addRow({},[{weight:1}],{noAnimate:!0})}var t=this.activeCell;return _.isEmpty(t)||-1===this.model.get("rows").indexOf(t.model.row)?this.model.get("rows").last().get("cells").first():t.model},addLiveEditor:function(){return _.isEmpty(this.config.liveEditorPreview)||(this.liveEditor=new a.view.liveEditor({builder:this,previewUrl:this.config.liveEditorPreview}),this.liveEditor.hasPreviewUrl()&&this.$(".so-builder-toolbar .so-live-editor").show(),this.trigger("builder_live_editor_added")),this},displayLiveEditor:function(){_.isUndefined(this.liveEditor)||this.liveEditor.open()},addHistoryBrowser:function(){if(_.isEmpty(this.config.liveEditorPreview))return this;this.dialogs.history=new a.dialog.history,(this.dialogs.history.builder=this).dialogs.history.entries.builder=this.model,this.dialogs.history.setRevertEntry(this.model),this.$(".so-builder-toolbar .so-history").show()},addHistoryEntry:function(e,t){_.isUndefined(t)&&(t=null),_.isUndefined(this.dialogs.history)||this.dialogs.history.entries.addEntry(e,t)},supports:function(e){return"rowAction"===e?this.supports("addRow")||this.supports("editRow")||this.supports("deleteRow"):"widgetAction"===e?this.supports("addWidget")||this.supports("editWidget")||this.supports("deleteWidget"):!_.isUndefined(this.config.builderSupports[e])&&this.config.builderSupports[e]},handleContentChange:function(){if(panelsOptions.copy_content&&this.attachedToEditor&&this.$el.is(":visible")){var e=this.model.getPanelsData();_.isEmpty(e.widgets)||n.post(panelsOptions.ajaxurl,{action:"so_panels_builder_content",panels_data:JSON.stringify(e),post_id:this.config.postId},function(e){""!==e&&this.updateEditorContent(e)}.bind(this))}},updateEditorContent:function(e){if("tinyMCE"!==this.config.editorType||"undefined"==typeof tinyMCE||_.isNull(tinyMCE.get("content"))){n(this.config.editorId).val(e).trigger("change").trigger("keyup")}else{var t=tinyMCE.get("content");t.setContent(e),t.fire("change"),t.fire("keyup")}this.triggerYoastSeoChange()},triggerYoastSeoChange:function(){if(n("#yoast_wpseo_focuskw_text_input").length){var e,t=document.getElementById("yoast_wpseo_focuskw_text_input");document.createEvent?(e=document.createEvent("HTMLEvents")).initEvent("keyup",!0,!0):(e=document.createEventObject()).eventType="keyup",e.eventName="keyup",document.createEvent?t.dispatchEvent(e):t.fireEvent("on"+e.eventType,e)}},handleDisplayBuilder:function(){var e="undefined"!=typeof tinyMCE&&tinyMCE.get("content"),t=e&&_.isFunction(e.getContent)?e.getContent():n("textarea#content").val();if((_.isEmpty(this.model.get("data"))||_.isEmpty(this.model.get("data").widgets)&&_.isEmpty(this.model.get("data").grids))&&""!==t){var i=panelsOptions.text_widget;if(_.isEmpty(i))return;this.model.loadPanelsData(this.model.getPanelsDataFromHtml(t,i)),this.model.trigger("change"),this.model.trigger("change:data")}n("#post-status-info").addClass("for-siteorigin-panels")},handleHideBuilder:function(){n("#post-status-info").show().removeClass("for-siteorigin-panels")},wrapEditorExpandAdjust:function(){try{for(var t,e=(n.hasData(window)&&n._data(window)).events.scroll,i=0;i<e.length;i++)if("editor-expand"===e[i].namespace){t=e[i],n(window).unbind("scroll",t.handler),n(window).bind("scroll",function(e){this.attachedVisible||t.handler(e)}.bind(this));break}}catch(e){return}},handleBuilderSizing:function(){var e=this.$el.width();return e&&(e<575?this.$el.addClass("so-display-narrow"):this.$el.removeClass("so-display-narrow")),this},setDialogParents:function(s,l){_.each(this.dialogs,function(e,t,i){i[t].setParent(s,l)}),this.on("add_dialog",function(e){e.setParent(s,l)},this)},toggleWelcomeDisplay:function(){this.model.get("rows").isEmpty()?this.$(".so-panels-welcome-message").show():this.$(".so-panels-welcome-message").hide()},activateContextMenu:function(t,i){var e=this;if(n.contains(e.$el.get(0),t.target)){var s=n([]).add(e.$(".so-panels-welcome-message:visible")).add(e.$(".so-rows-container > .so-row-container")).add(e.$(".so-cells > .cell")).add(e.$(".cell-wrapper > .so-widget")).filter(function(e){return i.isOverEl(n(this),t)}),l=s.last().data("view");void 0!==l&&void 0!==l.buildContextualMenu?l.buildContextualMenu(t,i):s.last().hasClass("so-panels-welcome-message")&&this.buildContextualMenu(t,i)}},buildContextualMenu:function(e,t){var i={};this.supports("addRow")&&(i.add_row={title:panelsOptions.loc.contextual.add_row}),a.helpers.clipboard.canCopyPaste()&&a.helpers.clipboard.isModel("row-model")&&this.supports("addRow")&&(i.paste_row={title:panelsOptions.loc.contextual.row_paste}),_.isEmpty(i)||t.addSection("builder-actions",{sectionTitle:panelsOptions.loc.contextual.row_actions,search:!1},i,function(e){switch(e){case"add_row":this.displayAddRowDialog();break;case"paste_row":this.pasteRowHandler()}}.bind(this))}})},{}],24:[function(e,t,i){var l=window.panels,r=jQuery;t.exports=Backbone.View.extend({template:_.template(l.helpers.utils.processTemplate(r("#siteorigin-panels-builder-cell").html())),events:{"click .cell-wrapper":"handleCellClick"},row:null,widgetSortable:null,initialize:function(){this.listenTo(this.model.get("widgets"),"add",this.onAddWidget)},render:function(){var e={weight:this.model.get("weight"),totalWeight:this.row.model.get("cells").totalWeight()};this.setElement(this.template(e)),this.$el.data("view",this);var i=this;return this.model.get("widgets").each(function(e){var t=new l.view.widget({model:e});t.cell=i,t.render(),t.$el.appendTo(i.$(".widgets-container"))}),this.initSortable(),this.initResizable(),this},initSortable:function(){if(!this.row.builder.supports("moveWidget"))return this;var o=this,e=o.row.builder,t=e.$el.attr("id"),n=e.model;return this.widgetSortable=this.$(".widgets-container").sortable({placeholder:"so-widget-sortable-highlight",connectWith:"#"+t+" .so-cells .cell .widgets-container,.block-editor .so-cells .cell .widgets-container",tolerance:"pointer",scroll:!1,over:function(e,t){o.row.builder.trigger("widget_sortable_move")},remove:function(e,t){o.model.get("widgets").remove(r(t.item).data("view").model,{silent:!0}),n.refreshPanelsData()},receive:function(e,t){var i=r(t.item).data("view").model;i.cell=o.model,o.model.get("widgets").add(i,{silent:!0,at:r(t.item).index()}),n.refreshPanelsData()},stop:function(e,t){var i=r(t.item),s=i.data("view"),l=i.closest(".cell").data("view");o.model.get("widgets").get(s.model)&&(o.row.builder.addHistoryEntry("widget_moved"),s.model.moveToCell(l.model,{},i.index()),s.cell=l,n.refreshPanelsData())},helper:function(e,t){var i=t.clone().css({width:t.outerWidth(),"z-index":1e4,position:"fixed"}).addClass("widget-being-dragged").appendTo("body");return 720<t.outerWidth()&&i.animate({"margin-left":e.pageX-t.offset().left-240,width:480},"fast"),i}}),this},refreshSortable:function(){_.isNull(this.widgetSortable)||this.widgetSortable.sortable("refresh")},initResizable:function(){if(!this.row.builder.supports("editRow"))return this;var o,n=this.$(".resize-handle").css("position","absolute"),e=this.row.$el,a=this;return n.draggable({axis:"x",containment:e,start:function(e,t){if(o=a.$el.prev().data("view"),!_.isUndefined(o)){var i=a.$el.clone().appendTo(t.helper).css({position:"absolute",top:"0",width:a.$el.outerWidth(),left:5,height:a.$el.outerHeight()});i.find(".resize-handle").remove();var s=o.$el.clone().appendTo(t.helper).css({position:"absolute",top:"0",width:o.$el.outerWidth(),right:5,height:o.$el.outerHeight()});s.find(".resize-handle").remove(),r(this).data({newCellClone:i,prevCellClone:s})}},drag:function(e,t){var i=a.row.$el.width()+10,s=a.model.get("weight")-(t.position.left+n.outerWidth()/2)/i,l=o.model.get("weight")+(t.position.left+n.outerWidth()/2)/i;r(this).data("newCellClone").css("width",i*s).find(".preview-cell-weight").html(Math.round(1e3*s)/10),r(this).data("prevCellClone").css("width",i*l).find(".preview-cell-weight").html(Math.round(1e3*l)/10)},stop:function(e,t){r(this).data("newCellClone").remove(),r(this).data("prevCellClone").remove();var i=a.row.$el.width()+10,s=a.model.get("weight")-(t.position.left+n.outerWidth()/2)/i,l=o.model.get("weight")+(t.position.left+n.outerWidth()/2)/i;.02<s&&.02<l&&(a.row.builder.addHistoryEntry("cell_resized"),a.model.set("weight",s),o.model.set("weight",l),a.row.resize()),t.helper.css("left",-n.outerWidth()/2),a.row.builder.model.refreshPanelsData()}}),this},onAddWidget:function(e,t,i){i=_.extend({noAnimate:!1},i);var s=new l.view.widget({model:e});s.cell=this,_.isUndefined(e.isDuplicate)&&(e.isDuplicate=!1),s.render({loadForm:e.isDuplicate}),_.isUndefined(i.at)||t.length<=1?s.$el.appendTo(this.$(".widgets-container")):s.$el.insertAfter(this.$(".widgets-container .so-widget").eq(i.at-1)),!1===i.noAnimate&&s.visualCreate(),this.refreshSortable(),this.row.resize(),this.row.builder.trigger("widget_added")},handleCellClick:function(e){this.row.builder.$el.find(".so-cells .cell").removeClass("cell-selected"),this.row.builder.activeCell!==this||this.model.get("widgets").length?(this.$el.addClass("cell-selected"),this.row.builder.activeCell=this):this.row.builder.activeCell=null},pasteHandler:function(){var e=l.helpers.clipboard.getModel("widget-model");!_.isEmpty(e)&&e instanceof l.model.widget&&(this.row.builder.addHistoryEntry("widget_pasted"),e.cell=this.model,this.model.get("widgets").add(e),this.row.builder.model.refreshPanelsData())},buildContextualMenu:function(e,t){var i=this;t.hasSection("add-widget-below")||t.addSection("add-widget-cell",{sectionTitle:panelsOptions.loc.contextual.add_widget_cell,searchPlaceholder:panelsOptions.loc.contextual.search_widgets,defaultDisplay:panelsOptions.contextual.default_widgets},panelsOptions.widgets,function(e){i.row.builder.trigger("before_user_adds_widget"),i.row.builder.addHistoryEntry("widget_added");var t=new l.model.widget({class:e});t.cell=i.model,t.cell.get("widgets").add(t),i.row.builder.model.refreshPanelsData(),i.row.builder.trigger("after_user_adds_widget",t)});var s={};this.row.builder.supports("addWidget")&&l.helpers.clipboard.isModel("widget-model")&&(s.paste={title:panelsOptions.loc.contextual.cell_paste_widget}),_.isEmpty(s)||t.addSection("cell-actions",{sectionTitle:panelsOptions.loc.contextual.cell_actions,search:!1},s,function(e){switch(e){case"paste":this.pasteHandler()}this.row.builder.model.refreshPanelsData()}.bind(this)),this.row.buildContextualMenu(e,t)}})},{}],25:[function(e,t,i){var o=window.panels,d=jQuery;t.exports=Backbone.View.extend({dialogTemplate:_.template(o.helpers.utils.processTemplate(d("#siteorigin-panels-dialog").html())),dialogTabTemplate:_.template(o.helpers.utils.processTemplate(d("#siteorigin-panels-dialog-tab").html())),tabbed:!1,rendered:!1,builder:!1,className:"so-panels-dialog-wrapper",dialogClass:"",dialogIcon:"",parentDialog:!1,dialogOpen:!1,editableLabel:!1,events:{"click .so-close":"closeDialog","click .so-nav.so-previous":"navToPrevious","click .so-nav.so-next":"navToNext"},initialize:function(){this.once("open_dialog",this.render),this.once("open_dialog",this.attach),this.once("open_dialog",this.setDialogClass),this.trigger("initialize_dialog",this),_.isUndefined(this.initializeDialog)||this.initializeDialog(),_.bindAll(this,"initSidebars","hasSidebar","onResize","toggleLeftSideBar","toggleRightSideBar")},getNextDialog:function(){return null},getPrevDialog:function(){return null},setDialogClass:function(){""!==this.dialogClass&&this.$(".so-panels-dialog").addClass(this.dialogClass)},setBuilder:function(e){return(this.builder=e).trigger("add_dialog",this,this.builder),this},attach:function(){return this.$el.appendTo("body"),this},parseDialogContent:function(e,t){t=_.extend({cid:this.cid},t);var i=d(_.template(o.helpers.utils.processTemplate(e))(t)),s={title:i.find(".title").html(),buttons:i.find(".buttons").html(),content:i.find(".content").html()};return i.has(".left-sidebar")&&(s.left_sidebar=i.find(".left-sidebar").html()),i.has(".right-sidebar")&&(s.right_sidebar=i.find(".right-sidebar").html()),s},renderDialog:function(e){if(e=_.extend({editableLabel:this.editableLabel,dialogIcon:this.dialogIcon},e),this.$el.html(this.dialogTemplate(e)).hide(),this.$el.data("view",this),this.$el.addClass("so-panels-dialog-wrapper"),!1!==this.parentDialog){var t=d('<h3 class="so-parent-link"></h3>').html(this.parentDialog.text+'<div class="so-separator"></div>');t.click(function(e){e.preventDefault(),this.closeDialog(),this.parentDialog.dialog.openDialog()}.bind(this)),this.$(".so-title-bar .so-title").before(t)}return this.$(".so-title-bar .so-title-editable").length&&this.initEditableLabel(),setTimeout(this.initSidebars,1),this},initSidebars:function(){var e=this.$(".so-show-left-sidebar").hide(),t=this.$(".so-show-right-sidebar").hide(),i=this.hasSidebar("left"),s=this.hasSidebar("right");(i||s)&&(d(window).on("resize",this.onResize),i&&(e.show(),e.on("click",this.toggleLeftSideBar)),s&&(t.show(),t.on("click",this.toggleRightSideBar))),this.onResize()},initTabs:function(){var e=this.$(".so-sidebar-tabs li a");if(0===e.length)return this;var l=this;return e.click(function(e){e.preventDefault();var t=d(this);l.$(".so-sidebar-tabs li").removeClass("tab-active"),l.$(".so-content .so-content-tabs > *").hide(),t.parent().addClass("tab-active");var i=t.attr("href");if(!_.isUndefined(i)&&"#"===i.charAt(0)){var s=i.split("#")[1];l.$(".so-content .so-content-tabs .tab-"+s).show()}l.trigger("tab_click",t)}),this.$(".so-sidebar-tabs li a").first().click(),this},initToolbar:function(){this.$(".so-toolbar .so-buttons .so-toolbar-button").click(function(e){e.preventDefault(),this.trigger("button_click",d(e.currentTarget))}.bind(this)),this.$(".so-toolbar .so-buttons .so-dropdown-button").click(function(e){e.preventDefault();var t=d(e.currentTarget).siblings(".so-dropdown-links-wrapper");t.is(".hidden")?t.removeClass("hidden"):t.addClass("hidden")}.bind(this)),d("html").click(function(l){this.$(".so-dropdown-links-wrapper").not(".hidden").each(function(e,t){var i=d(t),s=d(l.target);0!==s.length&&(s.is(".so-needs-confirm")&&!s.is(".so-confirmed")||s.is(".so-dropdown-button"))||i.addClass("hidden")})}.bind(this))},initEditableLabel:function(){var l=this.$(".so-title-bar .so-title-editable");l.keypress(function(e){var t="keypress"===e.type&&13===e.keyCode;if(t){var i=d(":tabbable"),s=i.index(l);i.eq(s+1).focus(),window.getSelection().removeAllRanges()}return!t}).blur(function(){var e=l.text().replace(/^\s+|\s+$/gm,"");e!==l.data("original-value").replace(/^\s+|\s+$/gm,"")&&(l.text(e),this.trigger("edit_label",e))}.bind(this)),l.focus(function(){l.data("original-value",l.text()),o.helpers.utils.selectElementContents(this)})},setupDialog:function(){this.openDialog(),this.closeDialog()},refreshDialogNav:function(){this.$(".so-title-bar .so-nav").show().removeClass("so-disabled");var e=this.getNextDialog(),t=this.$(".so-title-bar .so-next"),i=this.getPrevDialog(),s=this.$(".so-title-bar .so-previous");null===e?t.hide():!1===e&&t.addClass("so-disabled"),null===i?s.hide():!1===i&&s.addClass("so-disabled")},openDialog:function(e){(e=_.extend({silent:!1},e)).silent||this.trigger("open_dialog"),this.dialogOpen=!0,this.refreshDialogNav(),o.helpers.pageScroll.lock(),this.onResize(),this.$el.show(),e.silent||(this.trigger("open_dialog_complete"),this.builder.trigger("open_dialog",this),d(document).trigger("open_dialog",this))},closeDialog:function(e){(e=_.extend({silent:!1},e)).silent||this.trigger("close_dialog"),this.dialogOpen=!1,this.$el.hide(),o.helpers.pageScroll.unlock(),e.silent||(this.trigger("close_dialog_complete"),this.builder.trigger("close_dialog",this))},navToPrevious:function(){this.closeDialog();var e=this.getPrevDialog();null!==e&&!1!==e&&e.openDialog()},navToNext:function(){this.closeDialog();var e=this.getNextDialog();null!==e&&!1!==e&&e.openDialog()},getFormValues:function(e){_.isUndefined(e)&&(e=".so-content");var a,t=this.$(e),r={};return t.find("[name]").each(function(){var t=d(this);try{var e=/([A-Za-z_]+)\[(.*)\]/.exec(t.attr("name"));if(_.isEmpty(e))return!0;_.isUndefined(e[2])?a=t.attr("name"):(a=e[2].split("][")).unshift(e[1]),a=a.map(function(e){return!isNaN(parseFloat(e))&&isFinite(e)?parseInt(e):e});var i=r,s=null,l=!!_.isString(t.attr("type"))&&t.attr("type").toLowerCase();if("checkbox"===l)s=t.is(":checked")?""===t.val()||t.val():null;else if("radio"===l){if(!t.is(":checked"))return;s=t.val()}else if("SELECT"===t.prop("tagName")){var o=t.find("option:selected");1===o.length?s=t.find("option:selected").val():1<o.length&&(s=_.map(t.find("option:selected"),function(e,t){return d(e).val()}))}else s=t.val();if(!_.isUndefined(t.data("panels-filter")))switch(t.data("panels-filter")){case"json_parse":try{s=JSON.parse(s)}catch(e){s=""}}if(null!==s)for(var n=0;n<a.length;n++)n===a.length-1?""===a[n]?i.push(s):i[a[n]]=s:(_.isUndefined(i[a[n]])&&(""===a[n+1]?i[a[n]]=[]:i[a[n]]={}),i=i[a[n]])}catch(e){console.log("Field ["+t.attr("name")+"] could not be processed and was skipped - "+e.message)}}),r},setStatusMessage:function(e,t,i){var s=i?'<span class="dashicons dashicons-warning"></span>'+e:e;this.$(".so-toolbar .so-status").html(s),!_.isUndefined(t)&&t?this.$(".so-toolbar .so-status").addClass("so-panels-loading"):this.$(".so-toolbar .so-status").removeClass("so-panels-loading")},setParent:function(e,t){this.parentDialog={text:e,dialog:t}},onResize:function(){var s=window.matchMedia("(max-width: 980px)");["left","right"].forEach(function(e){var t=this.$(".so-"+e+"-sidebar"),i=this.$(".so-show-"+e+"-sidebar");this.hasSidebar(e)?(i.hide(),s.matches?(i.show(),i.closest(".so-title-bar").addClass("so-has-"+e+"-button"),t.hide(),t.closest(".so-panels-dialog").removeClass("so-panels-dialog-has-"+e+"-sidebar")):(i.hide(),i.closest(".so-title-bar").removeClass("so-has-"+e+"-button"),t.show(),t.closest(".so-panels-dialog").addClass("so-panels-dialog-has-"+e+"-sidebar"))):(t.hide(),i.hide())}.bind(this))},hasSidebar:function(e){return 0<this.$(".so-"+e+"-sidebar").children().length},toggleLeftSideBar:function(){this.toggleSidebar("left")},toggleRightSideBar:function(){this.toggleSidebar("right")},toggleSidebar:function(e){var t=this.$(".so-"+e+"-sidebar");t.is(":visible")?t.hide():t.show()}})},{}],26:[function(e,t,i){var s=window.panels,o=jQuery;t.exports=Backbone.View.extend({template:_.template(s.helpers.utils.processTemplate(o("#siteorigin-panels-live-editor").html())),previewScrollTop:0,loadTimes:[],previewFrameId:1,previewUrl:null,previewIframe:null,events:{"click .live-editor-close":"close","click .live-editor-save":"closeAndSave","click .live-editor-collapse":"collapse","click .live-editor-mode":"mobileToggle"},initialize:function(e){e=_.extend({builder:!1,previewUrl:!1},e),_.isEmpty(e.previewUrl)&&(e.previewUrl=panelsOptions.ajaxurl+"&action=so_panels_live_editor_preview"),this.builder=e.builder,this.previewUrl=e.previewUrl,this.listenTo(this.builder.model,"refresh_panels_data",this.handleRefreshData),this.listenTo(this.builder.model,"load_panels_data",this.handleLoadData)},render:function(){if(this.setElement(this.template()),this.$el.hide(),0<o("#submitdiv #save-post").length){var e=this.$el.find(".live-editor-save");e.text(e.data("save"))}var t=!1;o(document).mousedown(function(){t=!0}).mouseup(function(){t=!1});var i=this;return this.$el.on("mouseenter",".so-widget-wrapper",function(){var e=o(this).data("live-editor-preview-widget");t||void 0===e||!e.length||i.$(".so-preview-overlay").is(":visible")||(i.highlightElement(e),i.scrollToElement(e))}),this.$el.on("mouseleave",".so-widget-wrapper",function(){this.resetHighlights()}.bind(this)),this.listenTo(this.builder,"open_dialog",function(){this.resetHighlights()}),this},attach:function(){this.$el.appendTo("body")},open:function(){if(""===this.$el.html()&&this.render(),0===this.$el.closest("body").length&&this.attach(),s.helpers.pageScroll.lock(),this.$el.is(":visible"))return this;if(this.$el.show(),this.refreshPreview(this.builder.model.getPanelsData()),this.originalContainer=this.builder.$el.parent(),this.builder.$el.appendTo(this.$(".so-live-editor-builder")),this.builder.$(".so-tool-button.so-live-editor").hide(),this.builder.trigger("builder_resize"),"auto-draft"===o("#original_post_status").val()&&!this.autoSaved){var e=this;wp.autosave&&(""===o('#title[name="post_title"]').val()&&o('#title[name="post_title"]').val(panelsOptions.loc.draft).trigger("keydown"),o(document).one("heartbeat-tick.autosave",function(){e.autoSaved=!0,e.refreshPreview(e.builder.model.getPanelsData())}),wp.autosave.server.triggerSave())}},close:function(){if(!this.$el.is(":visible"))return this;this.$el.hide(),s.helpers.pageScroll.unlock(),this.builder.$el.appendTo(this.originalContainer),this.builder.$(".so-tool-button.so-live-editor").show(),this.builder.trigger("builder_resize")},closeAndSave:function(){this.close(),o('#submitdiv input[type="submit"][name="save"]').click()},collapse:function(){this.$el.toggleClass("so-collapsed")},highlightElement:function(e){_.isUndefined(this.resetHighlightTimeout)||clearTimeout(this.resetHighlightTimeout),this.previewIframe.contents().find("body").find(".panel-grid .panel-grid-cell .so-panel").filter(function(){return 0===o(this).parents(".so-panel").length}).not(e).addClass("so-panels-faded"),e.removeClass("so-panels-faded").addClass("so-panels-highlighted")},resetHighlights:function(){var e=this.previewIframe.contents().find("body");this.resetHighlightTimeout=setTimeout(function(){e.find(".panel-grid .panel-grid-cell .so-panel").removeClass("so-panels-faded so-panels-highlighted")},100)},scrollToElement:function(e){this.$(".so-preview iframe")[0].contentWindow.liveEditorScrollTo(e)},handleRefreshData:function(e){if(!this.$el.is(":visible"))return this;this.refreshPreview(e)},handleLoadData:function(){if(!this.$el.is(":visible"))return this;this.refreshPreview(this.builder.model.getPanelsData())},refreshPreview:function(e){var t=this.loadTimes.length?_.reduce(this.loadTimes,function(e,t){return e+t},0)/this.loadTimes.length:1e3;_.isNull(this.previewIframe)||this.$(".so-preview-overlay").is(":visible")||(this.previewScrollTop=this.previewIframe.contents().scrollTop()),this.$(".so-preview-overlay").show(),this.$(".so-preview-overlay .so-loading-bar").clearQueue().css("width","0%").animate({width:"100%"},parseInt(t)+100),this.postToIframe({live_editor_panels_data:JSON.stringify(e),live_editor_post_ID:this.builder.config.postId},this.previewUrl,this.$(".so-preview")),this.previewIframe.data("load-start",(new Date).getTime())},postToIframe:function(e,t,i){_.isNull(this.previewIframe)||this.previewIframe.remove();var s="siteorigin-panels-live-preview-"+this.previewFrameId;this.previewIframe=o('<iframe src="javascript:false;" />').attr({id:s,name:s}).appendTo(i),this.setupPreviewFrame(this.previewIframe);var l=o('<form id="soPostToPreviewFrame" method="post" />').attr({id:s,target:this.previewIframe.attr("id"),action:t}).appendTo("body");return o.each(e,function(e,t){o('<input type="hidden" />').attr({name:e,value:t}).appendTo(l)}),l.submit().remove(),this.previewFrameId++,this.previewIframe},setupPreviewFrame:function(e){var l=this;e.data("iframeready",!1).on("iframeready",function(){var e=o(this),t=e.contents();if(!e.data("iframeready")){e.data("iframeready",!0),void 0!==e.data("load-start")&&(l.loadTimes.unshift((new Date).getTime()-e.data("load-start")),_.isEmpty(l.loadTimes)||(l.loadTimes=l.loadTimes.slice(0,4))),setTimeout(function(){t.scrollTop(l.previewScrollTop),l.$(".so-preview-overlay").hide()},100);var i=t.find("#pl-"+l.builder.config.postId);i.find(".panel-grid .panel-grid-cell .so-panel").filter(function(){return o(this).closest(".panel-layout").is(i)}).each(function(e,t){var i=o(t),s=l.$(".so-live-editor-builder .so-widget-wrapper").eq(i.data("index"));s.data("live-editor-preview-widget",i),i.css({cursor:"pointer"}).mouseenter(function(){s.parent().addClass("so-hovered"),l.highlightElement(i)}).mouseleave(function(){s.parent().removeClass("so-hovered"),l.resetHighlights()}).click(function(e){e.preventDefault(),s.find(".title h4").click()})}),t.find("a").css({"pointer-events":"none"}).click(function(e){e.preventDefault()})}}).on("load",function(){var e=o(this);e.data("iframeready")||e.trigger("iframeready")})},hasPreviewUrl:function(){return""!==this.$("form.live-editor-form").attr("action")},mobileToggle:function(e){var t=o(e.currentTarget);this.$(".live-editor-mode").not(t).removeClass("so-active"),t.addClass("so-active"),this.$el.removeClass("live-editor-desktop-mode live-editor-tablet-mode live-editor-mobile-mode").addClass("live-editor-"+t.data("mode")+"-mode")}})},{}],27:[function(e,t,i){var n=window.panels,l=jQuery;t.exports=Backbone.View.extend({template:_.template(n.helpers.utils.processTemplate(l("#siteorigin-panels-builder-row").html())),events:{"click .so-row-settings":"editSettingsHandler","click .so-row-duplicate":"duplicateHandler","click .so-row-delete":"confirmedDeleteHandler","click .so-row-color":"rowColorChangeHandler"},builder:null,dialog:null,initialize:function(){var e=this.model.get("cells");this.listenTo(e,"add",this.handleCellAdd),this.listenTo(e,"remove",this.handleCellRemove),this.listenTo(this.model,"reweight_cells",this.resize),this.listenTo(this.model,"destroy",this.onModelDestroy);var t=this;e.each(function(e){t.listenTo(e.get("widgets"),"add",t.resize)}),e.on("add",function(e){t.listenTo(e.get("widgets"),"add",t.resize)},this),this.listenTo(this.model,"change:label",this.onLabelChange)},render:function(){var e=this.model.has("color_label")?this.model.get("color_label"):1,t=this.model.has("label")?this.model.get("label"):"";this.setElement(this.template({rowColorLabel:e,rowLabel:t})),this.$el.data("view",this);var i=this;return this.model.get("cells").each(function(e){var t=new n.view.cell({model:e});t.row=i,t.render(),t.$el.appendTo(i.$(".so-cells"))}),this.builder.supports("rowAction")?(this.builder.supports("editRow")||(this.$(".so-row-toolbar .so-dropdown-links-wrapper .so-row-settings").parent().remove(),this.$el.addClass("so-row-no-edit")),this.builder.supports("addRow")||(this.$(".so-row-toolbar .so-dropdown-links-wrapper .so-row-duplicate").parent().remove(),this.$el.addClass("so-row-no-duplicate")),this.builder.supports("deleteRow")||(this.$(".so-row-toolbar .so-dropdown-links-wrapper .so-row-delete").parent().remove(),this.$el.addClass("so-row-no-delete"))):(this.$(".so-row-toolbar .so-dropdown-wrapper").remove(),this.$el.addClass("so-row-no-actions")),this.builder.supports("moveRow")||(this.$(".so-row-toolbar .so-row-move").remove(),this.$el.addClass("so-row-no-move")),l.trim(this.$(".so-row-toolbar").html()).length||this.$(".so-row-toolbar").remove(),this.listenTo(this.builder,"widget_sortable_move",this.resize),this.listenTo(this.builder,"builder_resize",this.resize),this.resize(),this},visualCreate:function(){this.$el.hide().fadeIn("fast")},resize:function(e){if(this.$el.is(":visible")){this.$(".so-cells .cell-wrapper").css("min-height",0),this.$(".so-cells .resize-handle").css("height",0);var t=0;this.$(".so-cells .cell").each(function(){t=Math.max(t,l(this).height()),l(this).css("width",100*l(this).data("view").model.get("weight")+"%")}),this.$(".so-cells .cell-wrapper").css("min-height",Math.max(t,63)),this.$(".so-cells .resize-handle").css("height",this.$(".so-cells .cell-wrapper").outerHeight())}},onModelDestroy:function(){this.remove()},visualDestroyModel:function(){this.builder.addHistoryEntry("row_deleted");var e=this;this.$el.fadeOut("normal",function(){e.model.destroy(),e.builder.model.refreshPanelsData()})},onLabelChange:function(e,t){0==this.$(".so-row-label").length?this.$(".so-row-toolbar").prepend('<h3 class="so-row-label">'+t+"</h3>"):this.$(".so-row-label").text(t)},duplicateHandler:function(){this.builder.addHistoryEntry("row_duplicated");var e=this.model.clone(this.builder.model);this.builder.model.get("rows").add(e,{at:this.builder.model.get("rows").indexOf(this.model)+1}),this.builder.model.refreshPanelsData()},copyHandler:function(){n.helpers.clipboard.setModel(this.model)},pasteHandler:function(){var e=n.helpers.clipboard.getModel("row-model");!_.isEmpty(e)&&e instanceof n.model.row&&(this.builder.addHistoryEntry("row_pasted"),e.builder=this.builder.model,this.builder.model.get("rows").add(e,{at:this.builder.model.get("rows").indexOf(this.model)+1}),this.builder.model.refreshPanelsData())},confirmedDeleteHandler:function(e){var t=l(e.target);if(t.hasClass("dashicons")&&(t=t.parent()),t.hasClass("so-confirmed"))this.visualDestroyModel();else{var i=t.html();t.addClass("so-confirmed").html('<span class="dashicons dashicons-yes"></span>'+panelsOptions.loc.dropdown_confirm),setTimeout(function(){t.removeClass("so-confirmed").html(i)},2500)}},editSettingsHandler:function(){if(this.builder.supports("editRow"))return null===this.dialog&&(this.dialog=new n.dialog.row,this.dialog.setBuilder(this.builder).setRowModel(this.model),this.dialog.rowView=this),this.dialog.openDialog(),this},deleteHandler:function(){return this.model.destroy(),this},rowColorChangeHandler:function(e){this.$(".so-row-color").removeClass("so-row-color-selected");var t=l(e.target),i=t.data("color-label"),s=this.model.has("color_label")?this.model.get("color_label"):1;t.addClass("so-row-color-selected"),this.$el.removeClass("so-row-color-"+s),this.$el.addClass("so-row-color-"+i),this.model.set("color_label",i)},handleCellAdd:function(e){var t=new n.view.cell({model:e});t.row=this,t.render(),t.$el.appendTo(this.$(".so-cells"))},handleCellRemove:function(t){this.$(".so-cells > .cell").each(function(){var e=l(this).data("view");_.isUndefined(e)||e.model.cid===t.cid&&e.remove()})},buildContextualMenu:function(e,t){for(var i=[],s=1;s<5;s++)i.push({title:s+" "+panelsOptions.loc.contextual.column});this.builder.supports("addRow")&&t.addSection("add-row",{sectionTitle:panelsOptions.loc.contextual.add_row,search:!1},i,function(e){this.builder.addHistoryEntry("row_added");for(var t=Number(e)+1,i=[],s=0;s<t;s++)i.push({weight:100/t});var l=new n.model.row({collection:this.collection}),o=new n.collection.cells(i);o.each(function(e){e.row=l}),l.setCells(o),l.builder=this.builder.model,this.builder.model.get("rows").add(l,{at:this.builder.model.get("rows").indexOf(this.model)+1}),this.builder.model.refreshPanelsData()}.bind(this));var l={};this.builder.supports("editRow")&&(l.edit={title:panelsOptions.loc.contextual.row_edit}),n.helpers.clipboard.canCopyPaste()&&(l.copy={title:panelsOptions.loc.contextual.row_copy},this.builder.supports("addRow")&&n.helpers.clipboard.isModel("row-model")&&(l.paste={title:panelsOptions.loc.contextual.row_paste})),this.builder.supports("addRow")&&(l.duplicate={title:panelsOptions.loc.contextual.row_duplicate}),this.builder.supports("deleteRow")&&(l.delete={title:panelsOptions.loc.contextual.row_delete,confirm:!0}),_.isEmpty(l)||t.addSection("row-actions",{sectionTitle:panelsOptions.loc.contextual.row_actions,search:!1},l,function(e){switch(e){case"edit":this.editSettingsHandler();break;case"copy":this.copyHandler();break;case"paste":this.pasteHandler();break;case"duplicate":this.duplicateHandler();break;case"delete":this.visualDestroyModel()}}.bind(this))}})},{}],28:[function(e,t,i){window.panels;var d=jQuery;t.exports=Backbone.View.extend({stylesLoaded:!1,initialize:function(){},render:function(e,t,i){if(!_.isUndefined(e)){i=_.extend({builderType:"",dialog:null},i),this.$el.addClass("so-visual-styles so-"+e+"-styles so-panels-loading");var s={builderType:i.builderType};return"cell"===e&&(s.index=i.index),d.post(panelsOptions.ajaxurl,{action:"so_panels_style_form",type:e,style:this.model.get("style"),args:JSON.stringify(s),postId:t},null,"html").done(function(e){this.$el.html(e),this.setupFields(),this.stylesLoaded=!0,this.trigger("styles_loaded",!_.isEmpty(e)),_.isNull(i.dialog)||i.dialog.trigger("styles_loaded",!_.isEmpty(e))}.bind(this)).fail(function(e){var t;t=e&&e.responseText?e.responseText:panelsOptions.forms.loadingFailed,this.$el.html(t)}.bind(this)).always(function(){this.$el.removeClass("so-panels-loading")}.bind(this)),this}},attach:function(e){e.append(this.$el)},detach:function(){this.$el.detach()},setupFields:function(){this.$(".style-section-wrapper").each(function(){var t=d(this);t.find(".style-section-head").click(function(e){e.preventDefault(),t.find(".style-section-fields").slideToggle("fast")})}),_.isUndefined(d.fn.wpColorPicker)||(_.isObject(panelsOptions.wpColorPickerOptions.palettes)&&!d.isArray(panelsOptions.wpColorPickerOptions.palettes)&&(panelsOptions.wpColorPickerOptions.palettes=d.map(panelsOptions.wpColorPickerOptions.palettes,function(e){return e})),this.$(".so-wp-color-field").wpColorPicker(panelsOptions.wpColorPickerOptions)),this.$(".style-field-image").each(function(){var s=null,l=d(this);l.find(".so-image-selector").click(function(e){e.preventDefault(),null===s&&(s=wp.media({title:"choose",library:{type:"image"},button:{text:"Done",close:!0}})).on("select",function(){var t=s.state().get("selection").first().attributes,i=t.url;if(!_.isUndefined(t.sizes))try{i=t.sizes.thumbnail.url}catch(e){i=t.sizes.full.url}l.find(".current-image").css("background-image","url("+i+")"),l.find(".so-image-selector > input").val(t.id),l.find(".remove-image").removeClass("hidden")}),s.open()}),l.find(".remove-image").click(function(e){e.preventDefault(),l.find(".current-image").css("background-image","none"),l.find(".so-image-selector > input").val(""),l.find(".remove-image").addClass("hidden")})}),this.$(".style-field-measurement").each(function(){var e=d(this),n=e.find('input[type="text"]'),a=e.find("select"),r=e.find('input[type="hidden"]');n.focus(function(){d(this).select()});!function(e){if(""!==e){var t=/(?:([0-9\.,\-]+)(.*))+/,i=r.val().split(" "),s=[];for(var l in i){var o=t.exec(i[l]);_.isNull(o)||_.isUndefined(o[1])||_.isUndefined(o[2])||(s.push(o[1]),a.val(o[2]))}1===n.length?n.val(s.join(" ")):(1===s.length?s=[s[0],s[0],s[0],s[0]]:2===s.length?s=[s[0],s[1],s[0],s[1]]:3===s.length&&(s=[s[0],s[1],s[2],s[1]]),n.each(function(e,t){d(t).val(s[e])}))}}(r.val());var t=function(e){if(1===n.length){var t=n.val().split(" ").filter(function(e){return""!==e}).map(function(e){return e+a.val()}).join(" ");r.val(t)}else{var i=d(e.target),s=[],l=[],o=[];n.each(function(e,t){var i=""!==d(t).val()?parseFloat(d(t).val()):null;s.push(i),null===i?l.push(e):o.push(e)}),3===l.length&&o[0]===n.index(i)&&(n.val(i.val()),s=[i.val(),i.val(),i.val(),i.val()]),JSON.stringify(s)===JSON.stringify([null,null,null,null])?r.val(""):r.val(s.map(function(e){return(null===e?0:e)+a.val()}).join(" "))}};n.change(t),a.change(t)})}})},{}],29:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({template:_.template(s.helpers.utils.processTemplate(l("#siteorigin-panels-builder-widget").html())),cell:null,dialog:null,events:{"click .widget-edit":"editHandler","click .title h4":"editHandler","click .actions .widget-duplicate":"duplicateHandler","click .actions .widget-delete":"deleteHandler"},initialize:function(){this.listenTo(this.model,"destroy",this.onModelDestroy),this.listenTo(this.model,"change:values",this.onModelChange),this.listenTo(this.model,"change:label",this.onLabelChange)},render:function(e){if(e=_.extend({loadForm:!1},e),this.setElement(this.template({title:this.model.getWidgetField("title"),description:this.model.getTitle(),widget_class:this.model.attributes.class})),this.$el.data("view",this),this.cell.row.builder.supports("editWidget")&&!this.model.get("read_only")||(this.$(".actions .widget-edit").remove(),this.$el.addClass("so-widget-no-edit")),this.cell.row.builder.supports("addWidget")||(this.$(".actions .widget-duplicate").remove(),this.$el.addClass("so-widget-no-duplicate")),this.cell.row.builder.supports("deleteWidget")||(this.$(".actions .widget-delete").remove(),this.$el.addClass("so-widget-no-delete")),this.cell.row.builder.supports("moveWidget")||this.$el.addClass("so-widget-no-move"),l.trim(this.$(".actions").html()).length||this.$(".actions").remove(),this.model.get("read_only")&&this.$el.addClass("so-widget-read-only"),0===_.size(this.model.get("values"))||e.loadForm){var t=this.getEditDialog();t.once("form_loaded",t.saveWidget,t),t.setupDialog()}return this.listenTo(this.cell.row.builder,"after_user_adds_widget",this.afterUserAddsWidgetHandler),this},visualCreate:function(){this.$el.hide().fadeIn("fast")},getEditDialog:function(){return null===this.dialog&&(this.dialog=new s.dialog.widget({model:this.model}),this.dialog.setBuilder(this.cell.row.builder),this.dialog.widgetView=this),this.dialog},editHandler:function(){return!this.cell.row.builder.supports("editWidget")||this.model.get("read_only")||this.getEditDialog().openDialog(),this},duplicateHandler:function(){this.cell.row.builder.addHistoryEntry("widget_duplicated");var e=this.model.clone(this.model.cell);return this.cell.model.get("widgets").add(e,{at:this.model.collection.indexOf(this.model)+1}),this.cell.row.builder.model.refreshPanelsData(),this},copyHandler:function(){s.helpers.clipboard.setModel(this.model)},deleteHandler:function(){return this.visualDestroyModel(),this},onModelChange:function(){this.$(".description").html(this.model.getTitle())},onLabelChange:function(e){this.$(".title > h4").text(e.getWidgetField("title"))},onModelDestroy:function(){this.remove()},visualDestroyModel:function(){return this.cell.row.builder.addHistoryEntry("widget_deleted"),this.$el.fadeOut("fast",function(){this.cell.row.resize(),this.model.destroy(),this.cell.row.builder.model.refreshPanelsData(),this.remove()}.bind(this)),this},buildContextualMenu:function(e,t){this.cell.row.builder.supports("addWidget")&&t.addSection("add-widget-below",{sectionTitle:panelsOptions.loc.contextual.add_widget_below,searchPlaceholder:panelsOptions.loc.contextual.search_widgets,defaultDisplay:panelsOptions.contextual.default_widgets},panelsOptions.widgets,function(e){this.cell.row.builder.trigger("before_user_adds_widget"),this.cell.row.builder.addHistoryEntry("widget_added");var t=new s.model.widget({class:e});t.cell=this.cell.model,this.cell.model.get("widgets").add(t,{at:this.model.collection.indexOf(this.model)+1}),this.cell.row.builder.model.refreshPanelsData(),this.cell.row.builder.trigger("after_user_adds_widget",t)}.bind(this));var i={};this.cell.row.builder.supports("editWidget")&&!this.model.get("read_only")&&(i.edit={title:panelsOptions.loc.contextual.widget_edit}),s.helpers.clipboard.canCopyPaste()&&(i.copy={title:panelsOptions.loc.contextual.widget_copy}),this.cell.row.builder.supports("addWidget")&&(i.duplicate={title:panelsOptions.loc.contextual.widget_duplicate}),this.cell.row.builder.supports("deleteWidget")&&(i.delete={title:panelsOptions.loc.contextual.widget_delete,confirm:!0}),_.isEmpty(i)||t.addSection("widget-actions",{sectionTitle:panelsOptions.loc.contextual.widget_actions,search:!1},i,function(e){switch(e){case"edit":this.editHandler();break;case"copy":this.copyHandler();break;case"duplicate":this.duplicateHandler();break;case"delete":this.visualDestroyModel()}}.bind(this)),this.cell.buildContextualMenu(e,t)},afterUserAddsWidgetHandler:function(e){this.model===e&&panelsOptions.instant_open&&setTimeout(this.editHandler.bind(this),350)}})},{}],30:[function(e,t,i){var a=jQuery,s={addWidget:function(e,t,i){var s=wp.customHtmlWidgets,l=a("<div></div>"),o=t.find(".widget-content:first");o.before(l);var n=new s.CustomHtmlWidgetControl({el:l,syncContainer:o});return n.initializeEditor(),n.editor.codemirror.refresh(),n}};t.exports=s},{}],31:[function(e,t,i){var l=e("./custom-html-widget"),o=e("./media-widget"),n=e("./text-widget"),s={CUSTOM_HTML:"custom_html",MEDIA_AUDIO:"media_audio",MEDIA_GALLERY:"media_gallery",MEDIA_IMAGE:"media_image",MEDIA_VIDEO:"media_video",TEXT:"text",addWidget:function(e,t){var i,s=e.find("> .id_base").val();switch(s){case this.CUSTOM_HTML:i=l;break;case this.MEDIA_AUDIO:case this.MEDIA_GALLERY:case this.MEDIA_IMAGE:case this.MEDIA_VIDEO:i=o;break;case this.TEXT:i=n}i.addWidget(s,e,t)}};t.exports=s},{"./custom-html-widget":30,"./media-widget":32,"./text-widget":33}],32:[function(e,t,i){var h=jQuery,s={addWidget:function(e,t,i){var s=wp.mediaWidgets,l=s.controlConstructors[e];if(l){var o=s.modelConstructors[e]||s.MediaWidgetModel,n=t.find("> .widget-content"),a=h('<div class="media-widget-control"></div>');n.before(a);var r={};n.find(".media-widget-instance-property").each(function(){var e=h(this);r[e.data("property")]=e.val()}),r.widget_id=i;var d=new l({el:a,syncContainer:n,model:new o(r)});return d.render(),d}}};t.exports=s},{}],33:[function(e,t,i){var h=jQuery,s={addWidget:function(e,t,i){var s=wp.textWidgets,l={},o=t.find(".visual");if(0<o.length){if(!o.val())return null;var n=h("<div></div>"),a=t.find(".widget-content:first");a.before(n),l={el:n,syncContainer:a}}else l={el:t};var r=new s.TextWidgetControl(l),d=wp.oldEditor?wp.oldEditor:wp.editor;return d&&d.hasOwnProperty("autop")&&(wp.editor.autop=d.autop,wp.editor.removep=d.removep,wp.editor.initialize=d.initialize),r.initializeEditor(),r}};t.exports=s},{}]},{},[16]);
js/styling-2104.js ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* global _, jQuery */
2
+
3
+ jQuery( function ( $ ) {
4
+
5
+ var fullContainer = $( panelsStyles.fullContainer );
6
+ if ( fullContainer.length === 0 ) {
7
+ fullContainer = $( 'body' );
8
+ }
9
+
10
+ // Stretch all the full width rows
11
+ var stretchFullWidthRows = function () {
12
+ var $panelsRow = $( '.siteorigin-panels-stretch.panel-row-style' );
13
+ $panelsRow.each( function () {
14
+ var $$ = $( this );
15
+
16
+ var stretchType = $$.data( 'stretch-type' );
17
+ var defaultSidePadding = stretchType === 'full-stretched-padded' ? '' : 0;
18
+
19
+ // Reset all the styles associated with row stretching
20
+ $$.css( {
21
+ 'margin-left': 0,
22
+ 'margin-right': 0,
23
+ 'padding-left': defaultSidePadding,
24
+ 'padding-right': defaultSidePadding
25
+ } );
26
+
27
+ var leftSpace = $$.offset().left - fullContainer.offset().left,
28
+ rightSpace = fullContainer.outerWidth() - leftSpace - $$.parent().outerWidth();
29
+
30
+ $$.css( {
31
+ 'margin-left': - leftSpace,
32
+ 'margin-right': - rightSpace,
33
+ 'padding-left': stretchType === 'full' ? leftSpace : defaultSidePadding,
34
+ 'padding-right': stretchType === 'full' ? rightSpace : defaultSidePadding
35
+ } );
36
+
37
+ var cells = $$.find( '> .panel-grid-cell' );
38
+
39
+ if ( stretchType === 'full-stretched' && cells.length === 1 ) {
40
+ cells.css( {
41
+ 'padding-left': 0,
42
+ 'padding-right': 0
43
+ } );
44
+ }
45
+
46
+ $$.css( {
47
+ 'border-left': defaultSidePadding,
48
+ 'border-right': defaultSidePadding
49
+ } );
50
+ } );
51
+
52
+ if ( $panelsRow.length ) {
53
+ $( window ).trigger( 'panelsStretchRows' );
54
+ }
55
+ }
56
+ $( window ).on( 'resize load', stretchFullWidthRows );
57
+ stretchFullWidthRows();
58
+
59
+ // This should have been done in the footer, but run it here just incase.
60
+ $( 'body' ).removeClass( 'siteorigin-panels-before-js' );
61
+
62
+ } );
js/styling-2104.min.js ADDED
@@ -0,0 +1 @@
 
1
+ jQuery(function(a){var d=a(panelsStyles.fullContainer);0===d.length&&(d=a("body"));var e=function(){var e=a(".siteorigin-panels-stretch.panel-row-style");e.each(function(){var e=a(this),t=e.data("stretch-type"),r="full-stretched-padded"===t?"":0;e.css({"margin-left":0,"margin-right":0,"padding-left":r,"padding-right":r});var i=e.offset().left-d.offset().left,n=d.outerWidth()-i-e.parent().outerWidth();e.css({"margin-left":-i,"margin-right":-n,"padding-left":"full"===t?i:r,"padding-right":"full"===t?n:r});var l=e.find("> .panel-grid-cell");"full-stretched"===t&&1===l.length&&l.css({"padding-left":0,"padding-right":0}),e.css({"border-left":r,"border-right":r})}),e.length&&a(window).trigger("panelsStretchRows")};a(window).on("resize load",e),e(),a("body").removeClass("siteorigin-panels-before-js")});
lang/siteorigin-panels.pot CHANGED
@@ -1242,14 +1242,70 @@ msgstr ""
1242
  msgid "Search Settings"
1243
  msgstr ""
1244
 
1245
- #: settings/tpl/settings.php:29
 
 
 
 
1246
  msgid "Settings Saved"
1247
  msgstr ""
1248
 
1249
- #: settings/tpl/settings.php:78
1250
  msgid "Save Settings"
1251
  msgstr ""
1252
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1253
  #: siteorigin-panels.php:3
1254
  msgid "Page Builder by SiteOrigin"
1255
  msgstr ""
@@ -1270,15 +1326,15 @@ msgstr ""
1270
  msgid "https://siteorigin.com"
1271
  msgstr ""
1272
 
1273
- #: siteorigin-panels.php:331
1274
  msgid "Read More"
1275
  msgstr ""
1276
 
1277
- #: siteorigin-panels.php:479
1278
  msgid "Edit Home Page"
1279
  msgstr ""
1280
 
1281
- #: siteorigin-panels.php:499, tpl/js-templates.php:34, tpl/js-templates.php:36
1282
  msgid "Live Editor"
1283
  msgstr ""
1284
 
1242
  msgid "Search Settings"
1243
  msgstr ""
1244
 
1245
+ #: settings/tpl/settings.php:25
1246
+ msgid "Welcome"
1247
+ msgstr ""
1248
+
1249
+ #: settings/tpl/settings.php:30
1250
  msgid "Settings Saved"
1251
  msgstr ""
1252
 
1253
+ #: settings/tpl/settings.php:84
1254
  msgid "Save Settings"
1255
  msgstr ""
1256
 
1257
+ #: settings/tpl/welcome.php:1
1258
+ msgid "Welcome To SiteOrigin Page Builder"
1259
+ msgstr ""
1260
+
1261
+ #: settings/tpl/welcome.php:4
1262
+ msgid "Page Builder by SiteOrigin makes it easy to create responsive column based content, using the widgets you know and love. Your content will accurately adapt to all mobile devices, ensuring your site is mobile-ready."
1263
+ msgstr ""
1264
+
1265
+ #: settings/tpl/welcome.php:8
1266
+ msgid "Page Builder works with standard WordPress widgets, so you’ll always find the widget you need. We've also created the %s to give you a wide range of additional functionality. All the widgets are built on our powerful framework, giving you advanced forms, unlimited colours and 1500+ icons."
1267
+ msgstr ""
1268
+
1269
+ #: settings/tpl/welcome.php:11
1270
+ msgid "Simple Drag and Drop"
1271
+ msgstr ""
1272
+
1273
+ #: settings/tpl/welcome.php:14
1274
+ msgid "Reorder rows, move widgets, resize columns and build your page, all with your mouse. Page Builder makes it easy to nudge every detail into place, no matter how often you change your mind. We've meticulously crafted each and every interaction to make sure they all feel natural. It's intuitive content editing that doesn't sacrifice on functionality."
1275
+ msgstr ""
1276
+
1277
+ #: settings/tpl/welcome.php:17
1278
+ msgid "Live Editing"
1279
+ msgstr ""
1280
+
1281
+ #: settings/tpl/welcome.php:20
1282
+ msgid "The live editor gives you an exact preview of your content, that you can edit in real-time. You can use this to pin-point the sections and widgets you want to edit, then see those edits without leaving the page. Create content in a fraction of the time."
1283
+ msgstr ""
1284
+
1285
+ #: settings/tpl/welcome.php:23
1286
+ msgid "History Browser"
1287
+ msgstr ""
1288
+
1289
+ #: settings/tpl/welcome.php:26
1290
+ msgid "Worry free editing is having the freedom to experiment without fearing mistakes. The History Browser lets you roll forward and back through your changes. Preview changes, then roll back to that version without skipping a beat. Your personal safety net."
1291
+ msgstr ""
1292
+
1293
+ #: settings/tpl/welcome.php:29
1294
+ msgid "Row and Widget Styles"
1295
+ msgstr ""
1296
+
1297
+ #: settings/tpl/welcome.php:32
1298
+ msgid "Row and widget styles give you all the control you need to make your content uniquely your own. Change attributes like paddings, background colours and column spacing. You can also enter custom CSS and CSS classes if you need even finer grained control."
1299
+ msgstr ""
1300
+
1301
+ #: settings/tpl/welcome.php:35
1302
+ msgid "Get More Features"
1303
+ msgstr ""
1304
+
1305
+ #: settings/tpl/welcome.php:38
1306
+ msgid "%s is a single plugin that adds additional settings and functionality to Page Builder, SiteOrigin widgets and SiteOrign themes. SiteOrigin Premium also includes our next level email support service. If you need expert advice and quick replies, consider SiteOrigin Premium."
1307
+ msgstr ""
1308
+
1309
  #: siteorigin-panels.php:3
1310
  msgid "Page Builder by SiteOrigin"
1311
  msgstr ""
1326
  msgid "https://siteorigin.com"
1327
  msgstr ""
1328
 
1329
+ #: siteorigin-panels.php:333
1330
  msgid "Read More"
1331
  msgstr ""
1332
 
1333
+ #: siteorigin-panels.php:481
1334
  msgid "Edit Home Page"
1335
  msgstr ""
1336
 
1337
+ #: siteorigin-panels.php:501, tpl/js-templates.php:34, tpl/js-templates.php:36
1338
  msgid "Live Editor"
1339
  msgstr ""
1340
 
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Tags: page builder, responsive, widget, widgets, builder, page, admin, gallery, content, cms, pages, post, css, layout, grid
3
  Requires at least: 4.4
4
  Tested up to: 5.1
5
- Stable tag: 2.10.3
6
- Build time: 2019-04-02T10:40:39-07:00
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl.html
9
  Donate link: https://siteorigin.com/downloads/premium/
@@ -96,6 +96,10 @@ We've tried to ensure that Page Builder is compatible with most plugin widgets.
96
 
97
  == Changelog ==
98
 
 
 
 
 
99
  = 2.10.3 - 2 April 2019 =
100
  * Layout builder widget: Call styles sanitization in update.
101
  * Live editor: Only call `process_raw_widgets` once for preview data.
2
  Tags: page builder, responsive, widget, widgets, builder, page, admin, gallery, content, cms, pages, post, css, layout, grid
3
  Requires at least: 4.4
4
  Tested up to: 5.1
5
+ Stable tag: 2.10.4
6
+ Build time: 2019-04-03T14:14:32-07:00
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl.html
9
  Donate link: https://siteorigin.com/downloads/premium/
96
 
97
  == Changelog ==
98
 
99
+ = 2.10.4 - 3 April 2019 =
100
+ * New welcome page.
101
+ * Include row style wrapper in cell CSS direct child selectors.
102
+
103
  = 2.10.3 - 2 April 2019 =
104
  * Layout builder widget: Call styles sanitization in update.
105
  * Live editor: Only call `process_raw_widgets` once for preview data.
settings/admin-settings.css CHANGED
@@ -145,10 +145,16 @@
145
  -ms-user-select: none;
146
  user-select: none;
147
  }
 
 
 
148
  #panels-settings-page .submit {
149
  margin-top: 30px;
150
  padding: 0 30px;
151
  }
 
 
 
152
  body.settings_page_siteorigin_panels #contextual-help-link-wrap {
153
  z-index: 10;
154
  }
145
  -ms-user-select: none;
146
  user-select: none;
147
  }
148
+ #panels-settings-page #panels-settings-sections #panels-settings-section-welcome {
149
+ padding: 20px 30px 0 30px;
150
+ }
151
  #panels-settings-page .submit {
152
  margin-top: 30px;
153
  padding: 0 30px;
154
  }
155
+ #panels-settings-section-welcome {
156
+ max-width: 800px;
157
+ }
158
  body.settings_page_siteorigin_panels #contextual-help-link-wrap {
159
  z-index: 10;
160
  }
settings/admin-settings.js CHANGED
@@ -1,137 +1,227 @@
1
- jQuery( function($){
2
-
3
- // Handle the animations for the Page Builder logo
4
- // Only run after the image is loaded
5
- $(".settings-banner img")
6
- .hide()
7
- .eq(0)
8
- .one("load", function() {
9
- $.each([1,2,3], function(i, v){
10
- var $$ = $('.settings-banner img.layer-' + v);
11
- var opacity = $$.css('opacity');
12
-
13
- setTimeout( function(){
14
- $$.show()
15
- .css({'margin-top' : -5, 'opacity': 0})
16
- .animate({'margin-top' : 0, 'opacity': opacity}, 280 + 40*(4 - v) );
17
- }, 150 + 225 * (4 - v) );
18
- });
19
- })
20
- .each(function() { if(this.complete) { $(this).load(); } });
21
-
22
- // Settings page tabbing
23
-
24
- $('.settings-nav li a').click(function(e){
25
- e.preventDefault();
26
- var $$ = $(this);
27
- $('.settings-nav li a').not($$).closest('li').removeClass('active');
28
- $$.closest('li').addClass('active');
29
-
30
- var tabClicked = $$.attr('href').split('#')[1];
31
- var $s = $('#panels-settings-section-' + tabClicked);
32
-
33
- $('#panels-settings-sections .panels-settings-section').not($s).hide();
34
- $s.show();
35
- setUserSetting('siteorigin_panels_setting_tab', tabClicked);
36
- });
37
-
38
- // Save the tab the user last clicked
39
-
40
- var tabClicked = getUserSetting('siteorigin_panels_setting_tab');
41
- if(tabClicked === '') { $('.settings-nav li a').first().click(); }
42
- else { $('.settings-nav li a[href="#' + tabClicked + '"]').first().click(); }
43
-
44
- // Search settings
45
-
46
- var highlightSetting = function($s){
47
-
48
- // Click on the correct container
49
- $('.settings-nav li a[href="#' + $s.closest('.panels-settings-section').data('section') + '"]').first().click();
50
-
51
- $s.addClass('highlighted');
52
-
53
- $s
54
- .find('label')
55
- .css('border-left-width', 0)
56
- .animate({ 'border-left-width': 5 }, 'normal')
57
- .delay(4000)
58
- .animate({ 'border-left-width': 0 }, 'normal', function(){
59
- $s.removeClass('highlighted');
60
- });
61
-
62
- $s.find('input,textarea').focus();
63
- };
64
-
65
- var doSettingsSearch = function(){
66
- var $$ = $(this),
67
- $r = $('#panels-settings-search .results'),
68
- query = $$.val();
69
-
70
- if( query === '' ) {
71
- $r.empty().hide();
72
- return false;
73
- }
74
-
75
- // Search all the settings
76
- var settings = [];
77
- $('#panels-settings-sections .panels-setting').each(function(){
78
- var $s = $(this);
79
- var isMatch = 0;
80
-
81
- var indexes = {
82
- 'title' : $s.find('label').html().toLowerCase().indexOf( query ),
83
- 'keywords' : $s.find('.description').data('keywords').toLowerCase().indexOf( query ),
84
- 'description' : $s.find('.description').html().toLowerCase().indexOf( query )
85
- };
86
-
87
- if( indexes.title === 0 ) isMatch += 10;
88
- else if( indexes.title !== -1 ) isMatch += 7;
89
-
90
- if( indexes.keywords === 0 ) isMatch += 4;
91
- else if( indexes.keywords !== -1 ) isMatch += 3;
92
-
93
- if( indexes.description === 0 ) isMatch += 2;
94
- else if( indexes.description !== -1 ) isMatch += 1;
95
-
96
-
97
- if( isMatch > 0 ) {
98
- settings.push($s);
99
- $s.data('isMatch', isMatch);
100
- }
101
- });
102
-
103
- $r.empty();
104
-
105
- if( settings.length > 0 ) {
106
- $r.show();
107
- settings.sort( function(a,b){
108
- return b.data('isMatch') - a.data('isMatch');
109
- } );
110
-
111
- settings = settings.slice(0, 8);
112
-
113
- $.each(settings, function(i, el){
114
- $('#panels-settings-search .results').append(
115
- $('<li></li>')
116
- .html( el.find('label').html() )
117
- .click(function(){
118
- highlightSetting( el );
119
- $r.fadeOut('fast');
120
- $('#panels-settings-search input').blur();
121
- })
122
- );
123
- });
124
- }
125
- else {
126
- $r.hide();
127
- }
128
- };
129
-
130
- $('#panels-settings-search input')
131
- .keyup(doSettingsSearch)
132
- .click(doSettingsSearch)
133
- .blur( function(){
134
- $('#panels-settings-search .results').fadeOut('fast');
135
- } );
136
-
137
- } );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery( function($){
2
+
3
+ // Handle the animations for the Page Builder logo
4
+ // Only run after the image is loaded
5
+ $(".settings-banner img")
6
+ .hide()
7
+ .eq(0)
8
+ .one("load", function() {
9
+ $.each([1,2,3], function(i, v){
10
+ var $$ = $('.settings-banner img.layer-' + v);
11
+ var opacity = $$.css('opacity');
12
+
13
+ setTimeout( function(){
14
+ $$.show()
15
+ .css({'margin-top' : -5, 'opacity': 0})
16
+ .animate({'margin-top' : 0, 'opacity': opacity}, 280 + 40*(4 - v) );
17
+ }, 150 + 225 * (4 - v) );
18
+ });
19
+ })
20
+ .each(function() { if(this.complete) { $(this).load(); } });
21
+
22
+ // Settings page tabbing
23
+
24
+ $('.settings-nav li a').click(function(e){
25
+ e.preventDefault();
26
+ var $$ = $(this);
27
+ $('.settings-nav li a').not($$).closest('li').removeClass('active');
28
+ $$.closest('li').addClass('active');
29
+
30
+ var tabClicked = $$.attr('href').split('#')[1];
31
+ var $s = $('#panels-settings-section-' + tabClicked);
32
+
33
+ $('#panels-settings-sections .panels-settings-section').not($s).hide();
34
+ $s.show();
35
+
36
+ $('#panels-settings-page input[type="submit"]').css({
37
+ 'visibility' : tabClicked === 'welcome' ? 'hidden' : 'visible'
38
+ });
39
+
40
+ setUserSetting('siteorigin_panels_setting_tab', tabClicked);
41
+ });
42
+
43
+ if( window.location.hash ) {
44
+ $('.settings-nav li a[href="' + window.location.hash + '"]').click();
45
+ }
46
+
47
+ $('#panels-settings-section-welcome').fitVids();
48
+
49
+ // Save the tab the user last clicked
50
+
51
+ var tabClicked = getUserSetting('siteorigin_panels_setting_tab');
52
+ if(tabClicked === '') { $('.settings-nav li a').first().click(); }
53
+ else { $('.settings-nav li a[href="#' + tabClicked + '"]').first().click(); }
54
+
55
+ // Search settings
56
+
57
+ var highlightSetting = function($s){
58
+
59
+ // Click on the correct container
60
+ $('.settings-nav li a[href="#' + $s.closest('.panels-settings-section').data('section') + '"]').first().click();
61
+
62
+ $s.addClass('highlighted');
63
+
64
+ $s
65
+ .find('label')
66
+ .css('border-left-width', 0)
67
+ .animate({ 'border-left-width': 5 }, 'normal')
68
+ .delay(4000)
69
+ .animate({ 'border-left-width': 0 }, 'normal', function(){
70
+ $s.removeClass('highlighted');
71
+ });
72
+
73
+ $s.find('input,textarea').focus();
74
+ };
75
+
76
+ var doSettingsSearch = function(){
77
+ var $$ = $(this),
78
+ $r = $('#panels-settings-search .results'),
79
+ query = $$.val();
80
+
81
+ if( query === '' ) {
82
+ $r.empty().hide();
83
+ return false;
84
+ }
85
+
86
+ // Search all the settings
87
+ var settings = [];
88
+ $('#panels-settings-sections .panels-setting').each(function(){
89
+ var $s = $(this);
90
+ var isMatch = 0;
91
+
92
+ var indexes = {
93
+ 'title' : $s.find('label').html().toLowerCase().indexOf( query ),
94
+ 'keywords' : $s.find('.description').data('keywords').toLowerCase().indexOf( query ),
95
+ 'description' : $s.find('.description').html().toLowerCase().indexOf( query )
96
+ };
97
+
98
+ if( indexes.title === 0 ) isMatch += 10;
99
+ else if( indexes.title !== -1 ) isMatch += 7;
100
+
101
+ if( indexes.keywords === 0 ) isMatch += 4;
102
+ else if( indexes.keywords !== -1 ) isMatch += 3;
103
+
104
+ if( indexes.description === 0 ) isMatch += 2;
105
+ else if( indexes.description !== -1 ) isMatch += 1;
106
+
107
+
108
+ if( isMatch > 0 ) {
109
+ settings.push($s);
110
+ $s.data('isMatch', isMatch);
111
+ }
112
+ });
113
+
114
+ $r.empty();
115
+
116
+ if( settings.length > 0 ) {
117
+ $r.show();
118
+ settings.sort( function(a,b){
119
+ return b.data('isMatch') - a.data('isMatch');
120
+ } );
121
+
122
+ settings = settings.slice(0, 8);
123
+
124
+ $.each(settings, function(i, el){
125
+ $('#panels-settings-search .results').append(
126
+ $('<li></li>')
127
+ .html( el.find('label').html() )
128
+ .click(function(){
129
+ highlightSetting( el );
130
+ $r.fadeOut('fast');
131
+ $('#panels-settings-search input').blur();
132
+ })
133
+ );
134
+ });
135
+ }
136
+ else {
137
+ $r.hide();
138
+ }
139
+ };
140
+
141
+ $('#panels-settings-search input')
142
+ .keyup(doSettingsSearch)
143
+ .click(doSettingsSearch)
144
+ .blur( function(){
145
+ $('#panels-settings-search .results').fadeOut('fast');
146
+ } );
147
+
148
+ } );
149
+
150
+ // Fitvids
151
+ ;(function( $ ){
152
+
153
+ 'use strict';
154
+
155
+ $.fn.fitVids = function( options ) {
156
+ var settings = {
157
+ customSelector: null,
158
+ ignore: null
159
+ };
160
+
161
+ if(!document.getElementById('fit-vids-style')) {
162
+ // appendStyles: https://github.com/toddmotto/fluidvids/blob/master/dist/fluidvids.js
163
+ var head = document.head || document.getElementsByTagName('head')[0];
164
+ var css = '.fluid-width-video-wrapper{width:100%;position:relative;padding:0;}.fluid-width-video-wrapper iframe,.fluid-width-video-wrapper object,.fluid-width-video-wrapper embed {position:absolute;top:0;left:0;width:100%;height:100%;}';
165
+ var div = document.createElement("div");
166
+ div.innerHTML = '<p>x</p><style id="fit-vids-style">' + css + '</style>';
167
+ head.appendChild(div.childNodes[1]);
168
+ }
169
+
170
+ if ( options ) {
171
+ $.extend( settings, options );
172
+ }
173
+
174
+ return this.each(function(){
175
+ var selectors = [
176
+ 'iframe[src*="player.vimeo.com"]',
177
+ 'iframe[src*="youtube.com"]',
178
+ 'iframe[src*="youtube-nocookie.com"]',
179
+ 'iframe[src*="kickstarter.com"][src*="video.html"]',
180
+ 'object',
181
+ 'embed'
182
+ ];
183
+
184
+ if (settings.customSelector) {
185
+ selectors.push(settings.customSelector);
186
+ }
187
+
188
+ var ignoreList = '.fitvidsignore';
189
+
190
+ if(settings.ignore) {
191
+ ignoreList = ignoreList + ', ' + settings.ignore;
192
+ }
193
+
194
+ var $allVideos = $(this).find(selectors.join(','));
195
+ $allVideos = $allVideos.not('object object'); // SwfObj conflict patch
196
+ $allVideos = $allVideos.not(ignoreList); // Disable FitVids on this video.
197
+
198
+ $allVideos.each(function(){
199
+ var $this = $(this);
200
+ if($this.parents(ignoreList).length > 0) {
201
+ return; // Disable FitVids on this video.
202
+ }
203
+ if (this.tagName.toLowerCase() === 'embed' && $this.parent('object').length || $this.parent('.fluid-width-video-wrapper').length) { return; }
204
+ if ((!$this.css('height') && !$this.css('width')) && (isNaN($this.attr('height')) || isNaN($this.attr('width'))))
205
+ {
206
+ $this.attr('height', 9);
207
+ $this.attr('width', 16);
208
+ }
209
+ var height = ( this.tagName.toLowerCase() === 'object' || ($this.attr('height') && !isNaN(parseInt($this.attr('height'), 10))) ) ? parseInt($this.attr('height'), 10) : $this.height(),
210
+ width = !isNaN(parseInt($this.attr('width'), 10)) ? parseInt($this.attr('width'), 10) : $this.width(),
211
+ aspectRatio = height / width;
212
+ if(!$this.attr('name')){
213
+ var videoName = 'fitvid' + $.fn.fitVids._count;
214
+ $this.attr('name', videoName);
215
+ $.fn.fitVids._count++;
216
+ }
217
+ $this.wrap('<div class="fluid-width-video-wrapper"></div>').parent('.fluid-width-video-wrapper').css('padding-top', (aspectRatio * 100)+'%');
218
+ $this.removeAttr('height').removeAttr('width');
219
+ });
220
+ });
221
+ };
222
+
223
+ // Internal counter for unique video names.
224
+ $.fn.fitVids._count = 0;
225
+
226
+ // Works with either jQuery or Zepto
227
+ })( window.jQuery || window.Zepto );
settings/admin-settings.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(function(c){c(".settings-banner img").hide().eq(0).one("load",function(){c.each([1,2,3],function(t,e){var s=c(".settings-banner img.layer-"+e),i=s.css("opacity");setTimeout(function(){s.show().css({"margin-top":-5,opacity:0}).animate({"margin-top":0,opacity:i},280+40*(4-e))},150+225*(4-e))})}).each(function(){this.complete&&c(this).load()}),c(".settings-nav li a").click(function(t){t.preventDefault();var e=c(this);c(".settings-nav li a").not(e).closest("li").removeClass("active"),e.closest("li").addClass("active");var s=e.attr("href").split("#")[1],i=c("#panels-settings-section-"+s);c("#panels-settings-sections .panels-settings-section").not(i).hide(),i.show(),setUserSetting("siteorigin_panels_setting_tab",s)});var t=getUserSetting("siteorigin_panels_setting_tab");""===t?c(".settings-nav li a").first().click():c('.settings-nav li a[href="#'+t+'"]').first().click();var e=function(){var t=c(this),s=c("#panels-settings-search .results"),a=t.val();if(""===a)return s.empty().hide(),!1;var l=[];c("#panels-settings-sections .panels-setting").each(function(){var t=c(this),e=0,s=t.find("label").html().toLowerCase().indexOf(a),i=t.find(".description").data("keywords").toLowerCase().indexOf(a),n=t.find(".description").html().toLowerCase().indexOf(a);0===s?e+=10:-1!==s&&(e+=7),0===i?e+=4:-1!==i&&(e+=3),0===n?e+=2:-1!==n&&(e+=1),0<e&&(l.push(t),t.data("isMatch",e))}),s.empty(),0<l.length?(s.show(),l.sort(function(t,e){return e.data("isMatch")-t.data("isMatch")}),l=l.slice(0,8),c.each(l,function(t,e){c("#panels-settings-search .results").append(c("<li></li>").html(e.find("label").html()).click(function(){var t;c('.settings-nav li a[href="#'+(t=e).closest(".panels-settings-section").data("section")+'"]').first().click(),t.addClass("highlighted"),t.find("label").css("border-left-width",0).animate({"border-left-width":5},"normal").delay(4e3).animate({"border-left-width":0},"normal",function(){t.removeClass("highlighted")}),t.find("input,textarea").focus(),s.fadeOut("fast"),c("#panels-settings-search input").blur()}))})):s.hide()};c("#panels-settings-search input").keyup(e).click(e).blur(function(){c("#panels-settings-search .results").fadeOut("fast")})});
1
+ jQuery(function(o){o(".settings-banner img").hide().eq(0).one("load",function(){o.each([1,2,3],function(t,e){var i=o(".settings-banner img.layer-"+e),s=i.css("opacity");setTimeout(function(){i.show().css({"margin-top":-5,opacity:0}).animate({"margin-top":0,opacity:s},280+40*(4-e))},150+225*(4-e))})}).each(function(){this.complete&&o(this).load()}),o(".settings-nav li a").click(function(t){t.preventDefault();var e=o(this);o(".settings-nav li a").not(e).closest("li").removeClass("active"),e.closest("li").addClass("active");var i=e.attr("href").split("#")[1],s=o("#panels-settings-section-"+i);o("#panels-settings-sections .panels-settings-section").not(s).hide(),s.show(),o('#panels-settings-page input[type="submit"]').css({visibility:"welcome"===i?"hidden":"visible"}),setUserSetting("siteorigin_panels_setting_tab",i)}),window.location.hash&&o('.settings-nav li a[href="'+window.location.hash+'"]').click(),o("#panels-settings-section-welcome").fitVids();var t=getUserSetting("siteorigin_panels_setting_tab");""===t?o(".settings-nav li a").first().click():o('.settings-nav li a[href="#'+t+'"]').first().click();var e=function(){var t=o(this),i=o("#panels-settings-search .results"),a=t.val();if(""===a)return i.empty().hide(),!1;var r=[];o("#panels-settings-sections .panels-setting").each(function(){var t=o(this),e=0,i=t.find("label").html().toLowerCase().indexOf(a),s=t.find(".description").data("keywords").toLowerCase().indexOf(a),n=t.find(".description").html().toLowerCase().indexOf(a);0===i?e+=10:-1!==i&&(e+=7),0===s?e+=4:-1!==s&&(e+=3),0===n?e+=2:-1!==n&&(e+=1),0<e&&(r.push(t),t.data("isMatch",e))}),i.empty(),0<r.length?(i.show(),r.sort(function(t,e){return e.data("isMatch")-t.data("isMatch")}),r=r.slice(0,8),o.each(r,function(t,e){o("#panels-settings-search .results").append(o("<li></li>").html(e.find("label").html()).click(function(){var t;o('.settings-nav li a[href="#'+(t=e).closest(".panels-settings-section").data("section")+'"]').first().click(),t.addClass("highlighted"),t.find("label").css("border-left-width",0).animate({"border-left-width":5},"normal").delay(4e3).animate({"border-left-width":0},"normal",function(){t.removeClass("highlighted")}),t.find("input,textarea").focus(),i.fadeOut("fast"),o("#panels-settings-search input").blur()}))})):i.hide()};o("#panels-settings-search input").keyup(e).click(e).blur(function(){o("#panels-settings-search .results").fadeOut("fast")})}),function(n){"use strict";n.fn.fitVids=function(t){var i={customSelector:null,ignore:null};if(!document.getElementById("fit-vids-style")){var e=document.head||document.getElementsByTagName("head")[0],s=document.createElement("div");s.innerHTML='<p>x</p><style id="fit-vids-style">.fluid-width-video-wrapper{width:100%;position:relative;padding:0;}.fluid-width-video-wrapper iframe,.fluid-width-video-wrapper object,.fluid-width-video-wrapper embed {position:absolute;top:0;left:0;width:100%;height:100%;}</style>',e.appendChild(s.childNodes[1])}return t&&n.extend(i,t),this.each(function(){var t=['iframe[src*="player.vimeo.com"]','iframe[src*="youtube.com"]','iframe[src*="youtube-nocookie.com"]','iframe[src*="kickstarter.com"][src*="video.html"]',"object","embed"];i.customSelector&&t.push(i.customSelector);var s=".fitvidsignore";i.ignore&&(s=s+", "+i.ignore);var e=n(this).find(t.join(","));(e=(e=e.not("object object")).not(s)).each(function(){var t=n(this);if(!(0<t.parents(s).length||"embed"===this.tagName.toLowerCase()&&t.parent("object").length||t.parent(".fluid-width-video-wrapper").length)){t.css("height")||t.css("width")||!isNaN(t.attr("height"))&&!isNaN(t.attr("width"))||(t.attr("height",9),t.attr("width",16));var e=("object"===this.tagName.toLowerCase()||t.attr("height")&&!isNaN(parseInt(t.attr("height"),10))?parseInt(t.attr("height"),10):t.height())/(isNaN(parseInt(t.attr("width"),10))?t.width():parseInt(t.attr("width"),10));if(!t.attr("name")){var i="fitvid"+n.fn.fitVids._count;t.attr("name",i),n.fn.fitVids._count++}t.wrap('<div class="fluid-width-video-wrapper"></div>').parent(".fluid-width-video-wrapper").css("padding-top",100*e+"%"),t.removeAttr("height").removeAttr("width")}})})},n.fn.fitVids._count=0}(window.jQuery||window.Zepto);
settings/tpl/settings.php CHANGED
@@ -1,82 +1,88 @@
1
- <div class="wrap" id="panels-settings-page">
2
- <div class="settings-banner">
3
-
4
- <span class="icon">
5
- <img src="<?php echo siteorigin_panels_url( 'settings/images/icon-layer.png' ) ?>" class="layer-3" />
6
- <img src="<?php echo siteorigin_panels_url( 'settings/images/icon-layer.png' ) ?>" class="layer-2" />
7
- <img src="<?php echo siteorigin_panels_url( 'settings/images/icon-layer.png' ) ?>" class="layer-1" />
8
- </span>
9
- <h1><?php _e('SiteOrigin Page Builder', 'siteorigin-panels') ?></h1>
10
-
11
- <div id="panels-settings-search">
12
- <input type="search" placeholder="<?php esc_attr_e('Search Settings', 'siteorigin-panels') ?>" />
13
-
14
- <ul class="results">
15
- </ul>
16
- </div>
17
- </div>
18
-
19
- <ul class="settings-nav">
20
- <?php
21
- foreach($settings_fields as $section_id => $section) {
22
- ?><li><a href="#<?php echo esc_attr( $section_id ) ?>"><?php echo esc_html( $section['title'] ) ?></a></li><?php
23
- }
24
- ?>
25
- </ul>
26
-
27
- <?php if( $this->settings_saved ) : ?>
28
- <div id="setting-error-settings_updated" class="updated settings-error">
29
- <p><strong><?php _e('Settings Saved', 'siteorigin-panels') ?></strong></p>
30
- </div>
31
- <?php endif; ?>
32
-
33
- <form action="<?php echo admin_url('options-general.php?page=siteorigin_panels') ?>" method="post" >
34
-
35
- <div id="panels-settings-sections">
36
- <?php
37
- foreach($settings_fields as $section_id => $section) {
38
- ?>
39
- <div id="panels-settings-section-<?php echo esc_attr($section_id) ?>" class="panels-settings-section" data-section="<?php echo esc_attr($section_id) ?>">
40
- <table class="form-table">
41
- <tbody>
42
- <?php foreach( $section['fields'] as $field_id => $field ) : ?>
43
- <tr class="panels-setting">
44
- <th scope="row"><label><?php echo esc_html($field['label']) ?></label></th>
45
- <td>
46
- <?php
47
- $this->display_field( $field_id, $field );
48
- if( !empty($field['description']) ) {
49
- ?>
50
- <small class="description" data-keywords="<?php if(!empty($field['keywords'])) echo esc_attr($field['keywords']) ?>">
51
- <?php
52
- echo wp_kses( $field['description'], array(
53
- 'a' => array(
54
- 'href' => array(),
55
- 'title' => array()
56
- ),
57
- 'em' => array(),
58
- 'strong' => array(),
59
- ) );
60
- ?>
61
- </small>
62
- <?php
63
- }
64
- ?>
65
- </td>
66
- </tr>
67
- <?php endforeach; ?>
68
- </tbody>
69
- </table>
70
- </div>
71
- <?php
72
- }
73
- ?>
74
- </div>
75
-
76
- <div class="submit">
77
- <?php wp_nonce_field( 'panels-settings' ) ?>
78
- <input type="submit" value="<?php _e('Save Settings', 'siteorigin-panels') ?>" class="button-primary" />
79
- </div>
80
- </form>
81
-
82
- </div>
 
 
 
 
 
 
1
+ <div class="wrap" id="panels-settings-page">
2
+ <div class="settings-banner">
3
+
4
+ <span class="icon">
5
+ <img src="<?php echo siteorigin_panels_url( 'settings/images/icon-layer.png' ) ?>" class="layer-3" />
6
+ <img src="<?php echo siteorigin_panels_url( 'settings/images/icon-layer.png' ) ?>" class="layer-2" />
7
+ <img src="<?php echo siteorigin_panels_url( 'settings/images/icon-layer.png' ) ?>" class="layer-1" />
8
+ </span>
9
+ <h1><?php _e('SiteOrigin Page Builder', 'siteorigin-panels') ?></h1>
10
+
11
+ <div id="panels-settings-search">
12
+ <input type="search" placeholder="<?php esc_attr_e('Search Settings', 'siteorigin-panels') ?>" />
13
+
14
+ <ul class="results">
15
+ </ul>
16
+ </div>
17
+ </div>
18
+
19
+ <ul class="settings-nav">
20
+ <?php
21
+ foreach($settings_fields as $section_id => $section) {
22
+ ?><li><a href="#<?php echo esc_attr( $section_id ) ?>"><?php echo esc_html( $section['title'] ) ?></a></li><?php
23
+ }
24
+ ?>
25
+ <li><a href="#welcome"><?php esc_html_e( 'Welcome', 'siteorigin-panels' ) ?></a></li>
26
+ </ul>
27
+
28
+ <?php if( $this->settings_saved ) : ?>
29
+ <div id="setting-error-settings_updated" class="updated settings-error">
30
+ <p><strong><?php _e('Settings Saved', 'siteorigin-panels') ?></strong></p>
31
+ </div>
32
+ <?php endif; ?>
33
+
34
+ <form action="<?php echo admin_url('options-general.php?page=siteorigin_panels') ?>" method="post" >
35
+
36
+ <div id="panels-settings-sections">
37
+ <?php
38
+ foreach($settings_fields as $section_id => $section) {
39
+ ?>
40
+ <div id="panels-settings-section-<?php echo esc_attr($section_id) ?>" class="panels-settings-section" data-section="<?php echo esc_attr($section_id) ?>">
41
+ <table class="form-table">
42
+ <tbody>
43
+ <?php foreach( $section['fields'] as $field_id => $field ) : ?>
44
+ <tr class="panels-setting">
45
+ <th scope="row"><label><?php echo esc_html($field['label']) ?></label></th>
46
+ <td>
47
+ <?php
48
+ $this->display_field( $field_id, $field );
49
+ if( !empty($field['description']) ) {
50
+ ?>
51
+ <small class="description" data-keywords="<?php if(!empty($field['keywords'])) echo esc_attr($field['keywords']) ?>">
52
+ <?php
53
+ echo wp_kses( $field['description'], array(
54
+ 'a' => array(
55
+ 'href' => array(),
56
+ 'title' => array()
57
+ ),
58
+ 'em' => array(),
59
+ 'strong' => array(),
60
+ ) );
61
+ ?>
62
+ </small>
63
+ <?php
64
+ }
65
+ ?>
66
+ </td>
67
+ </tr>
68
+ <?php endforeach; ?>
69
+ </tbody>
70
+ </table>
71
+ </div>
72
+ <?php
73
+ }
74
+ ?>
75
+
76
+ <div id="panels-settings-section-welcome" class="panels-settings-section" data-section="welcome">
77
+ <?php include( plugin_dir_path(__FILE__) . 'welcome.php' ) ?>
78
+ </div>
79
+
80
+ </div>
81
+
82
+ <div class="submit">
83
+ <?php wp_nonce_field( 'panels-settings' ) ?>
84
+ <input type="submit" value="<?php _e('Save Settings', 'siteorigin-panels') ?>" class="button-primary" />
85
+ </div>
86
+ </form>
87
+
88
+ </div>
settings/tpl/welcome.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <h1><?php esc_html_e( 'Welcome To SiteOrigin Page Builder', 'siteorigin-panels' ); ?></h1>
2
+
3
+ <p>
4
+ <?php esc_html_e( 'Page Builder by SiteOrigin makes it easy to create responsive column based content, using the widgets you know and love. Your content will accurately adapt to all mobile devices, ensuring your site is mobile-ready.', 'siteorigin-panels' ); ?>
5
+ </p>
6
+
7
+ <p>
8
+ <?php printf( esc_html__( "Page Builder works with standard WordPress widgets, so you’ll always find the widget you need. We've also created the %s to give you a wide range of additional functionality. All the widgets are built on our powerful framework, giving you advanced forms, unlimited colours and 1500+ icons.", 'siteorigin-panels' ), '<a href="https://wordpress.org/plugins/so-widgets-bundle/" target="_blank">SiteOrigin Widgets Bundle</a>' ); ?>
9
+ </p>
10
+
11
+ <h2><?php esc_html_e( 'Simple Drag and Drop', 'siteorigin-panels' ); ?></h2>
12
+
13
+ <p>
14
+ <?php esc_html_e( "Reorder rows, move widgets, resize columns and build your page, all with your mouse. Page Builder makes it easy to nudge every detail into place, no matter how often you change your mind. We've meticulously crafted each and every interaction to make sure they all feel natural. It's intuitive content editing that doesn't sacrifice on functionality.", 'siteorigin-panels' ); ?>
15
+ </p>
16
+
17
+ <h2><?php esc_html_e( 'Live Editing', 'siteorigin-panels' ); ?></h2>
18
+
19
+ <p>
20
+ <?php esc_html_e( 'The live editor gives you an exact preview of your content, that you can edit in real-time. You can use this to pin-point the sections and widgets you want to edit, then see those edits without leaving the page. Create content in a fraction of the time.', 'siteorigin-panels' ); ?>
21
+ </p>
22
+
23
+ <h2><?php esc_html_e( 'History Browser', 'siteorigin-panels' ); ?></h2>
24
+
25
+ <p>
26
+ <?php esc_html_e( 'Worry free editing is having the freedom to experiment without fearing mistakes. The History Browser lets you roll forward and back through your changes. Preview changes, then roll back to that version without skipping a beat. Your personal safety net.', 'siteorigin-panels' ); ?>
27
+ </p>
28
+
29
+ <h2><?php esc_html_e( 'Row and Widget Styles', 'siteorigin-panels' ); ?></h2>
30
+
31
+ <p>
32
+ <?php esc_html_e( 'Row and widget styles give you all the control you need to make your content uniquely your own. Change attributes like paddings, background colours and column spacing. You can also enter custom CSS and CSS classes if you need even finer grained control.', 'siteorigin-panels' ); ?>
33
+ </p>
34
+
35
+ <h2><?php esc_html_e( 'Get More Features', 'siteorigin-panels' ); ?></h2>
36
+
37
+ <p>
38
+ <?php printf( esc_html__( '%s is a single plugin that adds additional settings and functionality to Page Builder, SiteOrigin widgets and SiteOrign themes. SiteOrigin Premium also includes our next level email support service. If you need expert advice and quick replies, consider SiteOrigin Premium.', 'siteorigin-panels' ), '<a href="https://siteorigin.com/downloads/premium/" target="_blank">SiteOrigin Premium</a>' ); ?>
39
+ </p>
40
+
41
+ <iframe src="https://player.vimeo.com/video/314964526" width="800" height="450" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
siteorigin-panels.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Page Builder by SiteOrigin
4
  Plugin URI: https://siteorigin.com/page-builder/
5
  Description: A drag and drop, responsive page builder that simplifies building your website.
6
- Version: 2.10.3
7
  Author: SiteOrigin
8
  Author URI: https://siteorigin.com
9
  License: GPL3
@@ -11,12 +11,12 @@ License URI: http://www.gnu.org/licenses/gpl.html
11
  Donate link: http://siteorigin.com/page-builder/#donate
12
  */
13
 
14
- define( 'SITEORIGIN_PANELS_VERSION', '2.10.3' );
15
  if ( ! defined( 'SITEORIGIN_PANELS_JS_SUFFIX' ) ) {
16
  define( 'SITEORIGIN_PANELS_JS_SUFFIX', '.min' );
17
  }
18
  define( 'SITEORIGIN_PANELS_CSS_SUFFIX', '.min' );
19
- define( 'SITEORIGIN_PANELS_VERSION_SUFFIX', '-2103' );
20
 
21
  require_once plugin_dir_path( __FILE__ ) . 'inc/functions.php';
22
 
@@ -37,6 +37,8 @@ class SiteOrigin_Panels {
37
  add_filter( 'body_class', array( $this, 'body_class' ) );
38
  add_filter( 'siteorigin_panels_data', array( $this, 'process_panels_data' ), 5 );
39
  add_filter( 'siteorigin_panels_widget_class', array( $this, 'fix_namespace_escaping' ), 5 );
 
 
40
 
41
  if (
42
  is_admin() ||
@@ -653,6 +655,17 @@ class SiteOrigin_Panels {
653
  }
654
  return null;
655
  }
 
 
 
 
 
 
 
 
 
 
 
656
  }
657
 
658
- SiteOrigin_Panels::single();
3
  Plugin Name: Page Builder by SiteOrigin
4
  Plugin URI: https://siteorigin.com/page-builder/
5
  Description: A drag and drop, responsive page builder that simplifies building your website.
6
+ Version: 2.10.4
7
  Author: SiteOrigin
8
  Author URI: https://siteorigin.com
9
  License: GPL3
11
  Donate link: http://siteorigin.com/page-builder/#donate
12
  */
13
 
14
+ define( 'SITEORIGIN_PANELS_VERSION', '2.10.4' );
15
  if ( ! defined( 'SITEORIGIN_PANELS_JS_SUFFIX' ) ) {
16
  define( 'SITEORIGIN_PANELS_JS_SUFFIX', '.min' );
17
  }
18
  define( 'SITEORIGIN_PANELS_CSS_SUFFIX', '.min' );
19
+ define( 'SITEORIGIN_PANELS_VERSION_SUFFIX', '-2104' );
20
 
21
  require_once plugin_dir_path( __FILE__ ) . 'inc/functions.php';
22
 
37
  add_filter( 'body_class', array( $this, 'body_class' ) );
38
  add_filter( 'siteorigin_panels_data', array( $this, 'process_panels_data' ), 5 );
39
  add_filter( 'siteorigin_panels_widget_class', array( $this, 'fix_namespace_escaping' ), 5 );
40
+
41
+ add_action( 'activated_plugin', array($this, 'activation_redirect') );
42
 
43
  if (
44
  is_admin() ||
655
  }
656
  return null;
657
  }
658
+
659
+ /**
660
+ * Redirect to a welcome page after activation.
661
+ *
662
+ * @param $plugin
663
+ */
664
+ public function activation_redirect( $plugin ){
665
+ if( $plugin == plugin_basename( __FILE__ ) ) {
666
+ exit( wp_redirect( admin_url( 'options-general.php?page=siteorigin_panels#welcome' ) ) );
667
+ }
668
+ }
669
  }
670
 
671
+ SiteOrigin_Panels::single();