Unyson - Version 2.2.2

Version Description

  • Added experimental $option['option_handler'] 636ed56
  • <input required ... /> works in fw.OptionsModal #274
  • Fixed #381, #382, #385, Shortcodes#15
Download this release

Release Info

Developer Unyson
Plugin Icon 128x128 Unyson
Version 2.2.2
Comparing to
See all releases

Code changes from version 2.2.1 to 2.2.2

framework/core/Fw.php CHANGED
@@ -46,6 +46,7 @@ final class _Fw
46
 
47
  require $fw_dir .'/core/extends/class-fw-extension.php';
48
  require $fw_dir .'/core/extends/class-fw-option-type.php';
 
49
 
50
  // components
51
  {
46
 
47
  require $fw_dir .'/core/extends/class-fw-extension.php';
48
  require $fw_dir .'/core/extends/class-fw-option-type.php';
49
+ require $fw_dir .'/core/extends/interface-fw-option-handler.php'; //option handler
50
 
51
  // components
52
  {
framework/core/components/backend.php CHANGED
@@ -615,12 +615,31 @@ final class _FW_Component_Backend {
615
 
616
  $old_values = (array) fw_get_db_post_option( $original_id );
617
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
618
  fw_set_db_post_option(
619
  $post_id,
620
  null,
621
- fw_get_options_values_from_input(
622
- fw()->theme->get_post_options( $original_post->post_type )
623
- )
624
  );
625
 
626
  do_action( 'fw_save_post_options', $post_id, $post, $old_values );
@@ -1189,7 +1208,19 @@ final class _FW_Component_Backend {
1189
  $data['id_prefix'] = FW_Option_Type::get_default_id_prefix();
1190
  }
1191
 
1192
- return fw_render_view( fw_get_framework_directory( '/views/backend-option-design-' . $design . '.php' ), array(
 
 
 
 
 
 
 
 
 
 
 
 
1193
  'id' => $id,
1194
  'option' => $option,
1195
  'data' => $data,
615
 
616
  $old_values = (array) fw_get_db_post_option( $original_id );
617
 
618
+ $handled_values = array();
619
+ $all_options = fw_extract_only_options(fw()->theme->get_post_options($post->post_type));
620
+ $options_values = fw_get_options_values_from_input( fw()->theme->get_post_options($post->post_type) );
621
+
622
+ foreach ($all_options as $option_id => $option) {
623
+ if (
624
+ isset($option['option_handler']) &&
625
+ $option['option_handler'] instanceof FW_Option_Handler
626
+ ) {
627
+
628
+ /*
629
+ * if the option has a custom option_handler
630
+ * the saving is delegated to the handler,
631
+ * so it does not go to the post_meta
632
+ */
633
+ $option['option_handler']->save_option_value($option_id, $option, $options_values[$option_id]);
634
+
635
+ $handled_values[$option_id] = $options_values[$option_id];
636
+ }
637
+ }
638
+
639
  fw_set_db_post_option(
640
  $post_id,
641
  null,
642
+ array_diff_key($options_values, $handled_values) //unset $handled_values
 
 
643
  );
644
 
645
  do_action( 'fw_save_post_options', $post_id, $post, $old_values );
1208
  $data['id_prefix'] = FW_Option_Type::get_default_id_prefix();
1209
  }
1210
 
1211
+ if (
1212
+ isset($option['option_handler']) &&
1213
+ $option['option_handler'] instanceof FW_Option_Handler
1214
+ ) {
1215
+
1216
+ /*
1217
+ * if the option has a custom option_handler
1218
+ * then the handler provides the option's value
1219
+ */
1220
+ $data['value'] = $option['option_handler']->get_option_value($id, $option, $data);
1221
+ }
1222
+
1223
+ return fw_render_view(fw_get_framework_directory('/views/backend-option-design-'. $design .'.php'), array(
1224
  'id' => $id,
1225
  'option' => $option,
1226
  'data' => $data,
framework/core/components/extensions.php CHANGED
@@ -53,6 +53,11 @@ final class _FW_Component_Extensions
53
  */
54
  private static $extension_to_active_tree = array();
55
 
 
 
 
 
 
56
  /**
57
  * @var null|_FW_Extensions_Manager
58
  */
@@ -103,6 +108,7 @@ final class _FW_Component_Extensions
103
  {
104
  if (false) {
105
  $data = array(
 
106
  'path' => '/path/to/extension',
107
  'uri' => 'https://uri.to/extension',
108
  'customizations_locations' => array(
@@ -125,6 +131,7 @@ final class _FW_Component_Extensions
125
  $data['all_extensions_tree'] = &self::$all_extensions_tree;
126
  $data['all_extensions'] = &self::$all_extensions;
127
  $data['current_depth'] = 1;
 
128
  $data['parent'] = null;
129
  }
130
 
@@ -169,6 +176,7 @@ final class _FW_Component_Extensions
169
  // this is a directory with customizations for an extension
170
 
171
  self::load_extensions(array(
 
172
  'path' => $data['path'] .'/'. $extension_name .'/extensions',
173
  'uri' => $data['uri'] .'/'. $extension_name .'/extensions',
174
  'customizations_locations' => $customizations_locations,
@@ -203,6 +211,7 @@ final class _FW_Component_Extensions
203
  }
204
 
205
  $data['all_extensions'][$extension_name] = new $class_name(array(
 
206
  'path' => $data['path'] .'/'. $extension_name,
207
  'uri' => $data['uri'] .'/'. $extension_name,
208
  'parent' => $data['parent'],
@@ -218,6 +227,7 @@ final class _FW_Component_Extensions
218
  }
219
 
220
  self::load_extensions(array(
 
221
  'path' => $data['all_extensions'][$extension_name]->get_path() .'/extensions',
222
  'uri' => $data['all_extensions'][$extension_name]->get_uri() .'/extensions',
223
  'customizations_locations' => $customizations_locations,
@@ -294,6 +304,11 @@ final class _FW_Component_Extensions
294
 
295
  private function load_all_extensions()
296
  {
 
 
 
 
 
297
  {
298
  $customizations_locations = array();
299
 
@@ -304,6 +319,8 @@ final class _FW_Component_Extensions
304
 
305
  $customizations_locations[fw_get_template_customizations_directory('/extensions')]
306
  = fw_get_template_customizations_directory_uri('/extensions');
 
 
307
  }
308
 
309
  self::load_extensions(array(
@@ -312,10 +329,8 @@ final class _FW_Component_Extensions
312
  'customizations_locations' => $customizations_locations,
313
  ));
314
 
315
- /**
316
- * { '/hello/world/extensions' => 'https://hello.com/world/extensions' }
317
- */
318
- foreach (apply_filters('fw_extensions_locations', array()) as $path => $uri) {
319
  self::load_extensions(array(
320
  'path' => $path,
321
  'uri' => $uri,
@@ -429,7 +444,7 @@ final class _FW_Component_Extensions
429
  self::include_extension_file_all_locations($extension_name, '/helpers.php');
430
  self::include_extension_file_all_locations($extension_name, '/hooks.php');
431
 
432
- if (self::$all_extensions[$extension_name]->_call_init() !== false) {
433
  $this->activate_extensions($extension_name);
434
  }
435
 
@@ -497,6 +512,8 @@ final class _FW_Component_Extensions
497
  */
498
  public function _init()
499
  {
 
 
500
  $this->load_all_extensions();
501
  $this->add_actions();
502
  }
53
  */
54
  private static $extension_to_active_tree = array();
55
 
56
+ /**
57
+ * @var FW_Access_Key
58
+ */
59
+ private static $access_key;
60
+
61
  /**
62
  * @var null|_FW_Extensions_Manager
63
  */
108
  {
109
  if (false) {
110
  $data = array(
111
+ 'rel_path' => '/extension',
112
  'path' => '/path/to/extension',
113
  'uri' => 'https://uri.to/extension',
114
  'customizations_locations' => array(
131
  $data['all_extensions_tree'] = &self::$all_extensions_tree;
132
  $data['all_extensions'] = &self::$all_extensions;
133
  $data['current_depth'] = 1;
134
+ $data['rel_path'] = '';
135
  $data['parent'] = null;
136
  }
137
 
176
  // this is a directory with customizations for an extension
177
 
178
  self::load_extensions(array(
179
+ 'rel_path' => $data['rel_path'] .'/'. $extension_name .'/extensions',
180
  'path' => $data['path'] .'/'. $extension_name .'/extensions',
181
  'uri' => $data['uri'] .'/'. $extension_name .'/extensions',
182
  'customizations_locations' => $customizations_locations,
211
  }
212
 
213
  $data['all_extensions'][$extension_name] = new $class_name(array(
214
+ 'rel_path' => $data['rel_path'] .'/'. $extension_name,
215
  'path' => $data['path'] .'/'. $extension_name,
216
  'uri' => $data['uri'] .'/'. $extension_name,
217
  'parent' => $data['parent'],
227
  }
228
 
229
  self::load_extensions(array(
230
+ 'rel_path' => $data['all_extensions'][$extension_name]->get_rel_path() .'/extensions',
231
  'path' => $data['all_extensions'][$extension_name]->get_path() .'/extensions',
232
  'uri' => $data['all_extensions'][$extension_name]->get_uri() .'/extensions',
233
  'customizations_locations' => $customizations_locations,
304
 
305
  private function load_all_extensions()
306
  {
307
+ /**
308
+ * { '/hello/world/extensions' => 'https://hello.com/world/extensions' }
309
+ */
310
+ $custom_locations = apply_filters('fw_extensions_locations', array());
311
+
312
  {
313
  $customizations_locations = array();
314
 
319
 
320
  $customizations_locations[fw_get_template_customizations_directory('/extensions')]
321
  = fw_get_template_customizations_directory_uri('/extensions');
322
+
323
+ $customizations_locations += $custom_locations;
324
  }
325
 
326
  self::load_extensions(array(
329
  'customizations_locations' => $customizations_locations,
330
  ));
331
 
332
+ foreach ($custom_locations as $path => $uri) {
333
+ unset($customizations_locations[$path]);
 
 
334
  self::load_extensions(array(
335
  'path' => $path,
336
  'uri' => $uri,
444
  self::include_extension_file_all_locations($extension_name, '/helpers.php');
445
  self::include_extension_file_all_locations($extension_name, '/hooks.php');
446
 
447
+ if (self::$all_extensions[$extension_name]->_call_init(self::$access_key) !== false) {
448
  $this->activate_extensions($extension_name);
449
  }
450
 
512
  */
513
  public function _init()
514
  {
515
+ self::$access_key = new FW_Access_Key('fw_extensions');
516
+
517
  $this->load_all_extensions();
518
  $this->add_actions();
519
  }
framework/core/extends/class-fw-extension.php CHANGED
@@ -32,6 +32,11 @@ abstract class FW_Extension
32
  */
33
  private $parent;
34
 
 
 
 
 
 
35
  /**
36
  * @var string
37
  */
@@ -66,10 +71,11 @@ abstract class FW_Extension
66
  self::$access_key = new FW_Access_Key('extension');
67
  }
68
 
69
- $this->path = $data['path'];
70
- $this->uri = $data['uri'];
71
- $this->parent = $data['parent'];
72
- $this->depth = $data['depth'];
 
73
  $this->customizations_locations = $data['customizations_locations'];
74
 
75
  {
@@ -119,10 +125,15 @@ abstract class FW_Extension
119
 
120
  /**
121
  * @internal
122
- * fixme: ask access key from caller
 
123
  */
124
- final public function _call_init()
125
  {
 
 
 
 
126
  return $this->_init();
127
  }
128
 
@@ -437,12 +448,9 @@ abstract class FW_Extension
437
  return $this->customizations_locations;
438
  }
439
 
440
- /**
441
- * @deprecated
442
- */
443
  final public function get_rel_path()
444
  {
445
- return preg_replace('/^'. preg_quote(fw_get_framework_directory('/extensions'), '/') .'/', '', $this->get_path());
446
  }
447
 
448
  /**
32
  */
33
  private $parent;
34
 
35
+ /**
36
+ * @var string
37
+ */
38
+ private $rel_path;
39
+
40
  /**
41
  * @var string
42
  */
71
  self::$access_key = new FW_Access_Key('extension');
72
  }
73
 
74
+ $this->rel_path = $data['rel_path'];
75
+ $this->path = $data['path'];
76
+ $this->uri = $data['uri'];
77
+ $this->parent = $data['parent'];
78
+ $this->depth = $data['depth'];
79
  $this->customizations_locations = $data['customizations_locations'];
80
 
81
  {
125
 
126
  /**
127
  * @internal
128
+ * @param FW_Access_Key $access_key
129
+ * @return mixed
130
  */
131
+ final public function _call_init($access_key)
132
  {
133
+ if ($access_key->get_key() !== 'fw_extensions') {
134
+ trigger_error(__METHOD__ .' denied', E_USER_ERROR);
135
+ }
136
+
137
  return $this->_init();
138
  }
139
 
448
  return $this->customizations_locations;
449
  }
450
 
 
 
 
451
  final public function get_rel_path()
452
  {
453
+ return $this->rel_path;
454
  }
455
 
456
  /**
framework/core/extends/interface-fw-option-handler.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php if (!defined('FW')) die('Forbidden');
2
+
3
+ interface FW_Option_Handler
4
+ {
5
+ function get_option_value($option_id, $option, $data = array());
6
+
7
+ function save_option_value($option_id, $option, $value, $data = array());
8
+ }
9
+
framework/includes/option-types/rgba-color-picker/class-fw-option-type-rgba-color-picker.php CHANGED
@@ -51,7 +51,7 @@ class FW_Option_Type_Rgba_Color_Picker extends FW_Option_Type {
51
  * @internal
52
  */
53
  protected function _get_value_from_input( $option, $input_value ) {
54
- if ( ! empty( $input_value ) ) {
55
  $input_value = trim($input_value);
56
  $input_value = (
57
  preg_match( '/^#[a-f0-9]{3}([a-f0-9]{3})?$/i', $input_value )
51
  * @internal
52
  */
53
  protected function _get_value_from_input( $option, $input_value ) {
54
+ if ( ! isset( $input_value ) ) {
55
  $input_value = trim($input_value);
56
  $input_value = (
57
  preg_match( '/^#[a-f0-9]{3}([a-f0-9]{3})?$/i', $input_value )
framework/includes/option-types/rgba-color-picker/static/js/scripts.js CHANGED
@@ -49,6 +49,12 @@
49
 
50
  $input.css('background-color', ui.color.toCSS());
51
  $input.css('color', ($alpha_slider.slider("value") > 40) ? ui.color.getMaxContrastColor().toCSS() : '#000000');
 
 
 
 
 
 
52
  }
53
  });
54
 
@@ -103,6 +109,12 @@
103
  var new_alpha_val = parseFloat(ui.value),
104
  iris = $input.data('a8cIris');
105
  iris._color._alpha = new_alpha_val / 100.0;
 
 
 
 
 
 
106
  }
107
  });
108
 
49
 
50
  $input.css('background-color', ui.color.toCSS());
51
  $input.css('color', ($alpha_slider.slider("value") > 40) ? ui.color.getMaxContrastColor().toCSS() : '#000000');
52
+
53
+ $input.trigger('fw:rgba:color:picker:changed', {
54
+ $element: $input,
55
+ iris: $input.data('a8cIris'),
56
+ alphaSlider: $alpha_slider.data('uiSlider')
57
+ });
58
  }
59
  });
60
 
109
  var new_alpha_val = parseFloat(ui.value),
110
  iris = $input.data('a8cIris');
111
  iris._color._alpha = new_alpha_val / 100.0;
112
+
113
+ $input.trigger('fw:rgba:color:picker:changed', {
114
+ $element: $input,
115
+ iris: $input.data('a8cIris'),
116
+ alphaSlider: $alpha_slider.data('uiSlider')
117
+ });
118
  }
119
  });
120
 
framework/includes/option-types/wp-editor/class-fw-option-type-wp-editor.php CHANGED
@@ -64,23 +64,23 @@ class FW_Option_Type_Wp_Editor extends FW_Option_Type {
64
  }
65
 
66
  private function get_teeny_preset( $option ) {
67
- return array(
68
  'menubar' => false,
69
  'wpautop' => $option['wpautop'],
70
  'tabfocus_elements' => ":prev,:next",
71
  'toolbar1' => "bold,italic,strikethrough,bullist,numlist,blockquote,hr,alignleft,aligncenter,alignright,link,unlink,wp_more,spellchecker,fullscreen,wp_adv",
72
- 'toolbar2' => "underline,alignjustify,forecolor,pastetext,removeformat,charmap,outdent,indent,undo,redo",
73
  'plugins' => "hr,tabfocus,fullscreen,wordpress,wpeditimage",
74
  'preview_styles' => 'font-family font-size font-weight font-style text-decoration text-transform',
75
  'content_css' => $this->_get_tmce_content_css(),
76
  'language' => $this->_get_tmce_locale(),
77
  'relative_urls' => false,
78
  'remove_script_host' => false,
79
- );
80
  }
81
 
82
  private function get_extended_preset( $option ) {
83
- return array(
84
  'theme' => 'modern',
85
  'skin' => 'lightgray',
86
  'formats' => array(
@@ -133,7 +133,7 @@ class FW_Option_Type_Wp_Editor extends FW_Option_Type {
133
  'menubar' => false,
134
  'indent' => false,
135
  'toolbar1' => 'bold,italic,strikethrough,bullist,numlist,blockquote,hr,alignleft,aligncenter,alignright,link,unlink,wp_more,spellchecker,fullscreen,wp_adv',
136
- 'toolbar2' => 'formatselect,underline,alignjustify,forecolor,pastetext,removeformat,charmap,outdent,indent,undo,redo,wp_help',
137
  'toolbar3' => '',
138
  'toolbar4' => '',
139
  'tabfocus_elements' => ':prev,:next',
@@ -141,7 +141,17 @@ class FW_Option_Type_Wp_Editor extends FW_Option_Type {
141
  'content_css' => $this->_get_tmce_content_css(),
142
  'language' => $this->_get_tmce_locale(),
143
  'wpautop' => $option['wpautop'],
144
- );
 
 
 
 
 
 
 
 
 
 
145
  }
146
 
147
  /**
@@ -318,7 +328,7 @@ class FW_Option_Type_Wp_Editor extends FW_Option_Type {
318
  $value = (string) $input_value;
319
 
320
  if ( $option['wpautop'] === true ) {
321
- $value = preg_replace("/\n/i","", wpautop( $value ));
322
  }
323
 
324
  return $value;
64
  }
65
 
66
  private function get_teeny_preset( $option ) {
67
+ return apply_filters( 'wp_editor_settings', array(
68
  'menubar' => false,
69
  'wpautop' => $option['wpautop'],
70
  'tabfocus_elements' => ":prev,:next",
71
  'toolbar1' => "bold,italic,strikethrough,bullist,numlist,blockquote,hr,alignleft,aligncenter,alignright,link,unlink,wp_more,spellchecker,fullscreen,wp_adv",
72
+ 'toolbar2' => implode(',', apply_filters( 'mce_buttons_2', array( 'formatselect', 'underline', 'alignjustify', 'forecolor', 'pastetext', 'removeformat', 'charmap', 'outdent', 'indent', 'undo', 'redo', 'wp_help' ), $option['attr']['id'] )),
73
  'plugins' => "hr,tabfocus,fullscreen,wordpress,wpeditimage",
74
  'preview_styles' => 'font-family font-size font-weight font-style text-decoration text-transform',
75
  'content_css' => $this->_get_tmce_content_css(),
76
  'language' => $this->_get_tmce_locale(),
77
  'relative_urls' => false,
78
  'remove_script_host' => false,
79
+ ), $option['attr']['id'] );
80
  }
81
 
82
  private function get_extended_preset( $option ) {
83
+ $return = apply_filters('tiny_mce_before_init', array(
84
  'theme' => 'modern',
85
  'skin' => 'lightgray',
86
  'formats' => array(
133
  'menubar' => false,
134
  'indent' => false,
135
  'toolbar1' => 'bold,italic,strikethrough,bullist,numlist,blockquote,hr,alignleft,aligncenter,alignright,link,unlink,wp_more,spellchecker,fullscreen,wp_adv',
136
+ 'toolbar2' => implode(',', apply_filters( 'mce_buttons_2', array( 'formatselect', 'underline', 'alignjustify', 'forecolor', 'pastetext', 'removeformat', 'charmap', 'outdent', 'indent', 'undo', 'redo', 'wp_help' ), $option['attr']['id'] )),
137
  'toolbar3' => '',
138
  'toolbar4' => '',
139
  'tabfocus_elements' => ':prev,:next',
141
  'content_css' => $this->_get_tmce_content_css(),
142
  'language' => $this->_get_tmce_locale(),
143
  'wpautop' => $option['wpautop'],
144
+ ), $option['attr']['id']);
145
+
146
+ foreach ( $return as $key => $item ) {
147
+ if ( ! is_string( $item ) || ! is_array( json_decode( $item, true ) ) ) {
148
+ continue;
149
+ }
150
+
151
+ $return[$key] = json_decode($item, true);
152
+ }
153
+
154
+ return $return;
155
  }
156
 
157
  /**
328
  $value = (string) $input_value;
329
 
330
  if ( $option['wpautop'] === true ) {
331
+ $value = preg_replace( "/\n/i", "", wpautop( $value ) );
332
  }
333
 
334
  return $value;
framework/manifest.php CHANGED
@@ -4,4 +4,4 @@ $manifest = array();
4
 
5
  $manifest['name'] = __('Unyson', 'fw');
6
 
7
- $manifest['version'] = '2.2.1';
4
 
5
  $manifest['name'] = __('Unyson', 'fw');
6
 
7
+ $manifest['version'] = '2.2.2';
framework/static/js/fw.js CHANGED
@@ -495,12 +495,56 @@ fw.getQueryString = function(name) {
495
  this.$el.find('.fw-options-tabs-contents > .fw-inner > .fw-options-tab')
496
  .append('<div class="fw-backend-options-last-border-hider"></div>');
497
  }
 
 
498
  },
499
  initialize: function() {
500
  this.listenTo(this.model, 'change:html', this.render);
501
  },
502
  onSubmit: function(e) {
503
  e.preventDefault();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
504
  }
505
  });
506
 
@@ -726,47 +770,12 @@ fw.getQueryString = function(name) {
726
  text: _fw_localized.l10n.save,
727
  priority: 40,
728
  click: function () {
729
- fw.loading.show();
730
-
731
- jQuery.ajax({
732
- url: ajaxurl,
733
- type: 'POST',
734
- data: [
735
- 'action=fw_backend_options_get_values',
736
- 'options='+ encodeURIComponent(JSON.stringify(modal.get('options'))),
737
- 'name_prefix=fw_edit_options_modal',
738
- modal.contentView.$el.serialize()
739
- ].join('&'),
740
- dataType: 'json',
741
- success: function (response, status, xhr) {
742
- fw.loading.hide();
743
-
744
- if (!response.success) {
745
- /**
746
- * do not replace html here
747
- * user completed the form with data and wants to submit data
748
- * do not delete all his work
749
- */
750
- alert('Error: '+ response.data.message);
751
- return;
752
- }
753
-
754
- modal.set('values', response.data.values);
755
-
756
- // simulate click on close button to fire animations
757
- modal.frame.modal.$el.find('.media-modal-close').trigger('click');
758
- },
759
- error: function (xhr, status, error) {
760
- fw.loading.hide();
761
-
762
- /**
763
- * do not replace html here
764
- * user completed the form with data and wants to submit data
765
- * do not delete all his work
766
- */
767
- alert(status +': '+ error.message);
768
- }
769
- });
770
  }
771
  }
772
  ]
495
  this.$el.find('.fw-options-tabs-contents > .fw-inner > .fw-options-tab')
496
  .append('<div class="fw-backend-options-last-border-hider"></div>');
497
  }
498
+
499
+ this.$el.append('<input type="submit" class="fw-hidden hidden-submit" />');
500
  },
501
  initialize: function() {
502
  this.listenTo(this.model, 'change:html', this.render);
503
  },
504
  onSubmit: function(e) {
505
  e.preventDefault();
506
+
507
+ fw.loading.show();
508
+
509
+ jQuery.ajax({
510
+ url: ajaxurl,
511
+ type: 'POST',
512
+ data: [
513
+ 'action=fw_backend_options_get_values',
514
+ 'options='+ encodeURIComponent(JSON.stringify(this.model.get('options'))),
515
+ 'name_prefix=fw_edit_options_modal',
516
+ this.$el.serialize()
517
+ ].join('&'),
518
+ dataType: 'json',
519
+ success: _.bind(function (response, status, xhr) {
520
+ fw.loading.hide();
521
+
522
+ if (!response.success) {
523
+ /**
524
+ * do not replace html here
525
+ * user completed the form with data and wants to submit data
526
+ * do not delete all his work
527
+ */
528
+ alert('Error: '+ response.data.message);
529
+ return;
530
+ }
531
+
532
+ this.model.set('values', response.data.values);
533
+
534
+ // simulate click on close button to fire animations
535
+ this.model.frame.modal.$el.find('.media-modal-close').trigger('click');
536
+ }, this),
537
+ error: function (xhr, status, error) {
538
+ fw.loading.hide();
539
+
540
+ /**
541
+ * do not replace html here
542
+ * user completed the form with data and wants to submit data
543
+ * do not delete all his work
544
+ */
545
+ alert(status +': '+ error.message);
546
+ }
547
+ });
548
  }
549
  });
550
 
770
  text: _fw_localized.l10n.save,
771
  priority: 40,
772
  click: function () {
773
+ /**
774
+ * Simulate form submit
775
+ * Important: Empty input[required] must not start form submit
776
+ * and must show default browser warning popup "This field is required"
777
+ */
778
+ modal.contentView.$el.find('input[type="submit"].hidden-submit').trigger('click');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
779
  }
780
  }
781
  ]
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: unyson, themefusecom
3
  Tags: page builder, cms, grid, layout, responsive, back up, backup, db backup, dump, migrate, schedule, search engine optimization, seo, media, slideshow, shortcode, slide, slideshare, slideshow, google sitemaps, sitemaps, analytics, google analytics, calendar, event, events, google maps, learning, lessons, sidebars, breadcrumbs, review, portfolio, framework
4
  Requires at least: 4.0.0
5
  Tested up to: 4.1
6
- Stable tag: 2.2.1
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -86,6 +86,11 @@ Yes; Unyson will work with any theme.
86
 
87
  == Changelog ==
88
 
 
 
 
 
 
89
  = 2.2.1 =
90
  * Fixed: Sub-extensions were not loaded [#368](https://github.com/ThemeFuse/Unyson/issues/368)
91
  * Fixed: $extension->locate_URI('/...') bug
3
  Tags: page builder, cms, grid, layout, responsive, back up, backup, db backup, dump, migrate, schedule, search engine optimization, seo, media, slideshow, shortcode, slide, slideshare, slideshow, google sitemaps, sitemaps, analytics, google analytics, calendar, event, events, google maps, learning, lessons, sidebars, breadcrumbs, review, portfolio, framework
4
  Requires at least: 4.0.0
5
  Tested up to: 4.1
6
+ Stable tag: 2.2.2
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
86
 
87
  == Changelog ==
88
 
89
+ = 2.2.2 =
90
+ * Added experimental `$option['option_handler']` [636ed56](https://github.com/ThemeFuse/Unyson/commit/636ed56fe499a4e855b5f49198747460833539a3)
91
+ * `<input required ... />` works in `fw.OptionsModal` [#274](https://github.com/ThemeFuse/Unyson/issues/274)
92
+ * Fixed [#381](https://github.com/ThemeFuse/Unyson/issues/381), [#382](https://github.com/ThemeFuse/Unyson/issues/382), [#385](https://github.com/ThemeFuse/Unyson/issues/385), [Shortcodes#15](https://github.com/ThemeFuse/Unyson-Shortcodes-Extension/issues/15)
93
+
94
  = 2.2.1 =
95
  * Fixed: Sub-extensions were not loaded [#368](https://github.com/ThemeFuse/Unyson/issues/368)
96
  * Fixed: $extension->locate_URI('/...') bug
unyson.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Unyson
4
  * Plugin URI: http://unyson.themefuse.com/
5
  * Description: A free drag & drop framework that comes with a bunch of built in extensions that will help you develop premium themes fast & easy.
6
- * Version: 2.2.1
7
  * Author: ThemeFuse
8
  * Author URI: http://themefuse.com
9
  * License: GPL2+
3
  * Plugin Name: Unyson
4
  * Plugin URI: http://unyson.themefuse.com/
5
  * Description: A free drag & drop framework that comes with a bunch of built in extensions that will help you develop premium themes fast & easy.
6
+ * Version: 2.2.2
7
  * Author: ThemeFuse
8
  * Author URI: http://themefuse.com
9
  * License: GPL2+