Data Tables Generator by Supsystic - Version 1.8.3

Version Description

/ 07.05.2018 = * Add options: Disable Table Cache * Add of constant SUPSYSTIC_STB_FOOTER_FIX for enable / disable fix for themes without wp_footer() * Fix of calculation of formulas: INDEX, MIN, MAX * Fix of displaying of diagrams as table's content * Fix of applying of invisible cells on frontend * Fix of export table to PDF * Fix of conflict with WPML plugin * Optimized labels for Frontend Fields

Download this release

Release Info

Developer supsystic.com
Plugin Icon 128x128 Data Tables Generator by Supsystic
Version 1.8.3
Comparing to
See all releases

Code changes from version 1.8.2 to 1.8.3

app/SupsysticTables.php CHANGED
@@ -16,47 +16,42 @@ class SupsysticTables
16
 
17
  add_action('init', array($this, 'addShortcodeButton'));
18
 
 
19
  $pluginPath = dirname(dirname(__FILE__));
20
- $environment = new Rsc_Environment('st', '1.8.2', $pluginPath);
21
 
22
  /* Configure */
23
  $environment->configure(
24
  array(
25
- 'optimizations' => 1,
26
- 'environment' => $this->getPluginEnvironment(),
27
- 'default_module' => 'tables',
28
- 'lang_domain' => 'supsystic_tables',
29
- 'lang_path' => plugin_basename(dirname(__FILE__)) . '/langs',
30
- 'plugin_prefix' => 'SupsysticTables',
31
- 'plugin_source' => $pluginPath . '/src',
32
  'plugin_title_name' => 'Data Tables',
33
- 'plugin_menu' => array(
34
- 'page_title' => __(
35
- 'Tables by Supsystic',
36
- 'supsystic-tables'
37
- ),
38
- 'menu_title' => __(
39
- 'Tables by Supsystic',
40
- 'supsystic-tables'
41
- ),
42
  'capability' => 'manage_options',
43
- 'menu_slug' => 'supsystic-tables',
44
  'icon_url' => 'dashicons-editor-table',
45
  'position' => '102.2',
46
  ),
47
- 'shortcode_name' => defined('SUPSYSTIC_TABLES_SHORTCODE_NAME') ? SUPSYSTIC_TABLES_SHORTCODE_NAME : 'supsystic-tables',
48
- 'shortcode_value_name' => defined('SUPSYSTIC_TABLES_VALUE_SHORTCODE_NAME') ? SUPSYSTIC_TABLES_VALUE_SHORTCODE_NAME : 'supsystic-tables-cell',
49
- 'shortcode_cell_name' => defined('SUPSYSTIC_TABLES_CELL_SHORTCODE_NAME') ? SUPSYSTIC_TABLES_CELL_SHORTCODE_NAME : 'supsystic-tables-cell-full',
50
- 'shortcode_part_name' => defined('SUPSYSTIC_TABLES_PART_SHORTCODE_NAME') ? SUPSYSTIC_TABLES_PART_SHORTCODE_NAME : 'supsystic-tables-part',
51
- 'db_prefix' => 'supsystic_tbl_',
52
- 'hooks_prefix' => 'supsystic_tbl_',
53
- 'ajax_url' => admin_url('admin-ajax.php'),
54
- 'admin_url' => admin_url(),
55
- 'plugin_db_update' => true,
56
- 'revision_key' => '_supsystic_tables_rev',
57
- 'revision' => 60,
58
- 'welcome_page_was_showed' => get_option('supsystic_tbl_welcome_page_was_showed'),
59
- 'promo_controller' => 'SupsysticTables_Promo_Controller'
60
  )
61
  );
62
 
16
 
17
  add_action('init', array($this, 'addShortcodeButton'));
18
 
19
+ $menuSlug = 'supsystic-tables';
20
  $pluginPath = dirname(dirname(__FILE__));
21
+ $environment = new Rsc_Environment('st', '1.8.3', $pluginPath);
22
 
23
  /* Configure */
24
  $environment->configure(
25
  array(
26
+ 'optimizations' => 1,
27
+ 'environment' => $this->getPluginEnvironment(),
28
+ 'default_module' => 'tables',
29
+ 'lang_domain' => 'supsystic_tables',
30
+ 'lang_path' => plugin_basename(dirname(__FILE__)) . '/langs',
31
+ 'plugin_prefix' => 'SupsysticTables',
32
+ 'plugin_source' => $pluginPath . '/src',
33
  'plugin_title_name' => 'Data Tables',
34
+ 'plugin_menu' => array(
35
+ 'page_title' => __('Tables by Supsystic', $menuSlug),
36
+ 'menu_title' => __('Tables by Supsystic', $menuSlug),
 
 
 
 
 
 
37
  'capability' => 'manage_options',
38
+ 'menu_slug' => $menuSlug,
39
  'icon_url' => 'dashicons-editor-table',
40
  'position' => '102.2',
41
  ),
42
+ 'shortcode_name' => defined('SUPSYSTIC_TABLES_SHORTCODE_NAME') ? SUPSYSTIC_TABLES_SHORTCODE_NAME : $menuSlug,
43
+ 'shortcode_value_name' => defined('SUPSYSTIC_TABLES_VALUE_SHORTCODE_NAME') ? SUPSYSTIC_TABLES_VALUE_SHORTCODE_NAME : $menuSlug . '-cell',
44
+ 'shortcode_cell_name' => defined('SUPSYSTIC_TABLES_CELL_SHORTCODE_NAME') ? SUPSYSTIC_TABLES_CELL_SHORTCODE_NAME : $menuSlug . '-cell-full',
45
+ 'shortcode_part_name' => defined('SUPSYSTIC_TABLES_PART_SHORTCODE_NAME') ? SUPSYSTIC_TABLES_PART_SHORTCODE_NAME : $menuSlug . '-part',
46
+ 'db_prefix' => 'supsystic_tbl_',
47
+ 'hooks_prefix' => 'supsystic_tbl_',
48
+ 'ajax_url' => admin_url('admin-ajax.php'),
49
+ 'admin_url' => admin_url(),
50
+ 'plugin_db_update' => true,
51
+ 'revision_key' => '_supsystic_tables_rev',
52
+ 'revision' => 60,
53
+ 'welcome_page_was_showed' => get_option('supsystic_tbl_welcome_page_was_showed'),
54
+ 'promo_controller' => 'SupsysticTables_Promo_Controller'
55
  )
56
  );
57
 
app/assets/css/supsystic-ui.css CHANGED
@@ -829,8 +829,10 @@ h3.nav-tab-wrapper {
829
  }
830
 
831
  .supsystic-pro-feature {
 
832
  color: #0074a2 !important;
833
  font-size: 10px !important;
 
834
  text-decoration: none !important;
835
  }
836
 
829
  }
830
 
831
  .supsystic-pro-feature {
832
+ display: block;
833
  color: #0074a2 !important;
834
  font-size: 10px !important;
835
+ line-height: 11px;
836
  text-decoration: none !important;
837
  }
838
 
app/assets/js/buttons.js CHANGED
@@ -1,41 +1,60 @@
1
- if(typeof(SDT_DATA) == 'undefined')
2
- var SDT_DATA = {};
3
-
4
  (function($) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- var dialogClass = '.data-tables-select-dialog',
7
- initDialog = function() {
8
- var $container = $('#post-body-content');
9
-
10
- $container.append(
11
- '<div class="data-tables-select-dialog" hidden>' +
12
- '<h3>Select table to insert</h3>' +
13
- '<select></select>' +
14
- '<button class="button button-primary">Select</button>' +
15
- '</div>');
 
 
 
 
16
 
17
- var url = '';
 
 
 
 
 
 
 
18
 
19
- if(typeof(wp.ajax) == 'undefined')
20
- url = SDT_DATA.ajaxurl;
21
- else
22
- url = wp.ajax.settings.url;
23
-
24
- $.post(url, {
25
- action: 'supsystic-tables',
26
- route: {
27
- module: 'tables',
28
- action: 'list'
29
- }
30
- }, function(response) {
31
- $.each(response.tables, function(index, value) {
32
- $container.find(dialogClass + ' select').append(
33
- '<option value="' + value.id + '">' + value.title + '</option>'
34
- );
35
- });
36
- }
37
- );
38
- };
39
 
40
  tinymce.create('tinymce.plugins.addShortcodeDataTable', {
41
  /**
@@ -52,20 +71,20 @@ if(typeof(SDT_DATA) == 'undefined')
52
  cmd : 'addShortcodeDataTable',
53
  image : url + '/img/logo_datatable.png'
54
  });
55
-
56
- initDialog();
57
-
58
  ed.addCommand('addShortcodeDataTable', function() {
59
- var $dialog = $(dialogClass).bPopup({
60
- onClose: function() {
61
- $(dialogClass + ' button').off('click');
 
 
 
 
62
  }
63
  }, function() {
64
- $(dialogClass + ' button').on('click', function() {
65
- var selected = $(dialogClass).find('select').val(),
66
- text = '[supsystic-tables id=' + selected + ' ]';
67
- ed.execCommand('mceInsertContent', 0, text);
68
- $dialog.close();
69
  });
70
  });
71
  });
1
+ if(typeof(SDT_DATA) == 'undefined') {
2
+ var SDT_DATA = {};
3
+ }
4
  (function($) {
5
+ var btnCreateObj = {
6
+ container: 'body',
7
+ dialogClass: '.data-tables-select-dialog',
8
+ dataList: null,
9
+ initDialog: function() {
10
+ $(this.container).append(
11
+ '<div class="data-tables-select-dialog" hidden>' +
12
+ '<h1 style="text-align: center;">Select Data Table</h1>' +
13
+ '<select></select>' +
14
+ '<button class="button button-primary">Insert</button>' +
15
+ '</div>');
16
+ btnCreateObj.setSelectboxOpts();
17
+ },
18
+ setSelectboxOpts: function() {
19
+ var self = this,
20
+ $container = $(self.container),
21
+ select = $container.find(self.dialogClass + ' select');
22
 
23
+ if(self.dataList === null) {
24
+ self.setDataList();
25
+ } else if(self.dataList.length) {
26
+ $.each(self.dataList, function(index, value) {
27
+ select.append('<option value="' + value.id + '">' + value.title + '</option>');
28
+ });
29
+ } else {
30
+ select.append('<option value="0">No tables for now...</option>');
31
+ select.attr('disabled', 'disabled');
32
+ }
33
+ },
34
+ setDataList: function() {
35
+ var self = this,
36
+ url = typeof(wp.ajax) == 'undefined' ? SDT_DATA.ajaxurl : wp.ajax.settings.url;
37
 
38
+ $.post(url, {
39
+ action: 'supsystic-tables',
40
+ route: {
41
+ module: 'tables',
42
+ action: 'list'
43
+ }
44
+ }, function(response) {
45
+ self.dataList = [];
46
 
47
+ if(response.tables.length) {
48
+ $.each(response.tables, function(index, value) {
49
+ self.dataList.push({id: value.id, title: value.title});
50
+ });
51
+ }
52
+ self.setSelectboxOpts();
53
+ }
54
+ );
55
+ }
56
+ },
57
+ dialogIsInit = false;
 
 
 
 
 
 
 
 
 
58
 
59
  tinymce.create('tinymce.plugins.addShortcodeDataTable', {
60
  /**
71
  cmd : 'addShortcodeDataTable',
72
  image : url + '/img/logo_datatable.png'
73
  });
 
 
 
74
  ed.addCommand('addShortcodeDataTable', function() {
75
+ if (!dialogIsInit) {
76
+ btnCreateObj.initDialog();
77
+ dialogIsInit = true;
78
+ }
79
+ var $dialog = $(btnCreateObj.dialogClass).bPopup({
80
+ onClose: function() {
81
+ $(btnCreateObj.dialogClass + ' button').off('click');
82
  }
83
  }, function() {
84
+ $(btnCreateObj.dialogClass + ' button').on('click', function() {
85
+ var selected = $(btnCreateObj.dialogClass).find('select').val();
86
+ ed.execCommand('mceInsertContent', 0, '[supsystic-tables id=' + selected + ']');
87
+ $dialog.close();
 
88
  });
89
  });
90
  });
index.php CHANGED
@@ -4,7 +4,7 @@
4
  * Plugin Name: Data Tables Generator by Supsystic
5
  * Plugin URI: http://supsystic.com
6
  * Description: Create and manage beautiful data tables with custom design. No HTML knowledge is required
7
- * Version: 1.8.2
8
  * Author: supsystic.com
9
  * Author URI: http://supsystic.com
10
  */
@@ -20,6 +20,9 @@ if (!defined('SUPSYSTIC_TABLES_VALUE_SHORTCODE_NAME')) {
20
  if (!defined('SUPSYSTIC_TABLES_CELL_SHORTCODE_NAME')) {
21
  define('SUPSYSTIC_TABLES_CELL_SHORTCODE_NAME', 'supsystic-tables-cell-full');
22
  }
 
 
 
23
 
24
  $supsysticTables = new SupsysticTables();
25
  $supsysticTables->activate(__FILE__);
4
  * Plugin Name: Data Tables Generator by Supsystic
5
  * Plugin URI: http://supsystic.com
6
  * Description: Create and manage beautiful data tables with custom design. No HTML knowledge is required
7
+ * Version: 1.8.3
8
  * Author: supsystic.com
9
  * Author URI: http://supsystic.com
10
  */
20
  if (!defined('SUPSYSTIC_TABLES_CELL_SHORTCODE_NAME')) {
21
  define('SUPSYSTIC_TABLES_CELL_SHORTCODE_NAME', 'supsystic-tables-cell-full');
22
  }
23
+ if (!defined('SUPSYSTIC_STB_DEBUG')) {
24
+ define('SUPSYSTIC_STB_DEBUG', false);
25
+ }
26
 
27
  $supsysticTables = new SupsysticTables();
28
  $supsysticTables->activate(__FILE__);
readme.txt CHANGED
@@ -2,7 +2,7 @@
2
  Contributors: supsystic.com
3
  Tags: csv, csv file, csv to table, excel, table, tablesorter, post, data table, table, database, html table, table generator, builder, generator, cells, area chart, bar chart, candlestick chart, canvas, chart, charting, charts, column chart, gauge chart, geo chart, google chart, google visualization api, graph, graphing, graphs, html5, line chart, pie chart, scatter chart, spreadsheet, visualisation, visualise data, visualization, visualize data
4
  Tested up to: 4.9.5
5
- Stable tag: 1.8.2
6
 
7
  Create data tables with charts and graphs. Custom design, navigation, searching and ordering functions. Export to PDF, CSV, Print. Excel spreadsheet
8
 
@@ -194,6 +194,16 @@ Important! Shortcode must be inserted in a text editor page, and not in the visu
194
 
195
  == Changelog ==
196
 
 
 
 
 
 
 
 
 
 
 
197
  = 1.8.2 / 20.04.2018 =
198
  * Hotfix by compatibility with old pro versions
199
 
2
  Contributors: supsystic.com
3
  Tags: csv, csv file, csv to table, excel, table, tablesorter, post, data table, table, database, html table, table generator, builder, generator, cells, area chart, bar chart, candlestick chart, canvas, chart, charting, charts, column chart, gauge chart, geo chart, google chart, google visualization api, graph, graphing, graphs, html5, line chart, pie chart, scatter chart, spreadsheet, visualisation, visualise data, visualization, visualize data
4
  Tested up to: 4.9.5
5
+ Stable tag: 1.8.3
6
 
7
  Create data tables with charts and graphs. Custom design, navigation, searching and ordering functions. Export to PDF, CSV, Print. Excel spreadsheet
8
 
194
 
195
  == Changelog ==
196
 
197
+ = 1.8.3 / 07.05.2018 =
198
+ * Add options: Disable Table Cache
199
+ * Add of constant SUPSYSTIC_STB_FOOTER_FIX for enable / disable fix for themes without wp_footer()
200
+ * Fix of calculation of formulas: INDEX, MIN, MAX
201
+ * Fix of displaying of diagrams as table's content
202
+ * Fix of applying of invisible cells on frontend
203
+ * Fix of export table to PDF
204
+ * Fix of conflict with WPML plugin
205
+ * Optimized labels for Frontend Fields
206
+
207
  = 1.8.2 / 20.04.2018 =
208
  * Hotfix by compatibility with old pro versions
209
 
src/SupsysticTables/Core/Module.php CHANGED
@@ -8,7 +8,20 @@ class SupsysticTables_Core_Module extends SupsysticTables_Core_BaseModule
8
  */
9
  protected $modelsFactory;
10
 
11
- private $ajaxRoute;
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
  /**
14
  * {@inheritdoc}
@@ -24,7 +37,7 @@ class SupsysticTables_Core_Module extends SupsysticTables_Core_BaseModule
24
  $config->add('plugin_url', $url);
25
  $config->add('plugin_path', $path);
26
 
27
- $this->registerAjaxRequestHandler();
28
  $this->registerTwigFunctions();
29
  $this->update();
30
 
@@ -64,7 +77,7 @@ class SupsysticTables_Core_Module extends SupsysticTables_Core_BaseModule
64
  wp_localize_script('tables-core', 'g_stbStandartFontsList', $standardFontsList);
65
  }
66
 
67
- /**
68
  * {@inheritdoc}
69
  */
70
  public function afterUiLoaded(SupsysticTables_Ui_Module $ui)
@@ -178,7 +191,7 @@ class SupsysticTables_Core_Module extends SupsysticTables_Core_BaseModule
178
  );
179
  }
180
 
181
- /**
182
  * Returns the models factory
183
  * @return SupsysticTables_Core_ModelsFactory
184
  */
@@ -202,85 +215,109 @@ class SupsysticTables_Core_Module extends SupsysticTables_Core_BaseModule
202
  }
203
 
204
  /**
205
- * Parse the ajax requests.
206
  * @return mixed
207
  */
208
- public function parseAjaxRequest() {
209
  $request = $this->getRequest();
210
- $this->setAjaxRoute($request->post->get('route'));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
  }
212
 
213
- public function setAjaxRoute($route) {
214
- $this->ajaxRoute = $route;
215
  }
216
 
217
- public function getAjaxRoute() {
218
- return $this->ajaxRoute;
 
 
 
219
  }
220
 
221
  /**
222
  * Handles the ajax requests and returns the response.
223
  * @return mixed
224
  */
225
- public function handleAjaxRequest()
 
 
 
 
 
 
 
 
 
 
226
  {
227
  $environment = $this->getEnvironment();
228
  $request = $this->getRequest();
229
- $route = $this->getAjaxRoute();
 
 
230
 
231
  if (!array_key_exists('module', $route)) {
232
- wp_send_json_error(
233
- array(
234
- 'message' => $environment->translate(
235
- 'Invalid route specified: missing "module" key.'
236
- )
237
- )
238
- );
239
  }
240
-
241
  $moduleName = $route['module'];
242
- $actionName = 'indexAction';
243
 
244
- if (array_key_exists('action', $route)) {
245
- $actionName = $route['action'] . 'Action';
246
- }
 
247
 
248
- $module = $environment->getModule($moduleName);
249
  if (!$module) {
250
- wp_send_json_error(
251
- array(
252
- 'message' => sprintf(
253
- $environment->translate(
254
- 'You are requested to the non-existing module "%s".'
255
- ),
256
- $moduleName
257
- )
258
- )
259
- );
260
  }
261
-
262
  if (!method_exists($module->getController(), $actionName)) {
263
- wp_send_json_error(
264
- array(
265
- 'message' => sprintf(
266
- $environment->translate(
267
- 'You are requested to the non-existing route: %s::%s'
268
- ),
269
- $moduleName,
270
- $actionName
271
- )
272
- )
273
- );
274
- }
275
-
276
- $request->headers->add('X_REQUESTED_WITH', 'XMLHttpRequest');
277
-
278
- return call_user_func_array(
279
- array($module->getController(), $actionName),
280
- array($request)
281
- );
282
  }
283
 
 
 
 
 
 
 
 
 
 
 
284
  public function buildProUrl(array $parameters = array())
285
  {
286
  $config = $this->getEnvironment()->getConfig();
@@ -319,35 +356,50 @@ class SupsysticTables_Core_Module extends SupsysticTables_Core_BaseModule
319
  echo '<div class="error"><p>' . $message . '</p></div>';
320
  }
321
 
322
- /**
323
- * Registers the ajax request handler
324
- */
325
- private function registerAjaxRequestHandler()
326
- {
327
- $this->parseAjaxRequest();
328
- $route = $this->getAjaxRoute();
329
- $action_name = 'wp_ajax_supsystic-tables';
330
- $is_frontend = false;
331
-
332
- $frontendModulesAndMethods = array(
333
- 'tables' => array('saveEditableFields')
334
- );
335
-
336
- if(!empty($route)) {
337
- foreach($frontendModulesAndMethods as $module => $actions) {
 
 
338
  if(isset($route['module']) && $module == $route['module']) {
339
  if(isset($route['action']) && in_array($route['action'], $actions)) {
340
- $is_frontend = true;
341
  }
342
  }
343
  }
344
  }
345
-
346
- if($is_frontend && !is_user_logged_in()) {
347
- $action_name = 'wp_ajax_nopriv_supsystic-tables';
348
  }
349
  add_action($action_name, array($this, 'handleAjaxRequest'));
350
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
351
 
352
  /**
353
  * Updates the plugin database if it is needed.
8
  */
9
  protected $modelsFactory;
10
 
11
+ private $mainRequestRoute;
12
+
13
+ private $mainRequestAction;
14
+
15
+ private $mainRequestError = '';
16
+
17
+ private $frontendMethods = array(
18
+ 'ajax' => array(
19
+ 'tables' => array('saveEditableFields')
20
+ ),
21
+ 'post' => array(
22
+ 'importer' => array('import'),
23
+ ),
24
+ );
25
 
26
  /**
27
  * {@inheritdoc}
37
  $config->add('plugin_url', $url);
38
  $config->add('plugin_path', $path);
39
 
40
+ $this->registerMainRequestHandler();
41
  $this->registerTwigFunctions();
42
  $this->update();
43
 
77
  wp_localize_script('tables-core', 'g_stbStandartFontsList', $standardFontsList);
78
  }
79
 
80
+ /**
81
  * {@inheritdoc}
82
  */
83
  public function afterUiLoaded(SupsysticTables_Ui_Module $ui)
191
  );
192
  }
193
 
194
+ /**
195
  * Returns the models factory
196
  * @return SupsysticTables_Core_ModelsFactory
197
  */
215
  }
216
 
217
  /**
218
+ * Parse all requests on backend and frontend.
219
  * @return mixed
220
  */
221
+ public function parseMainRequest() {
222
  $request = $this->getRequest();
223
+ $this->setMainRequestRoute($request->post->get('route'));
224
+ $this->setMainRequestAction($request->post->get('action'));
225
+ }
226
+
227
+ public function setMainRequestRoute($route) {
228
+ $this->mainRequestRoute = $route;
229
+ }
230
+
231
+ public function getMainRequestRoute() {
232
+ return $this->mainRequestRoute;
233
+ }
234
+
235
+ public function setMainRequestAction($action) {
236
+ $this->mainRequestAction = $action;
237
+ }
238
+
239
+ public function getMainRequestAction() {
240
+ return $this->mainRequestAction;
241
+ }
242
+
243
+ public function getMainRequestError() {
244
+ return $this->mainRequestError;
245
  }
246
 
247
+ public function setMainRequestError($error) {
248
+ $this->mainRequestError = $error;
249
  }
250
 
251
+ public function getFrontendMethods($type = false) {
252
+ if(!empty($type)) {
253
+ return !empty($this->frontendMethods[$type]) ? $this->frontendMethods[$type] : false;
254
+ }
255
+ return $this->frontendMethods;
256
  }
257
 
258
  /**
259
  * Handles the ajax requests and returns the response.
260
  * @return mixed
261
  */
262
+ public function handleAjaxRequest()
263
+ {
264
+ $this->handleMainRequest(true);
265
+ }
266
+
267
+ public function handlePostRequest()
268
+ {
269
+ $this->handleMainRequest();
270
+ }
271
+
272
+ private function handleMainRequest($isAjax = false)
273
  {
274
  $environment = $this->getEnvironment();
275
  $request = $this->getRequest();
276
+ $route = $this->getMainRequestRoute();
277
+ $isDebug = defined('WP_DEBUG') && WP_DEBUG;
278
+ $isError = false;
279
 
280
  if (!array_key_exists('module', $route)) {
281
+ $isError = true;
282
+ $message = $environment->translate('Invalid route specified: missing "module" key.');
283
+ $this->throwHandleMainRequestError($message, $isAjax, $isDebug);
 
 
 
 
284
  }
 
285
  $moduleName = $route['module'];
286
+ $actionName = $isAjax ? 'indexAction' : '';
287
 
288
+ if (array_key_exists('action', $route)) {
289
+ $actionName = $route['action'] . 'Action';
290
+ }
291
+ $module = $environment->getModule($moduleName);
292
 
 
293
  if (!$module) {
294
+ $isError = true;
295
+ $message = sprintf($environment->translate('You are requested to the non-existing module "%s".'), $moduleName);
296
+ $this->throwHandleMainRequestError($message, $isAjax, $isDebug);
 
 
 
 
 
 
 
297
  }
 
298
  if (!method_exists($module->getController(), $actionName)) {
299
+ $isError = true;
300
+ $message = sprintf($environment->translate('You are requested to the non-existing route: %s::%s'), $moduleName, $actionName);
301
+ $this->throwHandleMainRequestError($message, $isAjax, $isDebug);
302
+ }
303
+ if($isAjax) {
304
+ $request->headers->add('X_REQUESTED_WITH', 'XMLHttpRequest');
305
+ }
306
+ if($isAjax || (!$isAjax && !$isError)) {
307
+ return call_user_func_array(array($module->getController(), $actionName), array($request));
308
+ }
 
 
 
 
 
 
 
 
 
309
  }
310
 
311
+ private function throwHandleMainRequestError($message, $isAjax, $isDebug) {
312
+ if ($isAjax) {
313
+ wp_send_json_error(array('message' => $message));
314
+ } else {
315
+ if ($isDebug) {
316
+ $this->setMainRequestError($message);
317
+ }
318
+ }
319
+ }
320
+
321
  public function buildProUrl(array $parameters = array())
322
  {
323
  $config = $this->getEnvironment()->getConfig();
356
  echo '<div class="error"><p>' . $message . '</p></div>';
357
  }
358
 
359
+ /**
360
+ * Registers the ajax request handler
361
+ */
362
+ private function registerMainRequestHandler()
363
+ {
364
+ $this->parseMainRequest();
365
+ $route = $this->getMainRequestRoute();
366
+ $action = $this->getMainRequestAction();
367
+ $config = $this->getEnvironment()->getConfig();
368
+ $action_name = 'wp_ajax_' . $config['plugin_menu']['menu_slug'];
369
+ $ajaxFrontendMethods = $this->getFrontendMethods('ajax');
370
+ $postFrontendMethods = $this->getFrontendMethods('post');
371
+ $isFrontendAjax = false;
372
+ $isFrontendPost = false;
373
+
374
+ // Ajax handler (for backend and frontend)
375
+ if(!empty($route) && !empty($ajaxFrontendMethods)) {
376
+ foreach($ajaxFrontendMethods as $module => $actions) {
377
  if(isset($route['module']) && $module == $route['module']) {
378
  if(isset($route['action']) && in_array($route['action'], $actions)) {
379
+ $isFrontendAjax = true;
380
  }
381
  }
382
  }
383
  }
384
+ if($isFrontendAjax && !is_user_logged_in()) {
385
+ $action_name = 'wp_ajax_nopriv_' . $config['plugin_menu']['menu_slug'];
 
386
  }
387
  add_action($action_name, array($this, 'handleAjaxRequest'));
388
+
389
+ // Post handler (for frontend only)
390
+ if($action == $config['plugin_menu']['menu_slug'] && !empty($route) && !empty($postFrontendMethods)) {
391
+ foreach($postFrontendMethods as $module => $actions) {
392
+ if(isset($route['module']) && $module == $route['module']) {
393
+ if(isset($route['action']) && in_array($route['action'], $actions)) {
394
+ $isFrontendPost = true;
395
+ }
396
+ }
397
+ }
398
+ }
399
+ if(!is_admin() && $isFrontendPost) {
400
+ add_action('init', array($this, 'handlePostRequest'));
401
+ }
402
+ }
403
 
404
  /**
405
  * Updates the plugin database if it is needed.
src/SupsysticTables/Core/assets/js/core.js CHANGED
@@ -36,12 +36,16 @@ if(typeof(SDT_DATA) == 'undefined') {
36
  return dataTableInstances;
37
  });
38
 
 
 
 
 
39
  vendor[appName].setTableInstance = (function(instance) {
40
  dataTableInstances.push(instance);
41
  });
42
 
43
  vendor[appName].getTableInstanceById = (function(id) {
44
- var allTables = vendor[appName].getAllTableInstances();
45
 
46
  for(var i = 0; i < allTables.length; i++) {
47
  if(allTables[i].table_id == id) {
@@ -52,7 +56,7 @@ if(typeof(SDT_DATA) == 'undefined') {
52
  });
53
 
54
  vendor[appName].getTableInstanceByViewId = (function(viewId) {
55
- var allTables = vendor[appName].getAllTableInstances();
56
 
57
  for(var i = 0; i < allTables.length; i++) {
58
  if(allTables[i].table_view_id == viewId) {
@@ -63,7 +67,7 @@ if(typeof(SDT_DATA) == 'undefined') {
63
  });
64
 
65
  vendor[appName].removeTableInstanceByViewId = (function(viewId) {
66
- var allTables = vendor[appName].getAllTableInstances();
67
 
68
  for(var i = 0; i < allTables.length; i++) {
69
  if(allTables[i].table_view_id == viewId) {
@@ -87,49 +91,74 @@ if(typeof(SDT_DATA) == 'undefined') {
87
  });
88
 
89
  vendor[appName].getRuleJSInstance = (function(table) {
90
- var allRuleJS = vendor[appName].getAllRuleJSInstances(),
91
  viewId = table.data('view-id');
92
 
93
  if(!allRuleJS[viewId]) {
94
- vendor[appName].setRuleJSInstance(table);
95
  }
96
  return allRuleJS[viewId];
97
  });
98
 
99
  vendor[appName].request = (function(route, data) {
100
- if (!$.isPlainObject(route) || !('module' in route) || !('action' in route)) {
101
- throw new Error('Request route is not specified.');
102
- }
103
-
104
  if (!$.isPlainObject(data)) {
105
  data = {};
106
  }
107
-
108
  if ('action' in data) {
109
  throw new Error('Reserved field "action" used.');
110
  }
111
-
112
  data.action = 'supsystic-tables';
113
 
114
- var url = window.ajaxurl ? window.ajaxurl : ajax_obj.ajaxurl,
115
- request = $.post(url, $.extend({}, { route: route }, data)),
116
- deferred = $.Deferred();
117
 
118
- request.done(function (response, textStatus, jqXHR) {
119
- if (typeof response.success !== 'undefined' && response.success) {
120
- deferred.resolve(response, textStatus, jqXHR);
121
- } else {
122
- var message = 'There are errors during the request.';
 
 
 
 
123
 
124
- if (typeof response.message !== 'undefined') {
125
- message = response.message;
126
- }
 
 
 
 
 
 
 
127
 
128
- deferred.reject(message, textStatus, jqXHR);
129
- }
130
- }).fail(function (jqXHR, textStatus, errorThrown) {
131
- deferred.reject(errorThrown, textStatus, jqXHR);
132
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
 
134
  return deferred.promise();
135
  });
@@ -162,7 +191,8 @@ if(typeof(SDT_DATA) == 'undefined') {
162
  reinit = typeof reinit != 'undefined' ? reinit : {};
163
  addInstance = typeof addInstance != 'undefined' ? addInstance : true;
164
 
165
- var $table = (table instanceof $ ? table : $(table)),
 
166
  features = $table.data('features'),
167
  config = {},
168
  responsiveMode = $table.data('responsive-mode'),
@@ -180,12 +210,12 @@ if(typeof(SDT_DATA) == 'undefined') {
180
  initComplete: callback,
181
  headerCallback: function( thead, data, start, end, display ) {
182
  $(thead).closest('thead').find('th').each(function() {
183
- setStylesToCell(this);
184
  });
185
  },
186
  footerCallback: function( tfoot, data, start, end, display ) {
187
  $(tfoot).closest('tfoot').find('th').each(function() {
188
- setStylesToCell(this);
189
  });
190
  }
191
  };
@@ -209,6 +239,42 @@ if(typeof(SDT_DATA) == 'undefined') {
209
  });
210
  }
211
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
  // Set features
213
  $.each(features, function () {
214
  var featureName = this.replace(/[-_]([a-z])/g, function (g) { return g[1].toUpperCase(); });
@@ -473,18 +539,13 @@ if(typeof(SDT_DATA) == 'undefined') {
473
  tableInstance = $table.dataTable($.extend({}, defaultFeatures, config, reinit));
474
  tableInstance.table_id = $table.data('id');
475
  tableInstance.table_view_id = $table.data('view-id');
476
- tableInstance.fnFakeRowspan();
477
- // Only after table was inited - we can do this, and only in that way it will work
478
- _checkOnClickPopups($table);
479
 
480
  if(addInstance) {
481
- vendor[appName].setTableInstance(tableInstance);
482
- }
483
- if(typeof finalCallback == "function") {
484
- return finalCallback(tableInstance);
485
- } else {
486
- return tableInstance;
487
  }
 
488
  });
489
 
490
  /** Callback for displaying table after initializing
@@ -492,12 +553,12 @@ if(typeof(SDT_DATA) == 'undefined') {
492
  * @param {object} json - JSON data retrieved from the server if the ajax option was set. Otherwise undefined.
493
  */
494
  vendor[appName].showTable = (function(settings, json) {
495
- var $table = this instanceof jQuery ? this : settings, // for compatibility with old pro versions
 
496
  $tableWrap = $table.closest('.supsystic-tables-wrap'),
497
  afterTableLoadedScriptString = $table.attr('data-after-table-loaded-script'),
498
- _ruleJS = vendor[appName].setRuleJSInstance($table),
499
  responsiveMode = $table.data('responsive-mode'),
500
- mergedCells = $table.data('merged'),
501
  fixedHeader = $table.data('fixed-head') == 'on',
502
  fixedFooter = $table.data('fixed-foot') == 'on',
503
  fixedColumns = $table.data('fixed-right') > 0 || $table.data('fixed-left') > 0,
@@ -505,11 +566,11 @@ if(typeof(SDT_DATA) == 'undefined') {
505
 
506
  // Apply custom CSS styles, which have been set through the table editor
507
  $table.find('th, td').each(function () {
508
- setStylesToCell(this);
509
  });
510
  $table.bind('column-visibility.dt draw.dt', function (e) {
511
  $(this).find('th, td').each(function () {
512
- setStylesToCell(this);
513
  });
514
  });
515
 
@@ -522,10 +583,10 @@ if(typeof(SDT_DATA) == 'undefined') {
522
  _ruleJS.init();
523
 
524
  // Set formats
525
- vendor[appName].formatDataAtTable($table);
526
 
527
  $(document).on('click', '.paginate_button', function () {
528
- vendor[appName].formatDataAtTable($table);
529
  });
530
 
531
  // Show comments on tap
@@ -556,7 +617,7 @@ if(typeof(SDT_DATA) == 'undefined') {
556
  }
557
 
558
  // Frontend fields
559
- if (typeof(vendor[appName].createEditableFields) == 'function') { // for compatibility with old pro versions
560
  var $editableFields = $tableWrap.find('.editable'),
561
  $selectableFields = $tableWrap.find('.selectable'),
562
  $tableId = $table.data('id'),
@@ -565,40 +626,48 @@ if(typeof(SDT_DATA) == 'undefined') {
565
  : false;
566
 
567
  if(useEditableFields) {
568
- if (typeof(vendor[appName].setFrontendFields) == 'function') {
569
- vendor[appName].setFrontendFields($table);
570
- } else if (typeof(vendor[appName].setAllFields) == 'function') {
571
- vendor[appName].setAllFields($table, $editableFields, $selectableFields);
572
  } else {
573
- vendor[appName].createEditableFields($table, $editableFields);
574
  }
575
  } else if(SDT_DATA.isAdmin && SDT_DATA.isPro) {
576
- if (typeof(vendor[appName].setFrontendFields) == 'function') {
577
- vendor[appName].setFrontendFields($table);
578
- } else if (typeof(vendor[appName].setAllFields) == 'function') {
579
- vendor[appName].createEditableFields($table, $editableFields);
580
- vendor[appName].createSelectableFields($table, $selectableFields);
581
  } else {
582
- vendor[appName].createEditableFields($table, $editableFields);
583
  }
584
  }
585
  $table.on('init.dt', function() {
586
  $table.on('responsive-resize.dt responsive-display.dt draw.dt', function() {
587
  $editableFields.off('click.sup'); // for compatibility with old pro versions
588
- vendor[appName].updateAfterRedraw($table);
589
  });
590
  });
591
  }
 
 
 
 
 
 
 
 
 
592
  $table.trigger('beforeShowTable', $table);
593
 
594
  // Show table
595
  $tableWrap.prev('.supsystic-table-loader').hide();
596
  $tableWrap.css('visibility', 'visible');
597
 
598
- vendor[appName].fixSortingForMultipleHeader($table);
599
 
600
  if(responsiveMode === 2 || fixedHeader || fixedFooter) {
601
-
602
  // Responsive Mode: Horizontal Scroll
603
  $(window).on('resize', $table, function(event) {
604
  var tBody = $tableWrap.find('.dataTables_scrollBody'),
@@ -712,7 +781,7 @@ if(typeof(SDT_DATA) == 'undefined') {
712
  var $table = (table instanceof $ ? table : $(table)),
713
  $tableWrap = $table.closest('.supsystic-tables-wrap');
714
 
715
- vendor[appName].getRuleJSInstance($table).init();
716
  $tableWrap.prev('.supsystic-table-loader').hide();
717
  $tableWrap.css('visibility', 'visible');
718
  });
@@ -755,25 +824,6 @@ if(typeof(SDT_DATA) == 'undefined') {
755
  }
756
  });
757
  }
758
- // Fix of displaying the footer if table has multiple header
759
- /*if(table.data('foot')) {
760
- var newFooter = [];
761
-
762
- $.each(table.find('tfoot tr th'), function (index, element) {
763
- var nthChild = index + 1;
764
-
765
- $(thead).each(function() {
766
- var item = $(this).find('th:nth-child(' + nthChild + ')');
767
-
768
- if(item.is(':visible')) {
769
- newFooter.push(item.clone());
770
- return false; // stop .each() function
771
- }
772
- });
773
-
774
- });
775
- table.find('tfoot').html(newFooter);
776
- }*/
777
  }
778
  });
779
 
@@ -905,8 +955,8 @@ if(typeof(SDT_DATA) == 'undefined') {
905
  format = numberFormat;
906
  delimiters = (format.match(/[^\d]/g) || [',', '.']).reverse();
907
  languageData.delimiters = {
908
- decimal: delimiters[0]
909
- , thousands: delimiters[1]
910
  };
911
 
912
  // We need to use dafault delimiters for format string
@@ -937,17 +987,40 @@ if(typeof(SDT_DATA) == 'undefined') {
937
  return false;
938
  });
939
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
940
  vendor[appName].Base64 = {
941
  _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
942
  encode : function (input) {
943
- var output = "";
944
- var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
945
- var i = 0;
 
946
 
947
- input = vendor[appName].Base64._utf8_encode(input);
948
 
949
  while (i < input.length) {
950
-
951
  chr1 = input.charCodeAt(i++);
952
  chr2 = input.charCodeAt(i++);
953
  chr3 = input.charCodeAt(i++);
@@ -962,11 +1035,9 @@ if(typeof(SDT_DATA) == 'undefined') {
962
  } else if (isNaN(chr3)) {
963
  enc4 = 64;
964
  }
965
-
966
  output = output +
967
- this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
968
- this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
969
-
970
  }
971
 
972
  return output;
@@ -998,100 +1069,107 @@ if(typeof(SDT_DATA) == 'undefined') {
998
  return utftext;
999
  }
1000
  };
1001
- }
1002
 
1003
- }(window.supsystic = window.supsystic || {}, window.jQuery, window));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1004
 
1005
- // Apply styles to cell from its classes
1006
- function classesRegexp() {
1007
- return {
1008
- color: /color\-([0-9a-f]{6})/,
1009
- background: /bg\-([0-9a-f]{6})/,
1010
- fontFamily: /ffamily\-([a-z_]+)/i,
1011
- fontSize: /fsize\-([0-9]+)/
1012
- }
1013
- }
1014
- function setStylesToCell(cell) {
1015
- var $cell = jQuery(cell),
1016
- viewId = $cell.parents('.supsystic-table:first').data('view-id'),
1017
- classes = classesRegexp(),
1018
- color = classes.color.exec(cell.className),
1019
- background = classes.background.exec(cell.className),
1020
- fontFamily = classes.fontFamily.exec(cell.className),
1021
- fontSize = classes.fontSize.exec(cell.className);
1022
-
1023
- if (null !== color) {
1024
- $cell.css({color: '#' + color[1]});
1025
- }
1026
- if (null !== background) {
1027
- $cell.css({backgroundColor: '#' + background[1]});
1028
- }
1029
- if (null !== fontFamily) {
1030
- var family = fontFamily[1].replace(/_/g, ' '),
1031
- familyName = fontFamily[1].replace(/_/g, '+'),
1032
- familyString = '@import url("//fonts.googleapis.com/css?family=' + familyName + '");',
1033
- style = getFrontendCellStylesElem(viewId);
1034
-
1035
- if(g_stbStandartFontsList
1036
- && toeInArray(family, g_stbStandartFontsList) == -1
1037
- && style.text().indexOf(familyString) == -1
1038
- ) {
1039
- style.text(familyString + '\n' + style.text());
1040
- }
1041
- $cell.css({fontFamily: family});
1042
- }
1043
- if (null !== fontSize) {
1044
- var lineHeight = +fontSize[1] + 6;
1045
- $cell.css({fontSize: fontSize[1] + 'px', lineHeight: lineHeight + 'px'});
1046
- }
1047
- }
1048
- // Get editor styles element
1049
- function getFrontendCellStylesElem(viewId) {
1050
- var $style = jQuery('#supsystic-table-' + viewId + '-css');
1051
 
1052
- if (!$style.length) {
1053
- $style = jQuery('<style/>', { id: 'supsystic-table-' + viewId + '-css' });
1054
- jQuery('head').append($style);
1055
- }
1056
- return $style;
1057
- }
1058
- function getAdminCellStylesElem() {
1059
- var $style = jQuery('#supsystic-tables-style');
 
 
 
1060
 
1061
- if (!$style.length) {
1062
- $style = jQuery('<style/>', { id: 'supsystic-tables-style' });
1063
- jQuery('head').append($style);
1064
- }
1065
- return $style;
1066
- }
1067
 
1068
- /**
1069
- * Integration with our PopUp plugin
1070
- */
1071
- function _checkOnClickPopups( $table ) {
1072
- if(typeof(_ppsBindOnElementClickPopups) !== 'undefined' && $table && $table.size()) {
1073
- var $bindedLinks = $table.find('[href*="#ppsShowPopUp_"].ppsClickBinded');
1074
- if($bindedLinks && $bindedLinks.size()) {
1075
- $bindedLinks.removeClass('ppsClickBinded').unbind('click');
1076
- }
1077
- _ppsBindOnElementClickPopups();
1078
- }
1079
- }
1080
 
1081
- /**
1082
- * List of common used functions
1083
- */
1084
- function getChunksArray(arr, len) {
1085
- var chunks = [],
1086
- i = 0,
1087
- n = arr.length;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1088
 
1089
- while (i < n) {
1090
- chunks.push(arr.slice(i, i += len));
 
 
 
 
 
 
 
 
 
1091
  }
1092
 
1093
- return chunks;
 
 
 
 
 
 
 
1094
  }
 
1095
  /**
1096
  * We will not use just jQUery.inArray because it is work incorrect for objects
1097
  * @return mixed - key that was found element or -1 if not
@@ -1109,14 +1187,12 @@ function toeInArray(needle, haystack) {
1109
  }
1110
 
1111
  (function($) {
1112
-
1113
  /**
1114
  * Detects whether element can be scrolled vertically.
1115
  * @this jQuery
1116
  * @return {boolean}
1117
  */
1118
  $.fn.isVerticallyScrollable = function() {
1119
-
1120
  if (this.scrollTop()) {
1121
  // Element is already scrolled, so it is scrollable
1122
  return true;
@@ -1130,7 +1206,6 @@ function toeInArray(needle, haystack) {
1130
  return true;
1131
  }
1132
  }
1133
-
1134
  return false;
1135
  };
1136
 
@@ -1140,7 +1215,6 @@ function toeInArray(needle, haystack) {
1140
  * @return {boolean}
1141
  */
1142
  $.fn.isHorizontallyScrollable = function() {
1143
-
1144
  if (this.scrollLeft()) {
1145
  // Element is already scrolled, so it is scrollable
1146
  return true;
@@ -1165,10 +1239,7 @@ function toeInArray(needle, haystack) {
1165
  return $(a).isHorizontallyScrollable();
1166
  }
1167
  });
1168
- })(jQuery);
1169
 
1170
- (function($)
1171
- {
1172
  $.fn.removeStyle = function(style)
1173
  {
1174
  var search = new RegExp(style + '[^;]+;?', 'g');
36
  return dataTableInstances;
37
  });
38
 
39
+ vendor[appName].removeAllTableInstances = (function() {
40
+ dataTableInstances = [];
41
+ });
42
+
43
  vendor[appName].setTableInstance = (function(instance) {
44
  dataTableInstances.push(instance);
45
  });
46
 
47
  vendor[appName].getTableInstanceById = (function(id) {
48
+ var allTables = this.getAllTableInstances();
49
 
50
  for(var i = 0; i < allTables.length; i++) {
51
  if(allTables[i].table_id == id) {
56
  });
57
 
58
  vendor[appName].getTableInstanceByViewId = (function(viewId) {
59
+ var allTables = this.getAllTableInstances();
60
 
61
  for(var i = 0; i < allTables.length; i++) {
62
  if(allTables[i].table_view_id == viewId) {
67
  });
68
 
69
  vendor[appName].removeTableInstanceByViewId = (function(viewId) {
70
+ var allTables = this.getAllTableInstances();
71
 
72
  for(var i = 0; i < allTables.length; i++) {
73
  if(allTables[i].table_view_id == viewId) {
91
  });
92
 
93
  vendor[appName].getRuleJSInstance = (function(table) {
94
+ var allRuleJS = this.getAllRuleJSInstances(),
95
  viewId = table.data('view-id');
96
 
97
  if(!allRuleJS[viewId]) {
98
+ this.setRuleJSInstance(table);
99
  }
100
  return allRuleJS[viewId];
101
  });
102
 
103
  vendor[appName].request = (function(route, data) {
104
+ if (!$.isPlainObject(route) || !('module' in route) || !('action' in route)) {
105
+ throw new Error('Request route is not specified.');
106
+ }
 
107
  if (!$.isPlainObject(data)) {
108
  data = {};
109
  }
 
110
  if ('action' in data) {
111
  throw new Error('Reserved field "action" used.');
112
  }
 
113
  data.action = 'supsystic-tables';
114
 
115
+ var url = window.ajaxurl ? window.ajaxurl : ajax_obj.ajaxurl,
116
+ deferred = $.Deferred();
 
117
 
118
+ $.post(url, $.extend({}, { route: route }, data))
119
+ .done(function (response, textStatus, jqXHR) {
120
+ if (response.success) {
121
+ deferred.resolve(response, textStatus, jqXHR);
122
+ } else {
123
+ if(data._maxIter) {
124
+ retryAjax(deferred, url, route, data, 1, data._maxIter);
125
+ } else {
126
+ var message = typeof response.message !== 'undefined' ? response.message : 'There are errors during the request.';
127
 
128
+ deferred.reject(message, textStatus, jqXHR);
129
+ }
130
+ }
131
+ }).fail(function (jqXHR, textStatus, errorThrown) {
132
+ if(data._maxIter) {
133
+ retryAjax(deferred, url, route, data, 1, data._maxIter);
134
+ } else {
135
+ deferred.reject(errorThrown, textStatus, jqXHR);
136
+ }
137
+ });
138
 
139
+ function retryAjax(def, url, route, data, curIter, maxIter) {
140
+ $.post(url, $.extend({}, { route: route }, data))
141
+ .done(function (response, textStatus, jqXHR) {
142
+ if (response.success) {
143
+ def.resolve(response, textStatus, jqXHR);
144
+ } else {
145
+ var message = typeof response.message !== 'undefined' ? response.message : 'There are errors during the request.';
146
+
147
+ retryErrorHandler(def, url, route, data, curIter, maxIter, message, textStatus, jqXHR);
148
+ }
149
+ }).fail(function (jqXHR, textStatus, errorThrown) {
150
+ retryErrorHandler(def, url, route, data, curIter, maxIter, errorThrown, textStatus, jqXHR);
151
+ });
152
+ }
153
+
154
+ function retryErrorHandler(def, url, route, data, curIter, maxIter, errorThrown, textStatus, jqXHR) {
155
+ curIter++;
156
+ if(curIter < maxIter) {
157
+ retryAjax(def, url, route, data, curIter, maxIter);
158
+ } else {
159
+ def.reject(errorThrown, textStatus, jqXHR);
160
+ }
161
+ }
162
 
163
  return deferred.promise();
164
  });
191
  reinit = typeof reinit != 'undefined' ? reinit : {};
192
  addInstance = typeof addInstance != 'undefined' ? addInstance : true;
193
 
194
+ var self = this,
195
+ $table = (table instanceof $ ? table : $(table)),
196
  features = $table.data('features'),
197
  config = {},
198
  responsiveMode = $table.data('responsive-mode'),
210
  initComplete: callback,
211
  headerCallback: function( thead, data, start, end, display ) {
212
  $(thead).closest('thead').find('th').each(function() {
213
+ self.setStylesToCell(this);
214
  });
215
  },
216
  footerCallback: function( tfoot, data, start, end, display ) {
217
  $(tfoot).closest('tfoot').find('th').each(function() {
218
+ self.setStylesToCell(this);
219
  });
220
  }
221
  };
239
  });
240
  }
241
 
242
+ // Fix for searching by merged cells
243
+ $table.find('tbody td[data-colspan], tbody td[data-rowspan]').each(function(index, item) {
244
+ var cell = $(item),
245
+ cellData = cell.html();
246
+
247
+ // prevent of copy cell data if it contains tags with id attribute - it must be unique on page
248
+ if(!cellData.toString().match(/<.*?id=['|"].*?['|"].*?>/g)) {
249
+ var cellOrValue = cell.data('original-value'),
250
+ cellFormula = cell.data('formula'),
251
+ cellOrder = cell.data('order'),
252
+ table = cell.parents('table:first'),
253
+ colIndex = cell.index(),
254
+ rowIndex = cell.parents('tr:first').index(),
255
+ colspan = cell.data('colspan'),
256
+ rowspan = cell.data('rowspan');
257
+
258
+ for(var i = rowIndex + 1; i <= rowIndex + rowspan; i++) {
259
+ for(var j = colIndex + 1; j <= colIndex + colspan; j++) {
260
+ var hiddenCell = table.find('tbody tr:nth-child(' + i + ') td:nth-child(' + j + ')');
261
+
262
+ if(hiddenCell.data('hide')) {
263
+ hiddenCell.html(cellData);
264
+ hiddenCell.data('original-value', cellOrValue);
265
+ hiddenCell.attr('data-original-value', cellOrValue);
266
+ hiddenCell.data('order', cellOrder);
267
+ hiddenCell.attr('data-order', cellOrder);
268
+ if(cellFormula) {
269
+ hiddenCell.data('formula', cellFormula);
270
+ hiddenCell.attr('data-formula', cellFormula);
271
+ }
272
+ }
273
+ }
274
+ }
275
+ }
276
+ });
277
+
278
  // Set features
279
  $.each(features, function () {
280
  var featureName = this.replace(/[-_]([a-z])/g, function (g) { return g[1].toUpperCase(); });
539
  tableInstance = $table.dataTable($.extend({}, defaultFeatures, config, reinit));
540
  tableInstance.table_id = $table.data('id');
541
  tableInstance.table_view_id = $table.data('view-id');
542
+ tableInstance.fnFakeRowspan();
543
+ self._checkOnClickPopups($table);
 
544
 
545
  if(addInstance) {
546
+ this.setTableInstance(tableInstance);
 
 
 
 
 
547
  }
548
+ return typeof finalCallback == "function" ? finalCallback(tableInstance) : tableInstance;
549
  });
550
 
551
  /** Callback for displaying table after initializing
553
  * @param {object} json - JSON data retrieved from the server if the ajax option was set. Otherwise undefined.
554
  */
555
  vendor[appName].showTable = (function(settings, json) {
556
+ var self = vendor[appName], // it is callback so "this" does not equal vendor[appName] object
557
+ $table = this instanceof jQuery ? this : settings, // for compatibility with old pro versions
558
  $tableWrap = $table.closest('.supsystic-tables-wrap'),
559
  afterTableLoadedScriptString = $table.attr('data-after-table-loaded-script'),
560
+ _ruleJS = self.setRuleJSInstance($table),
561
  responsiveMode = $table.data('responsive-mode'),
 
562
  fixedHeader = $table.data('fixed-head') == 'on',
563
  fixedFooter = $table.data('fixed-foot') == 'on',
564
  fixedColumns = $table.data('fixed-right') > 0 || $table.data('fixed-left') > 0,
566
 
567
  // Apply custom CSS styles, which have been set through the table editor
568
  $table.find('th, td').each(function () {
569
+ self.setStylesToCell(this);
570
  });
571
  $table.bind('column-visibility.dt draw.dt', function (e) {
572
  $(this).find('th, td').each(function () {
573
+ self.setStylesToCell(this);
574
  });
575
  });
576
 
583
  _ruleJS.init();
584
 
585
  // Set formats
586
+ self.formatDataAtTable($table);
587
 
588
  $(document).on('click', '.paginate_button', function () {
589
+ self.formatDataAtTable($table);
590
  });
591
 
592
  // Show comments on tap
617
  }
618
 
619
  // Frontend fields
620
+ if (typeof(self.createEditableFields) == 'function') { // for compatibility with old pro versions
621
  var $editableFields = $tableWrap.find('.editable'),
622
  $selectableFields = $tableWrap.find('.selectable'),
623
  $tableId = $table.data('id'),
626
  : false;
627
 
628
  if(useEditableFields) {
629
+ if (typeof(self.setFrontendFields) == 'function') {
630
+ self.setFrontendFields($table);
631
+ } else if (typeof(self.setAllFields) == 'function') {
632
+ self.setAllFields($table, $editableFields, $selectableFields);
633
  } else {
634
+ self.createEditableFields($table, $editableFields);
635
  }
636
  } else if(SDT_DATA.isAdmin && SDT_DATA.isPro) {
637
+ if (typeof(self.setFrontendFields) == 'function') {
638
+ self.setFrontendFields($table);
639
+ } else if (typeof(self.setAllFields) == 'function') {
640
+ self.createEditableFields($table, $editableFields);
641
+ self.createSelectableFields($table, $selectableFields);
642
  } else {
643
+ self.createEditableFields($table, $editableFields);
644
  }
645
  }
646
  $table.on('init.dt', function() {
647
  $table.on('responsive-resize.dt responsive-display.dt draw.dt', function() {
648
  $editableFields.off('click.sup'); // for compatibility with old pro versions
649
+ self.updateAfterRedraw($table);
650
  });
651
  });
652
  }
653
+
654
+ // apply page.dt event by change table pagination via select
655
+ var paginationSelect = $tableWrap.find('.dataTables_length select');
656
+ if(paginationSelect.length) {
657
+ paginationSelect.on('change', function() {
658
+ $table.trigger('page.dt');
659
+ });
660
+ }
661
+
662
  $table.trigger('beforeShowTable', $table);
663
 
664
  // Show table
665
  $tableWrap.prev('.supsystic-table-loader').hide();
666
  $tableWrap.css('visibility', 'visible');
667
 
668
+ self.fixSortingForMultipleHeader($table);
669
 
670
  if(responsiveMode === 2 || fixedHeader || fixedFooter) {
 
671
  // Responsive Mode: Horizontal Scroll
672
  $(window).on('resize', $table, function(event) {
673
  var tBody = $tableWrap.find('.dataTables_scrollBody'),
781
  var $table = (table instanceof $ ? table : $(table)),
782
  $tableWrap = $table.closest('.supsystic-tables-wrap');
783
 
784
+ this.getRuleJSInstance($table).init();
785
  $tableWrap.prev('.supsystic-table-loader').hide();
786
  $tableWrap.css('visibility', 'visible');
787
  });
824
  }
825
  });
826
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
827
  }
828
  });
829
 
955
  format = numberFormat;
956
  delimiters = (format.match(/[^\d]/g) || [',', '.']).reverse();
957
  languageData.delimiters = {
958
+ decimal: delimiters[0],
959
+ thousands: delimiters[1]
960
  };
961
 
962
  // We need to use dafault delimiters for format string
987
  return false;
988
  });
989
 
990
+ vendor[appName].prepareFormulaToParse = (function (value) {
991
+ var stringsInFormula = value.match(/".+?"|'.+?'/g);
992
+
993
+ if(stringsInFormula && stringsInFormula.length) {
994
+ var clearValue = value.replace(/".+?"|'.+?'/g, '%STR%'),
995
+ index = 0;
996
+
997
+ clearValue = clearValue.toUpperCase();
998
+ value = clearValue.replace(/%STR%/g, function(match) {
999
+ var val = match;
1000
+
1001
+ if(index < stringsInFormula.length) {
1002
+ val = stringsInFormula[index];
1003
+ index++;
1004
+ }
1005
+ return val;
1006
+ });
1007
+ } else {
1008
+ value = value.toUpperCase();
1009
+ }
1010
+ return value;
1011
+ });
1012
+
1013
  vendor[appName].Base64 = {
1014
  _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
1015
  encode : function (input) {
1016
+ var self = vendor[appName].Base64,
1017
+ output = "",
1018
+ i = 0,
1019
+ chr1, chr2, chr3, enc1, enc2, enc3, enc4;
1020
 
1021
+ input = self._utf8_encode(input);
1022
 
1023
  while (i < input.length) {
 
1024
  chr1 = input.charCodeAt(i++);
1025
  chr2 = input.charCodeAt(i++);
1026
  chr3 = input.charCodeAt(i++);
1035
  } else if (isNaN(chr3)) {
1036
  enc4 = 64;
1037
  }
 
1038
  output = output +
1039
+ self._keyStr.charAt(enc1) + self._keyStr.charAt(enc2) +
1040
+ self._keyStr.charAt(enc3) + self._keyStr.charAt(enc4);
 
1041
  }
1042
 
1043
  return output;
1069
  return utftext;
1070
  }
1071
  };
 
1072
 
1073
+ vendor[appName].getClassesRegexp = (function() {
1074
+ return {
1075
+ color: /color\-([0-9a-f]{6})/,
1076
+ background: /bg\-([0-9a-f]{6})/,
1077
+ fontFamily: /ffamily\-([a-z_]+)/i,
1078
+ fontSize: /fsize\-([0-9]+)/
1079
+ }
1080
+ });
1081
+
1082
+ vendor[appName].setStylesToCell = (function(cell) {
1083
+ var $cell = cell instanceof jQuery ? cell : $(cell),
1084
+ viewId = $cell.parents('.supsystic-table:first').data('view-id'),
1085
+ classes = this.getClassesRegexp(),
1086
+ cellClassNames = $cell.get(0).className,
1087
+ color = classes.color.exec(cellClassNames),
1088
+ background = classes.background.exec(cellClassNames),
1089
+ fontFamily = classes.fontFamily.exec(cellClassNames),
1090
+ fontSize = classes.fontSize.exec(cellClassNames);
1091
+
1092
+ if (null !== color) {
1093
+ $cell.css({color: '#' + color[1]});
1094
+ }
1095
+ if (null !== background) {
1096
+ $cell.css({backgroundColor: '#' + background[1]});
1097
+ }
1098
+ if (null !== fontFamily) {
1099
+ var family = fontFamily[1].replace(/_/g, ' '),
1100
+ familyName = fontFamily[1].replace(/_/g, '+'),
1101
+ familyString = '@import url("//fonts.googleapis.com/css?family=' + familyName + '");';
1102
 
1103
+ if(g_stbStandartFontsList && toeInArray(family, g_stbStandartFontsList) == -1) {
1104
+ var style = this.getFrontendCellStylesElem(viewId);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1105
 
1106
+ if(style.text().indexOf(familyString) == -1) {
1107
+ style.text(familyString + '\n' + style.text());
1108
+ }
1109
+ }
1110
+ $cell.css({fontFamily: family});
1111
+ }
1112
+ if (null !== fontSize) {
1113
+ var lineHeight = +fontSize[1] + 6;
1114
+ $cell.css({fontSize: fontSize[1] + 'px', lineHeight: lineHeight + 'px'});
1115
+ }
1116
+ });
1117
 
1118
+ vendor[appName].getAdminCellStylesElem = (function() {
1119
+ var $style = $('#supsystic-tables-style');
 
 
 
 
1120
 
1121
+ if (!$style.length) {
1122
+ $style = $('<style/>', { id: 'supsystic-tables-style' });
1123
+ $('head').append($style);
1124
+ }
1125
+ return $style;
1126
+ });
 
 
 
 
 
 
1127
 
1128
+ vendor[appName].getFrontendCellStylesElem = (function(viewId) {
1129
+ var $style = $('#supsystic-table-' + viewId + '-css');
1130
+
1131
+ if (!$style.length) {
1132
+ $style = $('<style/>', { id: 'supsystic-table-' + viewId + '-css' });
1133
+ $('head').append($style);
1134
+ }
1135
+ return $style;
1136
+ });
1137
+
1138
+ vendor[appName]._getChunksArray = (function(arr, len) {
1139
+ var chunks = [],
1140
+ i = 0,
1141
+ n = arr.length;
1142
+
1143
+ while (i < n) {
1144
+ chunks.push(arr.slice(i, i += len));
1145
+ }
1146
+
1147
+ return chunks;
1148
+ });
1149
 
1150
+ vendor[appName]._checkOnClickPopups = (function( $table ) {
1151
+ // Integration with our PopUp plugin
1152
+ // Only after table was inited - we can do this, and only in that way it will work
1153
+ if(typeof(_ppsBindOnElementClickPopups) !== 'undefined' && $table && $table.size()) {
1154
+ var $bindedLinks = $table.find('[href*="#ppsShowPopUp_"].ppsClickBinded');
1155
+ if($bindedLinks && $bindedLinks.size()) {
1156
+ $bindedLinks.removeClass('ppsClickBinded').unbind('click');
1157
+ }
1158
+ _ppsBindOnElementClickPopups();
1159
+ }
1160
+ });
1161
  }
1162
 
1163
+ }(window.supsystic = window.supsystic || {}, window.jQuery, window));
1164
+
1165
+ // For compatibility to old PRO versions
1166
+ function classesRegexp() {
1167
+ return window.supsystic.Tables.getClassesRegexp();
1168
+ }
1169
+ function getAdminCellStylesElem() {
1170
+ return window.supsystic.Tables.getAdminCellStylesElem();
1171
  }
1172
+
1173
  /**
1174
  * We will not use just jQUery.inArray because it is work incorrect for objects
1175
  * @return mixed - key that was found element or -1 if not
1187
  }
1188
 
1189
  (function($) {
 
1190
  /**
1191
  * Detects whether element can be scrolled vertically.
1192
  * @this jQuery
1193
  * @return {boolean}
1194
  */
1195
  $.fn.isVerticallyScrollable = function() {
 
1196
  if (this.scrollTop()) {
1197
  // Element is already scrolled, so it is scrollable
1198
  return true;
1206
  return true;
1207
  }
1208
  }
 
1209
  return false;
1210
  };
1211
 
1215
  * @return {boolean}
1216
  */
1217
  $.fn.isHorizontallyScrollable = function() {
 
1218
  if (this.scrollLeft()) {
1219
  // Element is already scrolled, so it is scrollable
1220
  return true;
1239
  return $(a).isHorizontallyScrollable();
1240
  }
1241
  });
 
1242
 
 
 
1243
  $.fn.removeStyle = function(style)
1244
  {
1245
  var search = new RegExp(style + '[^;]+;?', 'g');
src/SupsysticTables/Core/assets/js/lib/dataTables.customExtensions.js CHANGED
@@ -1,26 +1,28 @@
1
  (function ($, app) {
2
  $.fn.dataTableExt.oApi.fnFakeRowspan = function (oSettings) {
3
- var cells;
4
- $.each(oSettings.aoData, function(index, rowData) {
5
- setCellAttributes(rowData.anCells);
6
- });
7
- if (oSettings.aoHeader.length) {
8
- cells = [];
9
- $.each(oSettings.aoHeader, function(index, rowData) {
10
- $.each(rowData, function(index, cellData) {
11
- cells.push(cellData.cell);
12
- });
13
  });
14
- setCellAttributes(cells);
15
- }
16
- if (oSettings.aoFooter.length) {
17
- cells = [];
18
- $.each(oSettings.aoFooter, function(index, rowData) {
19
- $.each(rowData, function(index, cellData) {
20
- cells.push(cellData.cell);
21
  });
22
- });
23
- setCellAttributes(cells);
 
 
 
 
 
 
 
 
 
24
  }
25
  return this;
26
  };
@@ -64,19 +66,20 @@
64
  }
65
  } );
66
 
67
- function setCellAttributes(cellArray) {
68
- for (var i = 0; i < cellArray.length; i++) {
69
- if (cellArray[i].getAttribute('data-hide')) {
70
- cellArray[i].style.display = 'none';
 
71
  }
72
- if (colspan = cellArray[i].getAttribute('data-colspan')) {
73
  if (colspan > 1) {
74
- cellArray[i].setAttribute('colspan', colspan);
75
  }
76
  }
77
- if (rowspan = cellArray[i].getAttribute('data-rowspan')) {
78
  if (rowspan > 1) {
79
- cellArray[i].setAttribute('rowspan', rowspan);
80
  }
81
  }
82
  }
1
  (function ($, app) {
2
  $.fn.dataTableExt.oApi.fnFakeRowspan = function (oSettings) {
3
+ if(oSettings) {
4
+ var cells;
5
+ $.each(oSettings.aoData, function(index, rowData) {
6
+ setCellAttributes(rowData.anCells);
 
 
 
 
 
 
7
  });
8
+ if (oSettings.aoHeader.length) {
9
+ cells = [];
10
+ $.each(oSettings.aoHeader, function(index, rowData) {
11
+ $.each(rowData, function(index, cellData) {
12
+ cells.push(cellData.cell);
13
+ });
 
14
  });
15
+ setCellAttributes(cells);
16
+ }
17
+ if (oSettings.aoFooter.length) {
18
+ cells = [];
19
+ $.each(oSettings.aoFooter, function(index, rowData) {
20
+ $.each(rowData, function(index, cellData) {
21
+ cells.push(cellData.cell);
22
+ });
23
+ });
24
+ setCellAttributes(cells);
25
+ }
26
  }
27
  return this;
28
  };
66
  }
67
  } );
68
 
69
+ function setCellAttributes(cells) {
70
+ var colspan, rowspan;
71
+ for (var i = 0; i < cells.length; i++) {
72
+ if (cells[i].getAttribute('data-hide')) {
73
+ cells[i].style.display = 'none';
74
  }
75
+ if (colspan = cells[i].getAttribute('data-colspan')) {
76
  if (colspan > 1) {
77
+ cells[i].setAttribute('colspan', colspan);
78
  }
79
  }
80
+ if (rowspan = cells[i].getAttribute('data-rowspan')) {
81
  if (rowspan > 1) {
82
+ cells[i].setAttribute('rowspan', rowspan);
83
  }
84
  }
85
  }
src/SupsysticTables/Core/assets/js/lib/jquery.dataTables.min.js CHANGED
@@ -2,7 +2,7 @@
2
  DataTables 1.10.12
3
  ©2008-2015 SpryMedia Ltd - datatables.net/license
4
  */
5
- (function(h){"function"===typeof define&&define.amd?define(["jquery"],function(D){return h(D,window,document)}):"object"===typeof exports?module.exports=function(D,I){D||(D=window);I||(I="undefined"!==typeof window?require("jquery"):require("jquery")(D));return h(I,D,D.document)}:h(jQuery,window,document)})(function(h,D,I,k){function X(a){var b,c,d={};h.each(a,function(e){if((b=e.match(/^([^A-Z]+?)([A-Z])/))&&-1!=="a aa ai ao as b fn i m o s ".indexOf(b[1]+" "))c=e.replace(b[0],b[2].toLowerCase()),
6
  d[c]=e,"o"===b[1]&&X(a[e])});a._hungarianMap=d}function K(a,b,c){a._hungarianMap||X(a);var d;h.each(b,function(e){d=a._hungarianMap[e];if(d!==k&&(c||b[d]===k))"o"===d.charAt(0)?(b[d]||(b[d]={}),h.extend(!0,b[d],b[e]),K(a[d],b[d],c)):b[d]=b[e]})}function Da(a){var b=m.defaults.oLanguage,c=a.sZeroRecords;!a.sEmptyTable&&(c&&"No data available in table"===b.sEmptyTable)&&E(a,a,"sZeroRecords","sEmptyTable");!a.sLoadingRecords&&(c&&"Loading..."===b.sLoadingRecords)&&E(a,a,"sZeroRecords","sLoadingRecords");
7
  a.sInfoThousands&&(a.sThousands=a.sInfoThousands);(a=a.sDecimal)&&db(a)}function eb(a){A(a,"ordering","bSort");A(a,"orderMulti","bSortMulti");A(a,"orderClasses","bSortClasses");A(a,"orderCellsTop","bSortCellsTop");A(a,"order","aaSorting");A(a,"orderFixed","aaSortingFixed");A(a,"paging","bPaginate");A(a,"pagingType","sPaginationType");A(a,"pageLength","iDisplayLength");A(a,"searching","bFilter");"boolean"===typeof a.sScrollX&&(a.sScrollX=a.sScrollX?"100%":"");"boolean"===typeof a.scrollX&&(a.scrollX=
8
  a.scrollX?"100%":"");if(a=a.aoSearchCols)for(var b=0,c=a.length;b<c;b++)a[b]&&K(m.models.oSearch,a[b])}function fb(a){A(a,"orderable","bSortable");A(a,"orderData","aDataSort");A(a,"orderSequence","asSorting");A(a,"orderDataType","sortDataType");var b=a.aDataSort;b&&!h.isArray(b)&&(a.aDataSort=[b])}function gb(a){if(!m.__browser){var b={};m.__browser=b;var c=h("<div/>").css({position:"fixed",top:0,left:0,height:1,width:1,overflow:"hidden"}).append(h("<div/>").css({position:"absolute",top:1,left:1,
2
  DataTables 1.10.12
3
  ©2008-2015 SpryMedia Ltd - datatables.net/license
4
  */
5
+ (function(h){/*"function"===typeof define&&define.amd?define(["jquery"],function(D){return h(D,window,document)}):"object"===typeof exports?module.exports=function(D,I){D||(D=window);I||(I="undefined"!==typeof window?require("jquery"):require("jquery")(D));return h(I,D,D.document)}:*/h(jQuery,window,document)})(function(h,D,I,k){function X(a){var b,c,d={};h.each(a,function(e){if((b=e.match(/^([^A-Z]+?)([A-Z])/))&&-1!=="a aa ai ao as b fn i m o s ".indexOf(b[1]+" "))c=e.replace(b[0],b[2].toLowerCase()),
6
  d[c]=e,"o"===b[1]&&X(a[e])});a._hungarianMap=d}function K(a,b,c){a._hungarianMap||X(a);var d;h.each(b,function(e){d=a._hungarianMap[e];if(d!==k&&(c||b[d]===k))"o"===d.charAt(0)?(b[d]||(b[d]={}),h.extend(!0,b[d],b[e]),K(a[d],b[d],c)):b[d]=b[e]})}function Da(a){var b=m.defaults.oLanguage,c=a.sZeroRecords;!a.sEmptyTable&&(c&&"No data available in table"===b.sEmptyTable)&&E(a,a,"sZeroRecords","sEmptyTable");!a.sLoadingRecords&&(c&&"Loading..."===b.sLoadingRecords)&&E(a,a,"sZeroRecords","sLoadingRecords");
7
  a.sInfoThousands&&(a.sThousands=a.sInfoThousands);(a=a.sDecimal)&&db(a)}function eb(a){A(a,"ordering","bSort");A(a,"orderMulti","bSortMulti");A(a,"orderClasses","bSortClasses");A(a,"orderCellsTop","bSortCellsTop");A(a,"order","aaSorting");A(a,"orderFixed","aaSortingFixed");A(a,"paging","bPaginate");A(a,"pagingType","sPaginationType");A(a,"pageLength","iDisplayLength");A(a,"searching","bFilter");"boolean"===typeof a.sScrollX&&(a.sScrollX=a.sScrollX?"100%":"");"boolean"===typeof a.scrollX&&(a.scrollX=
8
  a.scrollX?"100%":"");if(a=a.aoSearchCols)for(var b=0,c=a.length;b<c;b++)a[b]&&K(m.models.oSearch,a[b])}function fb(a){A(a,"orderable","bSortable");A(a,"orderData","aDataSort");A(a,"orderSequence","asSorting");A(a,"orderDataType","sortDataType");var b=a.aDataSort;b&&!h.isArray(b)&&(a.aDataSort=[b])}function gb(a){if(!m.__browser){var b={};m.__browser=b;var c=h("<div/>").css({position:"fixed",top:0,left:0,height:1,width:1,overflow:"hidden"}).append(h("<div/>").css({position:"absolute",top:1,left:1,
src/SupsysticTables/Settings/views/index.twig CHANGED
@@ -18,7 +18,6 @@
18
  <div class="settings-list">
19
  {% block beforeSettings %}{% endblock %}
20
  <div class="setting">
21
-
22
  <div class="table-search-option table-option">
23
  <div class="setting-description">
24
  <label>{{ environment.translate('Include to Global Search') }}</label>
@@ -28,6 +27,15 @@
28
  <input type="checkbox" name="settings[table_search]" {% if settings.table_search == 'on' %} checked {% endif %}>
29
  </div>
30
  </div>
 
 
 
 
 
 
 
 
 
31
  <div class="table-step-option table-option">
32
  <div class="setting-description">
33
  <label>{{ environment.translate('Rows Count per Request') }}</label>
18
  <div class="settings-list">
19
  {% block beforeSettings %}{% endblock %}
20
  <div class="setting">
 
21
  <div class="table-search-option table-option">
22
  <div class="setting-description">
23
  <label>{{ environment.translate('Include to Global Search') }}</label>
27
  <input type="checkbox" name="settings[table_search]" {% if settings.table_search == 'on' %} checked {% endif %}>
28
  </div>
29
  </div>
30
+ <div class="table-disable-wp-footer-fix-option table-option">
31
+ <div class="setting-description">
32
+ <label>{{ environment.translate('Disable WP Footer Fix') }}</label>
33
+ {{ tooltip.icon(environment.translate('Standard WP theme must call the wp_footer() function in site footer (see <a href="%s" target="_blank">Theme Development</a>). But sometimes it is not happen in custom themes. In this case our plugin will call its function forced, because it needs it for correct work as the many other plugins. But if you have the problems in your site because of this feature - just enable this option to disable force call of wp_footer() function by our plugin.') | format('//codex.wordpress.org/Theme_Development'), 'top', true) }} </label>
34
+ </div>
35
+ <div class="setting-control">
36
+ <input type="checkbox" name="settings[disable_wp_footer_fix]" {% if settings.disable_wp_footer_fix == 'on' %} checked {% endif %}>
37
+ </div>
38
+ </div>
39
  <div class="table-step-option table-option">
40
  <div class="setting-description">
41
  <label>{{ environment.translate('Rows Count per Request') }}</label>
src/SupsysticTables/Tables/Controller.php CHANGED
@@ -11,12 +11,10 @@ class SupsysticTables_Tables_Controller extends SupsysticTables_Core_BaseControl
11
  {
12
  try {
13
  $this->getEnvironment()->getModule('tables')->setIniLimits();
14
- $tables = $this->getModel('tables')->getAll(
15
- array(
16
- 'order' => 'DESC',
17
- 'order_by' => 'id'
18
- )
19
- );
20
  return $this->response('@tables/index.twig', array('tables' => $tables));
21
  } catch (Exception $e) {
22
  return $this->response('error.twig', array('exception' => $e));
@@ -36,11 +34,7 @@ class SupsysticTables_Tables_Controller extends SupsysticTables_Core_BaseControl
36
 
37
  try {
38
  if (!$this->isValidTitle($title)) {
39
- return $this->ajaxError(
40
- $this->translate(
41
- 'Title can\'t be empty or more than 255 characters'
42
- )
43
- );
44
  }
45
  $this->getEnvironment()->getModule('tables')->setIniLimits();
46
  // Add base settings
@@ -69,15 +63,7 @@ class SupsysticTables_Tables_Controller extends SupsysticTables_Core_BaseControl
69
  return $this->ajaxError($e->getMessage());
70
  }
71
 
72
- return $this->ajaxSuccess(
73
- array(
74
- 'url' => $this->generateUrl(
75
- 'tables',
76
- 'view',
77
- array('id' => $tableId)
78
- )
79
- )
80
- );
81
  }
82
 
83
  /**
@@ -240,11 +226,11 @@ class SupsysticTables_Tables_Controller extends SupsysticTables_Core_BaseControl
240
  */
241
  public function updateRowsAction(Rsc_Http_Request $request)
242
  {
243
- /** @var SupsysticTables_Tables_Model_Tables $tables */
244
  $tables = $this->getModel('tables');
245
  $id = $request->post->get('id');
246
  $step = $request->post->get('step');
247
- $last = $request->post->get('last');
248
  $rowsData = $request->post->get('rows');
249
  $rows = $this->prepareData($rowsData);
250
 
@@ -478,22 +464,20 @@ class SupsysticTables_Tables_Controller extends SupsysticTables_Core_BaseControl
478
 
479
  return $this->ajaxSuccess();
480
  }
 
481
  /**
482
  * Returns full list of the tables.
483
- * Uses for shortcode button.
484
  *
485
  * @return Rsc_Http_Response
486
  */
487
  public function listAction() {
488
  try{
489
- $tables = $this->getModel('tables')->getAll(
490
- array(
491
- 'order' => 'ASC',
492
- 'order_by' => 'title'
493
- )
494
- );
495
  return $this->ajaxSuccess(array('tables' => $tables));
496
-
497
  } catch (Exception $e) {
498
  return $this->ajaxError($e->getMessage());
499
  }
11
  {
12
  try {
13
  $this->getEnvironment()->getModule('tables')->setIniLimits();
14
+ $tables = $this->getModel('tables')->getAll(array(
15
+ 'order' => 'DESC',
16
+ 'order_by' => 'id'
17
+ ));
 
 
18
  return $this->response('@tables/index.twig', array('tables' => $tables));
19
  } catch (Exception $e) {
20
  return $this->response('error.twig', array('exception' => $e));
34
 
35
  try {
36
  if (!$this->isValidTitle($title)) {
37
+ return $this->ajaxError($this->translate('Title can\'t be empty or more than 255 characters'));
 
 
 
 
38
  }
39
  $this->getEnvironment()->getModule('tables')->setIniLimits();
40
  // Add base settings
63
  return $this->ajaxError($e->getMessage());
64
  }
65
 
66
+ return $this->ajaxSuccess(array('url' => $this->generateUrl('tables', 'view', array('id' => $tableId))));
 
 
 
 
 
 
 
 
67
  }
68
 
69
  /**
226
  */
227
  public function updateRowsAction(Rsc_Http_Request $request)
228
  {
229
+ /** @var SupsysticTables_Tables_Model_Tables $tables */
230
  $tables = $this->getModel('tables');
231
  $id = $request->post->get('id');
232
  $step = $request->post->get('step');
233
+ $last = (bool) $request->post->get('last');
234
  $rowsData = $request->post->get('rows');
235
  $rows = $this->prepareData($rowsData);
236
 
464
 
465
  return $this->ajaxSuccess();
466
  }
467
+
468
  /**
469
  * Returns full list of the tables.
470
+ * Uses for adding of shortcode button to TinyMCE Editor.
471
  *
472
  * @return Rsc_Http_Response
473
  */
474
  public function listAction() {
475
  try{
476
+ $tables = $this->getModel('tables')->getAll(array(
477
+ 'order' => 'ASC',
478
+ 'order_by' => 'title'
479
+ ));
 
 
480
  return $this->ajaxSuccess(array('tables' => $tables));
 
481
  } catch (Exception $e) {
482
  return $this->ajaxError($e->getMessage());
483
  }
src/SupsysticTables/Tables/Model/History.php CHANGED
@@ -49,7 +49,6 @@ class SupsysticTables_Tables_Model_History extends SupsysticTables_Core_BaseMode
49
 
50
  public function _checkUserTableHistoryByPeriod($tableId, $history, $period = null)
51
  {
52
- $history = array_reverse($history);
53
  $settings = $this->getHistorySettings($tableId);
54
  $historyTable = array();
55
 
@@ -57,6 +56,7 @@ class SupsysticTables_Tables_Model_History extends SupsysticTables_Core_BaseMode
57
  if(!function_exists('date_create')) {
58
  throw new RuntimeException($this->environment->translate('You should to use PHP v.5.2.0 or greater to use the period feature for history table.'));
59
  }
 
60
  $today = date_create();
61
  $needCreate = empty($period);
62
  $period = !empty($period) ? $period : $today;
@@ -107,13 +107,16 @@ class SupsysticTables_Tables_Model_History extends SupsysticTables_Core_BaseMode
107
 
108
  public function updateUserTableHistory($userId, $tableId, $data, $period = null)
109
  {
 
 
 
 
 
110
  for($i = 0; $i < count($data); $i++) {
111
  $data[$i] = $this->prepareRowsData($data[$i], true);
112
  }
113
- $history = array(
114
- 'data' => serialize($data),
115
- //'updated' => date('Y-m-d H:i:s'),
116
- );
117
  $historyTable = $this->getUserTableHistory($userId, $tableId, $period);
118
 
119
  if($historyTable) {
49
 
50
  public function _checkUserTableHistoryByPeriod($tableId, $history, $period = null)
51
  {
 
52
  $settings = $this->getHistorySettings($tableId);
53
  $historyTable = array();
54
 
56
  if(!function_exists('date_create')) {
57
  throw new RuntimeException($this->environment->translate('You should to use PHP v.5.2.0 or greater to use the period feature for history table.'));
58
  }
59
+ $history = array_reverse($history);
60
  $today = date_create();
61
  $needCreate = empty($period);
62
  $period = !empty($period) ? $period : $today;
107
 
108
  public function updateUserTableHistory($userId, $tableId, $data, $period = null)
109
  {
110
+ // Fix for compatibility with old PRO versions start
111
+ $config = $this->environment->getConfig();
112
+ $updateField = version_compare($config->get('plugin_version_pro'), '1.4.3', '>') ? 'updated' : 'created';
113
+ // Fix for compatibility with old PRO versions end
114
+
115
  for($i = 0; $i < count($data); $i++) {
116
  $data[$i] = $this->prepareRowsData($data[$i], true);
117
  }
118
+ $history = array('data' => serialize($data),);
119
+ $history[$updateField] = date('Y-m-d H:i:s');
 
 
120
  $historyTable = $this->getUserTableHistory($userId, $tableId, $period);
121
 
122
  if($historyTable) {
src/SupsysticTables/Tables/Model/Tables.php CHANGED
@@ -348,7 +348,7 @@ class SupsysticTables_Tables_Model_Tables extends SupsysticTables_Core_BaseModel
348
  $this->addRow($id, $row);
349
  }
350
 
351
- if($last) {
352
  $this->removeRowsByPart($id, $lastRowId, $last);
353
  delete_option($option_name, $lastRowId);
354
  }
348
  $this->addRow($id, $row);
349
  }
350
 
351
+ if(!empty($last)) {
352
  $this->removeRowsByPart($id, $lastRowId, $last);
353
  delete_option($option_name, $lastRowId);
354
  }
src/SupsysticTables/Tables/Module.php CHANGED
@@ -112,7 +112,16 @@ class SupsysticTables_Tables_Module extends SupsysticTables_Core_BaseModule
112
  public function addDataTableStyles($tableViewId) {
113
  $tableObj = is_object($tableViewId) ? $tableViewId : $this->_tablesObj[$tableViewId];
114
  array_push($this->_tablesStyles, $tableObj->view_id);
115
- return $this->getTwig()->render('@tables/styles.twig', array('tableObj' => $tableObj));
 
 
 
 
 
 
 
 
 
116
  }
117
 
118
  public function getDataTablesObj() {
@@ -203,10 +212,11 @@ class SupsysticTables_Tables_Module extends SupsysticTables_Core_BaseModule
203
  && isset($table->settings['features']['import']['google']['automatically_update'])
204
  && isset($table->settings['features']['import']['google']['link']);
205
 
206
- if (!$this->isSingleCell && !$this->isTablePart && !$this->checkSpreadsheet && !$this->isFromHistory && file_exists($cachePath) && $this->getEnvironment()->isProd()) {
207
  // Connect scripts and styles depending on table settings and table's cells settings for table cache
208
  $dispatcher = $this->getEnvironment()->getDispatcher();
209
  $dispatcher->apply('before_table_render', array($table));
 
210
  return file_get_contents($cachePath);
211
  }
212
  if ($this->checkSpreadsheet) {
@@ -1070,7 +1080,8 @@ class SupsysticTables_Tables_Module extends SupsysticTables_Core_BaseModule
1070
  * Call wp footer manualy on broken themes to ensure than scripts are loaded
1071
  */
1072
  public function onShutdown() {
1073
- if (!is_admin() && did_action('after_setup_theme') && did_action('get_footer') && !did_action('wp_footer')) {
 
1074
  wp_footer();
1075
  }
1076
  }
@@ -1115,38 +1126,44 @@ class SupsysticTables_Tables_Module extends SupsysticTables_Core_BaseModule
1115
  $environment = $this->getEnvironment();
1116
  $config = $environment->getConfig();
1117
  $dispatcher = $environment->getDispatcher();
1118
-
1119
- return $dispatcher->apply('table-shortcodes-list',
1120
- array(
1121
- array(
1122
- 'shortcode' => array(
1123
- 'name' => $config->get('shortcode_name'),
1124
- 'label' => $environment->translate('Table Shortcode'),
1125
- 'attrs' => '',
1126
- ),
1127
- 'part_shortcode' => array(
1128
- 'name' => $config->get('shortcode_part_name'),
1129
- 'label' => $environment->translate('Table Part Shortcode'),
1130
- 'attrs' => 'row=1,2 col=1,2',
1131
- ),
1132
- 'cell_shortcode' => array(
1133
- 'name' => $config->get('shortcode_part_name'),
1134
- 'label' => $environment->translate('Cell Shortcode'),
1135
- 'attrs' => 'row=1 col=1',
1136
- ),
1137
- 'value_shortcode' => array(
1138
- 'name' => $config->get('shortcode_value_name'),
1139
- 'label' => $environment->translate('Value Shortcode'),
1140
- 'attrs' => 'row=1 col=1',
1141
- ),
1142
- 'php_code' => array(
1143
- 'name' => $config->get('shortcode_name'),
1144
- 'label' => $environment->translate('PHP code'),
1145
- 'attrs' => '',
1146
- ),
1147
- )
1148
- )
1149
  );
 
 
 
 
 
 
 
 
 
 
 
1150
  }
1151
  }
1152
 
112
  public function addDataTableStyles($tableViewId) {
113
  $tableObj = is_object($tableViewId) ? $tableViewId : $this->_tablesObj[$tableViewId];
114
  array_push($this->_tablesStyles, $tableObj->view_id);
115
+
116
+ if(!empty($tableObj->meta) && !empty($tableObj->meta)) {
117
+ $styles = $tableObj->meta['css'];
118
+ $styles = trim(preg_replace('/\/\*.*\*\//Us', '', $styles));
119
+
120
+ if(!empty($styles)) {
121
+ return $this->getTwig()->render('@tables/styles.twig', array('tableObj' => $tableObj));
122
+ }
123
+ }
124
+ return '';
125
  }
126
 
127
  public function getDataTablesObj() {
212
  && isset($table->settings['features']['import']['google']['automatically_update'])
213
  && isset($table->settings['features']['import']['google']['link']);
214
 
215
+ if (!isset($table->settings['disableCache']) && !$this->isSingleCell && !$this->isTablePart && !$this->checkSpreadsheet && !$this->isFromHistory && file_exists($cachePath) && $this->getEnvironment()->isProd()) {
216
  // Connect scripts and styles depending on table settings and table's cells settings for table cache
217
  $dispatcher = $this->getEnvironment()->getDispatcher();
218
  $dispatcher->apply('before_table_render', array($table));
219
+ $dispatcher->apply('before_table_render_from_cache', array($table));
220
  return file_get_contents($cachePath);
221
  }
222
  if ($this->checkSpreadsheet) {
1080
  * Call wp footer manualy on broken themes to ensure than scripts are loaded
1081
  */
1082
  public function onShutdown() {
1083
+ $settings = get_option('supsystic_tbl_settings');
1084
+ if (empty($settings['disable_wp_footer_fix']) && !is_admin() && did_action('after_setup_theme') && did_action('get_footer') && !did_action('wp_footer')) {
1085
  wp_footer();
1086
  }
1087
  }
1126
  $environment = $this->getEnvironment();
1127
  $config = $environment->getConfig();
1128
  $dispatcher = $environment->getDispatcher();
1129
+ $shortcodes = array(
1130
+ 'shortcode' => array(
1131
+ 'name' => $config->get('shortcode_name'),
1132
+ 'label' => $environment->translate('Table Shortcode'),
1133
+ 'attrs' => '',
1134
+ ),
1135
+ 'part_shortcode' => array(
1136
+ 'name' => $config->get('shortcode_part_name'),
1137
+ 'label' => $environment->translate('Table Part Shortcode'),
1138
+ 'attrs' => 'row=1,2 col=1,2',
1139
+ ),
1140
+ 'cell_shortcode' => array(
1141
+ 'name' => $config->get('shortcode_part_name'),
1142
+ 'label' => $environment->translate('Cell Shortcode'),
1143
+ 'attrs' => 'row=1 col=1',
1144
+ ),
1145
+ 'value_shortcode' => array(
1146
+ 'name' => $config->get('shortcode_value_name'),
1147
+ 'label' => $environment->translate('Value Shortcode'),
1148
+ 'attrs' => 'row=1 col=1',
1149
+ ),
1150
+ 'php_code' => array(
1151
+ 'name' => $config->get('shortcode_name'),
1152
+ 'label' => $environment->translate('PHP code'),
1153
+ 'attrs' => '',
1154
+ ),
 
 
 
 
 
1155
  );
1156
+
1157
+ if($this->getEnvironment()->isPro()) {
1158
+ // it should be here for compatibility with old pro versions
1159
+ $shortcodes['history_shortcode'] = array(
1160
+ 'name' => $config->get('shortcode_name'),
1161
+ 'label' => $environment->translate('History Shortcode'),
1162
+ 'attrs' => 'use_history=1',
1163
+ );
1164
+ }
1165
+
1166
+ return $dispatcher->apply('table-shortcodes-list', array($shortcodes));
1167
  }
1168
  }
1169
 
src/SupsysticTables/Tables/assets/css/tables.editor.css CHANGED
@@ -153,10 +153,24 @@ i.toolbar-word-wrap.word-wrap-visible {
153
  }
154
 
155
  #tableEditor .editable, #tableEditor .selectable, #tableEditor .datefield, #tableEditor .unescapeHTML,
156
- #tableEditor .hiddenCell, #tableEditor .invisibleCell, #tableEditor .collapsibleCell, #tableEditor .tooltipCell {
157
  position: relative;
158
  }
159
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  #tableEditor .editable:after {
161
  content: '';
162
  display: block;
@@ -364,4 +378,4 @@ i.toolbar-word-wrap.word-wrap-visible {
364
  #formulaEditor #formula {
365
  width: 85%;
366
  }
367
- }
153
  }
154
 
155
  #tableEditor .editable, #tableEditor .selectable, #tableEditor .datefield, #tableEditor .unescapeHTML,
156
+ #tableEditor .hiddenCell, #tableEditor .invisibleCell, #tableEditor .collapsibleCell, #tableEditor .tooltipCell, #tableEditor .formatedCell {
157
  position: relative;
158
  }
159
 
160
+ #tableEditor .formatedCell:before {
161
+ content: '';
162
+ display: block;
163
+ position: absolute;
164
+ top: 0;
165
+ left: 0;
166
+ width: 0;
167
+ height: 0;
168
+ border-top: 7px solid #000;
169
+ border-left: 0 solid transparent;
170
+ border-right: 7px solid transparent;
171
+ border-bottom: 0 solid transparent;
172
+ }
173
+
174
  #tableEditor .editable:after {
175
  content: '';
176
  display: block;
378
  #formulaEditor #formula {
379
  width: 85%;
380
  }
381
+ }
src/SupsysticTables/Tables/assets/js/editor/tables.editor.formula.js CHANGED
@@ -2,15 +2,33 @@
2
 
3
  var Formula = (function () {
4
  function Formula(editor) {
5
- var input = $('#formula');
 
 
 
 
 
 
6
 
7
  this.getInput = function () {
8
  return input;
9
  };
10
 
11
- this.getEditor = function () {
12
- return editor;
13
- }
 
 
 
 
 
 
 
 
 
 
 
 
14
  }
15
 
16
  Formula.prototype.getValue = function () {
@@ -22,7 +40,7 @@
22
  };
23
 
24
  Formula.prototype.getSupportedFormulas = function () {
25
- if (ruleJS() === undefined) {
26
  return null;
27
  }
28
 
@@ -48,16 +66,33 @@
48
  }, this));
49
 
50
  this.getInput().on('keyup', $.proxy(function (e) {
51
- var range = this.getEditor().getSelectedRange(),
52
- oldVal = this.getEditor().getDataAtCell(range.highlight.row, range.highlight.col),
53
- newVal = this.getValue();
54
-
55
- if(oldVal != newVal) {
56
- this.getEditor().setDataAtCell(
57
- range.highlight.row,
58
- range.highlight.col,
59
- newVal
60
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  }
62
  }, this));
63
 
2
 
3
  var Formula = (function () {
4
  function Formula(editor) {
5
+ var input = $('#formula'),
6
+ inputData = {},
7
+ inputTimeout = false;
8
+
9
+ this.getEditor = function () {
10
+ return editor;
11
+ };
12
 
13
  this.getInput = function () {
14
  return input;
15
  };
16
 
17
+ this.getInputTimeout = function () {
18
+ return inputTimeout;
19
+ };
20
+
21
+ this.setInputTimeout = function (val) {
22
+ inputTimeout = val;
23
+ };
24
+
25
+ this.getInputData = function () {
26
+ return inputData;
27
+ };
28
+
29
+ this.setInputData = function (val) {
30
+ inputData = val;
31
+ };
32
  }
33
 
34
  Formula.prototype.getValue = function () {
40
  };
41
 
42
  Formula.prototype.getSupportedFormulas = function () {
43
+ if (typeof ruleJS != 'function') {
44
  return null;
45
  }
46
 
66
  }, this));
67
 
68
  this.getInput().on('keyup', $.proxy(function (e) {
69
+ // Enter, Tab, ArrowUp, ArrowLeft, ArrowRight, ArrowDown buttons
70
+ if (toeInArray((e.keyCode || e.which), [13, 9, 37, 38, 39, 40]) != -1) return false;
71
+
72
+ var self = this,
73
+ range = self.getEditor().getSelectedRange();
74
+
75
+ self.setInputData({
76
+ row: range.highlight.row,
77
+ col: range.highlight.col,
78
+ oldVal: self.getEditor().getDataAtCell(range.highlight.row, range.highlight.col),
79
+ newVal: self.getValue()
80
+ });
81
+
82
+ if(!self.getInputTimeout()) {
83
+ setTimeout(function() {
84
+ var keyupData = self.getInputData();
85
+
86
+ if(keyupData.oldVal != keyupData.newVal) {
87
+ self.getEditor().setDataAtCell(
88
+ keyupData.row,
89
+ keyupData.col,
90
+ keyupData.newVal
91
+ );
92
+ }
93
+ self.setInputTimeout(false);
94
+ }, 500);
95
+ self.setInputTimeout(true);
96
  }
97
  }, this));
98
 
src/SupsysticTables/Tables/assets/js/editor/tables.editor.js CHANGED
@@ -42,6 +42,102 @@ g_stbWindowHeight = 0;
42
  toolbar.subscribe();
43
  formula.subscribe();
44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  // Editor Hooks
46
  editor.addHook('beforeCellAlignment', function (stateBefore, range, type, alignmentClass) {
47
  updateUndoRedoBtns();
@@ -216,142 +312,6 @@ g_stbWindowHeight = 0;
216
  editor.render();
217
  });
218
 
219
- // Custom Handsontabe Renderers
220
- Handsontable.renderers.CustomHtmlRenderer = function(instance,td,row,col,prop,value,cellProperties) {
221
- Handsontable.renderers.HtmlRenderer.call(this,instance,td,row,col,prop,value,cellProperties);
222
- if(td.innerHTML === 'null') {
223
- td.innerHTML = '';
224
- }
225
- };
226
- Handsontable.renderers.DefaultRenderer = function(instance,td,row,col,prop,value,cellProperties) {
227
- var cellMeta = instance.getCellMeta(row, col);
228
-
229
- if(tablesModel.isFormula(value)) {
230
- Handsontable.TextCell.renderer.apply(this,arguments);
231
- value = tablesModel.getFormulaResult(value,row,col);
232
- }
233
- if(cellProperties && cellProperties.formatType == 'currency') {
234
- Handsontable.renderers.CurrencyRenderer.call(this,instance,td,row,col,prop,value,cellProperties);
235
- } else if(cellProperties && cellProperties.formatType == 'percent') {
236
- Handsontable.renderers.PercentRenderer.call(this,instance,td,row,col,prop,value,cellProperties);
237
- } else if(instance.useNumberFormat && (tablesModel.isNumber(value) || cellMeta.formatType == 'number')) {
238
- Handsontable.renderers.NumberRenderer.call(this,instance,td,row,col,prop,value,cellProperties);
239
- } else {
240
- Handsontable.renderers.CustomHtmlRenderer.call(this,instance,td,row,col,prop,value,cellProperties);
241
- }
242
- };
243
- Handsontable.renderers.NumberRenderer = function(instance,td,row,col,prop,value,cellProperties) {
244
- value = tablesModel.setCellFormat(value,'number');
245
-
246
- Handsontable.renderers.CustomHtmlRenderer.call(this,instance,td,row,col,prop,value,cellProperties);
247
- };
248
- Handsontable.renderers.CurrencyRenderer = function(instance,td,row,col,prop,value,cellProperties) {
249
- if(value) {
250
- if(tablesModel.isFormula(value)) {
251
- Handsontable.TextCell.renderer.apply(this,arguments);
252
- value = tablesModel.getFormulaResult(value,row,col);
253
- }
254
-
255
- value = tablesModel.setCellFormat(value,'currency');
256
- }
257
-
258
- Handsontable.renderers.CustomHtmlRenderer.call(this,instance,td,row,col,prop,value,cellProperties);
259
- };
260
- Handsontable.renderers.PercentRenderer = function(instance,td,row,col,prop,value,cellProperties) {
261
- if(value) {
262
- if(tablesModel.isFormula(value)) {
263
- Handsontable.TextCell.renderer.apply(this,arguments);
264
- value = tablesModel.getFormulaResult(value,row,col);
265
- }
266
-
267
- value = tablesModel.setCellFormat(value,'percent');
268
- }
269
-
270
- Handsontable.renderers.CustomHtmlRenderer.call(this,instance,td,row,col,prop,value,cellProperties);
271
- };
272
- Handsontable.editors.TextEditor.prototype.focus = function() {
273
- this.TEXTAREA.select();
274
- };
275
- Handsontable.editors.TextEditor.prototype.beginEditing = function() {
276
- // To show percents as is if it is pure number
277
- var formatType = this.cellProperties.formatType || '',value = this.originalValue;
278
-
279
- if(tablesModel.isNumber(value) && !tablesModel.isFormula(value)) {
280
- if(formatType == 'percent') {
281
- value = (value * 100).toString();
282
- }
283
- }
284
-
285
- this.originalValue = value;
286
-
287
- Handsontable.editors.BaseEditor.prototype.beginEditing.call(this);
288
- };
289
- Handsontable.editors.TextEditor.prototype.saveValue = function(val,ctrlDown) {
290
- // Correct save of percent values
291
- var type = this.cellProperties.type || '',formatType = this.cellProperties.formatType || '',value = val[0][0];
292
-
293
- if(tablesModel.isNumber(value) && !tablesModel.isFormula(value)) {
294
- if(formatType == 'percent' && type != 'dropdown') {
295
- value = (value / 100).toString();
296
- }
297
- }
298
- if(formatType == 'time_duration') {
299
- var cellFormat = this.cellProperties.format || $('input[name="timeDurationFormat"]').val(),newTime = moment(value,cellFormat);
300
-
301
- if(newTime.isValid()) {
302
- value = newTime.format(cellFormat);
303
- } else {
304
- var duration = value.match(/.{1,2}/g);
305
-
306
- newTime = moment.duration({
307
- seconds: duration[2] || 0,minutes: duration[1] || 0,hours: duration[0] || 0,days: 0,weeks: 0,months: 0,years: 0
308
- });
309
-
310
- if(newTime._milliseconds || value == 0) {
311
- value = newTime.format(cellFormat);
312
- }
313
- }
314
- }
315
-
316
- val[0][0] = value;
317
-
318
- Handsontable.editors.BaseEditor.prototype.saveValue.call(this,val,ctrlDown);
319
- };
320
- Handsontable.editors.DropdownEditor.prototype.beginEditing = function() {
321
- // To show percents as is if it is pure number
322
- var formatType = this.cellProperties.formatType || '',source = this.cellProperties.source || [];
323
-
324
- for(var i = 0; i < source.length; i++) {
325
- if(tablesModel.isNumber(source[i]) && !tablesModel.isFormula(source[i])) {
326
- if(formatType == 'percent') {
327
- source[i] = (source[i] * 100).toString();
328
- }
329
- }
330
- }
331
- Handsontable.editors.BaseEditor.prototype.beginEditing.call(this);
332
- };
333
-
334
- Handsontable.editors.DropdownEditor.prototype.saveValue = function(val,ctrlDown) {
335
- // Correct save of percent values
336
- var type = this.cellProperties.type || '',formatType = this.cellProperties.formatType || '',source = this.cellProperties.source || [],value = val[0][0];
337
-
338
- if(tablesModel.isNumber(value) && !tablesModel.isFormula(value)) {
339
- if(formatType == 'percent') {
340
- value = (value / 100).toString();
341
- }
342
- }
343
- for(var i = 0; i < source.length; i++) {
344
- if(tablesModel.isNumber(source[i]) && !tablesModel.isFormula(source[i])) {
345
- if(formatType == 'percent') {
346
- source[i] = (source[i] / 100).toString();
347
- }
348
- }
349
- }
350
- val[0][0] = value;
351
-
352
- Handsontable.editors.BaseEditor.prototype.saveValue.call(this,val,ctrlDown);
353
- };
354
-
355
  // Load table data to editor
356
  $.when(
357
  tablesModel.getMeta(tableId),
42
  toolbar.subscribe();
43
  formula.subscribe();
44
 
45
+ // Custom Handsontabe Renderer
46
+ Handsontable.renderers.DefaultRenderer = function(instance,td,row,col,prop,value,cellProperties) {
47
+ value = Handsontable.TextCell.renderer.call(this,instance,td,row,col,prop,value,cellProperties);
48
+
49
+ if(cellProperties && cellProperties.formatType == 'currency') {
50
+ value = tablesModel.setCellFormat(value,'currency');
51
+ } else if(cellProperties && cellProperties.formatType == 'percent') {
52
+ value = tablesModel.setCellFormat(value,'percent');
53
+ } else if(instance.useNumberFormat && (app.isNumber(value) || cellProperties.formatType == 'number')) {
54
+ value = tablesModel.setCellFormat(value,'number');
55
+ }
56
+ Handsontable.TextCell.renderer.call(this,instance,td,row,col,prop,value,cellProperties);
57
+ };
58
+ Handsontable.editors.TextEditor.prototype.focus = function() {
59
+ this.TEXTAREA.select();
60
+ };
61
+ Handsontable.editors.TextEditor.prototype.beginEditing = function() {
62
+ // To show percents as is if it is pure number
63
+ var formatType = this.cellProperties.formatType || '',value = this.originalValue;
64
+
65
+ if(app.isNumber(value) && !tablesModel.isFormula(value)) {
66
+ if(formatType == 'percent') {
67
+ value = (value * 100).toString();
68
+ }
69
+ }
70
+
71
+ this.originalValue = value;
72
+
73
+ Handsontable.editors.BaseEditor.prototype.beginEditing.call(this);
74
+ };
75
+ Handsontable.editors.TextEditor.prototype.saveValue = function(val,ctrlDown) {
76
+ // Correct save of percent values
77
+ var type = this.cellProperties.type || '',formatType = this.cellProperties.formatType || '',value = val[0][0];
78
+
79
+ if(app.isNumber(value) && !tablesModel.isFormula(value)) {
80
+ if(formatType == 'percent' && type != 'dropdown') {
81
+ value = (value / 100).toString();
82
+ }
83
+ }
84
+ if(formatType == 'time_duration') {
85
+ var cellFormat = this.cellProperties.format || $('input[name="timeDurationFormat"]').val(),newTime = moment(value,cellFormat);
86
+
87
+ if(newTime.isValid()) {
88
+ value = newTime.format(cellFormat);
89
+ } else {
90
+ var duration = value.match(/.{1,2}/g);
91
+
92
+ newTime = moment.duration({
93
+ seconds: duration[2] || 0,minutes: duration[1] || 0,hours: duration[0] || 0,days: 0,weeks: 0,months: 0,years: 0
94
+ });
95
+
96
+ if(newTime._milliseconds || value == 0) {
97
+ value = newTime.format(cellFormat);
98
+ }
99
+ }
100
+ }
101
+
102
+ val[0][0] = value;
103
+
104
+ Handsontable.editors.BaseEditor.prototype.saveValue.call(this,val,ctrlDown);
105
+ };
106
+ Handsontable.editors.DropdownEditor.prototype.beginEditing = function() {
107
+ // To show percents as is if it is pure number
108
+ var formatType = this.cellProperties.formatType || '',source = this.cellProperties.source || [];
109
+
110
+ for(var i = 0; i < source.length; i++) {
111
+ if(app.isNumber(source[i]) && !tablesModel.isFormula(source[i])) {
112
+ if(formatType == 'percent') {
113
+ source[i] = (source[i] * 100).toString();
114
+ }
115
+ }
116
+ }
117
+ Handsontable.editors.BaseEditor.prototype.beginEditing.call(this);
118
+ };
119
+
120
+ Handsontable.editors.DropdownEditor.prototype.saveValue = function(val,ctrlDown) {
121
+ // Correct save of percent values
122
+ var type = this.cellProperties.type || '',formatType = this.cellProperties.formatType || '',source = this.cellProperties.source || [],value = val[0][0];
123
+
124
+ if(app.isNumber(value) && !tablesModel.isFormula(value)) {
125
+ if(formatType == 'percent') {
126
+ value = (value / 100).toString();
127
+ }
128
+ }
129
+ for(var i = 0; i < source.length; i++) {
130
+ if(app.isNumber(source[i]) && !tablesModel.isFormula(source[i])) {
131
+ if(formatType == 'percent') {
132
+ source[i] = (source[i] / 100).toString();
133
+ }
134
+ }
135
+ }
136
+ val[0][0] = value;
137
+
138
+ Handsontable.editors.BaseEditor.prototype.saveValue.call(this,val,ctrlDown);
139
+ };
140
+
141
  // Editor Hooks
142
  editor.addHook('beforeCellAlignment', function (stateBefore, range, type, alignmentClass) {
143
  updateUndoRedoBtns();
312
  editor.render();
313
  });
314
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
315
  // Load table data to editor
316
  $.when(
317
  tablesModel.getMeta(tableId),
src/SupsysticTables/Tables/assets/js/editor/tables.editor.toolbar.js CHANGED
@@ -3,6 +3,17 @@ var g_stbCellBgColorTimeoutSet = false,
3
  g_stbCellBgColorLast = '',
4
  g_stbCellTxtColorLast = '';
5
  (function ($, app, undefined) {
 
 
 
 
 
 
 
 
 
 
 
6
 
7
  // Toolbar methods
8
  var methods = {
@@ -19,8 +30,8 @@ var g_stbCellBgColorTimeoutSet = false,
19
  this.getEditor().render();
20
  },
21
  color: function (color) {
22
- var $style = getAdminCellStylesElem(),
23
- classes = classesRegexp();
24
 
25
  if($style.html().indexOf('.color-'+color) == -1) {
26
  $style.html($style.html() + ' .color-'+color+' {color:#'+color+' !important;'+'}');
@@ -31,12 +42,12 @@ var g_stbCellBgColorTimeoutSet = false,
31
  this.getEditor().render();
32
  },
33
  background: function (color) {
34
- var classes = classesRegexp();
35
 
36
  if (color === 'ffffff') {
37
  this.removeClass(classes.background);
38
  } else {
39
- var $style = getAdminCellStylesElem();
40
 
41
  if($style.html().indexOf('.bg-'+color) == -1) {
42
  $style.html($style.html() + ' .bg-'+color+' {background:#'+color+' !important;}');
@@ -47,13 +58,13 @@ var g_stbCellBgColorTimeoutSet = false,
47
  this.getEditor().render();
48
  },
49
  size: function (e) {
50
- var classes = classesRegexp(),
51
  size = $(e.target).val();
52
 
53
  if (!size || size == 'default') {
54
  this.removeClass(classes.fontSize);
55
  } else {
56
- var $style = getAdminCellStylesElem();
57
 
58
  if($style.html().indexOf('.fsize-'+size) == -1) {
59
  var lineHeight = +size + 6;
@@ -205,7 +216,7 @@ var g_stbCellBgColorTimeoutSet = false,
205
  );
206
  $this.dialog('close');
207
  },
208
- Cansel: function (e) {
209
  $(this).dialog('close');
210
  }
211
  }
@@ -347,6 +358,12 @@ var g_stbCellBgColorTimeoutSet = false,
347
  return editor;
348
  };
349
  }
 
 
 
 
 
 
350
  Toolbar.prototype.getValidRange = function (range) {
351
  if (range !== undefined) {
352
  var startRow = range.from.row,
@@ -388,7 +405,7 @@ var g_stbCellBgColorTimeoutSet = false,
388
  newClassName;
389
 
390
  cell.className = typeof cell.className == 'string' ? cell.className : '';
391
-
392
  if (cell.className.match(classNamePattern)) {
393
  newClassName = cell.className.replace(className, '');
394
  } else {
@@ -398,6 +415,37 @@ var g_stbCellBgColorTimeoutSet = false,
398
  }
399
  }
400
  };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
401
  Toolbar.prototype.replaceClass = function (className, replace, highlight) {
402
  var editor = this.getEditor(),
403
  range = this.getValidRange(editor.getSelectedRange()),
@@ -416,17 +464,44 @@ var g_stbCellBgColorTimeoutSet = false,
416
  var startRow = highlight ? range.highlight.row : range.from.row,
417
  endRow = highlight ? range.highlight.row : range.to.row,
418
  startCol = highlight ? range.highlight.col : range.from.col,
419
- endCol = highlight ? range.highlight.col : range.to.col;
 
420
 
421
- for (var row = startRow; row <= endRow; row++) {
422
- for (var col = startCol; col <= endCol; col++) {
423
- var cell = editor.getCellMeta(row, col);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
424
 
425
- cell.className = cell.className || '';
426
- cell.className = cell.className.replace(replPattern, '');
427
- editor.setCellMeta(row, col, 'className', cell.className + ' ' + className);
428
- }
429
- }
430
  };
431
  Toolbar.prototype.removeClass = function (className, highlight) {
432
  var editor = this.getEditor(),
@@ -438,14 +513,37 @@ var g_stbCellBgColorTimeoutSet = false,
438
  var startRow = highlight ? range.highlight.row : range.from.row,
439
  endRow = highlight ? range.highlight.row : range.to.row,
440
  startCol = highlight ? range.highlight.col : range.from.col,
441
- endCol = highlight ? range.highlight.col : range.to.col;
 
442
 
443
  for (var row = startRow; row <= endRow; row++) {
444
  for (var col = startCol; col <= endCol; col++) {
445
- var cell = editor.getCellMeta(row, col);
446
- editor.setCellMeta(row, col, 'className', cell.className.replace(className, ' '));
447
- }
448
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
449
  };
450
  Toolbar.prototype.getSelectedText = function(element) {
451
  var txtarea = element;
@@ -545,7 +643,7 @@ var g_stbCellBgColorTimeoutSet = false,
545
  editor.validateCell(data, cell, function() {}, 'validateCells');
546
  editor.setDataAtCell(row, col, data);
547
  }
548
- }
549
  };
550
  // Apply methods to its buttons / elements
551
  Toolbar.prototype.subscribe = function () {
@@ -615,7 +713,7 @@ var g_stbCellBgColorTimeoutSet = false,
615
  return;
616
  }
617
  var cellMeta = self.getEditor().getCellMeta(startRow, startCol),
618
- classes = classesRegexp(),
619
  color = classes.color.exec(cell.className),
620
  background = classes.background.exec(cell.className),
621
  size = classes.fontSize.exec(cell.className),
@@ -658,11 +756,12 @@ var g_stbCellBgColorTimeoutSet = false,
658
  });
659
 
660
  this.getContainer().find('button').each(function () {
661
- var $button = $(this);
 
662
 
663
- if ($button.data('toolbar') !== undefined) {
664
  $button.toolbar({
665
- content: $button.data('toolbar'),
666
  position: 'bottom',
667
  hideOnClick: true,
668
  style: $button.data('style') || null
@@ -714,4 +813,4 @@ var g_stbCellBgColorTimeoutSet = false,
714
  app.Editor = app.Editor || {};
715
  app.Editor.Toolbar = Toolbar;
716
 
717
- }(window.jQuery, window.supsystic.Tables || {}));
3
  g_stbCellBgColorLast = '',
4
  g_stbCellTxtColorLast = '';
5
  (function ($, app, undefined) {
6
+ var svlFormatsClass = 'formatedCell',
7
+ formatClasses = {
8
+ hiddenCell: ['Hidden','hiddenCell'],
9
+ invisibleCell: ['Invisible','invisibleCell'],
10
+ unescapeHTML: ['UnescapeHTML','unescapeHtml'],
11
+ editable: ['Editable','editableField'],
12
+ selectable: ['Selectable','selectableField'],
13
+ datefield: ['Date','datepickerField'],
14
+ collapsibleCell: ['Collapsible','collapsibleCell'],
15
+ tooltipCell: ['Tooltip','tooltipCell']
16
+ };
17
 
18
  // Toolbar methods
19
  var methods = {
30
  this.getEditor().render();
31
  },
32
  color: function (color) {
33
+ var $style = app.getAdminCellStylesElem(),
34
+ classes = app.getClassesRegexp();
35
 
36
  if($style.html().indexOf('.color-'+color) == -1) {
37
  $style.html($style.html() + ' .color-'+color+' {color:#'+color+' !important;'+'}');
42
  this.getEditor().render();
43
  },
44
  background: function (color) {
45
+ var classes = app.getClassesRegexp();
46
 
47
  if (color === 'ffffff') {
48
  this.removeClass(classes.background);
49
  } else {
50
+ var $style = app.getAdminCellStylesElem();
51
 
52
  if($style.html().indexOf('.bg-'+color) == -1) {
53
  $style.html($style.html() + ' .bg-'+color+' {background:#'+color+' !important;}');
58
  this.getEditor().render();
59
  },
60
  size: function (e) {
61
+ var classes = app.getClassesRegexp(),
62
  size = $(e.target).val();
63
 
64
  if (!size || size == 'default') {
65
  this.removeClass(classes.fontSize);
66
  } else {
67
+ var $style = app.getAdminCellStylesElem();
68
 
69
  if($style.html().indexOf('.fsize-'+size) == -1) {
70
  var lineHeight = +size + 6;
216
  );
217
  $this.dialog('close');
218
  },
219
+ Cancel: function (e) {
220
  $(this).dialog('close');
221
  }
222
  }
358
  return editor;
359
  };
360
  }
361
+ Toolbar.prototype.getFormatClasses = function () {
362
+ return formatClasses;
363
+ };
364
+ Toolbar.prototype.getSvlFormatClass = function () {
365
+ return svlFormatsClass;
366
+ };
367
  Toolbar.prototype.getValidRange = function (range) {
368
  if (range !== undefined) {
369
  var startRow = range.from.row,
405
  newClassName;
406
 
407
  cell.className = typeof cell.className == 'string' ? cell.className : '';
408
+
409
  if (cell.className.match(classNamePattern)) {
410
  newClassName = cell.className.replace(className, '');
411
  } else {
415
  }
416
  }
417
  };
418
+ Toolbar.prototype.setTooltip = function(row, col) {
419
+ var cell = $(".htCore tbody tr").eq(row).find('td').eq(col),
420
+ meta = this.getEditor().getCellMeta(row, col),
421
+ dataFormats = ('data-formats' in meta ? meta['data-formats'] : '');
422
+
423
+ if(dataFormats.length > 0)
424
+ {
425
+ var formats = dataFormats.split(' '),
426
+ title = '',
427
+ n = 1;
428
+
429
+ for (var i = 0; i < formats.length; i++) {
430
+ var className = formats[i];
431
+ if (className in formatClasses) {
432
+ var o = $('[data-toolbar="\\#toolbar-' + formatClasses[className][1] + '"]');
433
+ title += (n++) + '. ' + o.html() + formatClasses[className][0] + '<br>';
434
+ }
435
+ }
436
+ $(cell).tooltip({
437
+ trigger: 'hover',
438
+ html: true,
439
+ placement: 'auto',
440
+ container: 'body',
441
+ title: title,
442
+ template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner" style="text-align:left"></div></div>'
443
+ });
444
+ $(cell).attr('title', title).tooltip('fixTitle').tooltip('setContent');
445
+ } else {
446
+ $(cell).tooltip('destroy');
447
+ }
448
+ };
449
  Toolbar.prototype.replaceClass = function (className, replace, highlight) {
450
  var editor = this.getEditor(),
451
  range = this.getValidRange(editor.getSelectedRange()),
464
  var startRow = highlight ? range.highlight.row : range.from.row,
465
  endRow = highlight ? range.highlight.row : range.to.row,
466
  startCol = highlight ? range.highlight.col : range.from.col,
467
+ endCol = highlight ? range.highlight.col : range.to.col,
468
+ isFormat = (className in formatClasses);
469
 
470
+ for (var row = startRow; row <= endRow; row++) {
471
+ for (var col = startCol; col <= endCol; col++) {
472
+ var cell = editor.getCellMeta(row, col),
473
+ newClass = className,
474
+ cellClasses = cell.className || '';
475
+
476
+ cellClasses = cellClasses.replace(replPattern, '').trim();
477
+
478
+ if (isFormat) {
479
+ if (cellClasses.indexOf(svlFormatsClass) !== -1) {
480
+ var dataFormats = ('data-formats' in cell ? cell['data-formats'] : '');
481
+ dataFormats = dataFormats.replace(replPattern, '').trim();
482
+ editor.setCellMeta(row, col, 'data-formats', dataFormats + ' ' + className);
483
+ newClass = '';
484
+ } else {
485
+ var curFormats = [];
486
+ for (var c in formatClasses) {
487
+ if (cellClasses.indexOf(c) !== -1) {
488
+ curFormats.push(c);
489
+ }
490
+ }
491
+ if (curFormats.length > 0) {
492
+ cellClasses = cellClasses.replace(new RegExp(curFormats.join('|')), '');
493
+ newClass = svlFormatsClass;
494
+ editor.setCellMeta(row, col, 'data-formats', curFormats.join(' ') + ' ' + className);
495
+ }
496
+ }
497
+ this.setTooltip(row, col);
498
+ }
499
 
500
+ if (newClass.length > 0) {
501
+ editor.setCellMeta(row, col, 'className', cellClasses + ' ' + newClass);
502
+ }
503
+ }
504
+ }
505
  };
506
  Toolbar.prototype.removeClass = function (className, highlight) {
507
  var editor = this.getEditor(),
513
  var startRow = highlight ? range.highlight.row : range.from.row,
514
  endRow = highlight ? range.highlight.row : range.to.row,
515
  startCol = highlight ? range.highlight.col : range.from.col,
516
+ endCol = highlight ? range.highlight.col : range.to.col,
517
+ isFormat = (className in formatClasses);
518
 
519
  for (var row = startRow; row <= endRow; row++) {
520
  for (var col = startCol; col <= endCol; col++) {
521
+ var cell = editor.getCellMeta(row, col),
522
+ cellClasses = cell.className || '';
523
+
524
+ cellClasses = cellClasses.replace(className, '');
525
+
526
+ if (isFormat) {
527
+ var dataFormats = ('data-formats' in cell ? cell['data-formats'] : '');
528
+ if (dataFormats.length > 0) {
529
+ dataFormats = dataFormats.replace(className, '').trim();
530
+ var formats = dataFormats.split(' ');
531
+ if (formats.length <= 1) {
532
+ dataFormats = '';
533
+ cellClasses = cellClasses.replace(svlFormatsClass, '');
534
+ if (formats.length == 1) {
535
+ cellClasses = cellClasses + ' ' + formats[0];
536
+ }
537
+ }
538
+ editor.setCellMeta(row, col, 'data-formats', dataFormats);
539
+ this.setTooltip(row, col);
540
+ } else {
541
+ cellClasses = cellClasses.replace(svlFormatsClass, '');
542
+ }
543
+ }
544
+ editor.setCellMeta(row, col, 'className', cellClasses);
545
+ }
546
+ }
547
  };
548
  Toolbar.prototype.getSelectedText = function(element) {
549
  var txtarea = element;
643
  editor.validateCell(data, cell, function() {}, 'validateCells');
644
  editor.setDataAtCell(row, col, data);
645
  }
646
+ }
647
  };
648
  // Apply methods to its buttons / elements
649
  Toolbar.prototype.subscribe = function () {
713
  return;
714
  }
715
  var cellMeta = self.getEditor().getCellMeta(startRow, startCol),
716
+ classes = app.getClassesRegexp(),
717
  color = classes.color.exec(cell.className),
718
  background = classes.background.exec(cell.className),
719
  size = classes.fontSize.exec(cell.className),
756
  });
757
 
758
  this.getContainer().find('button').each(function () {
759
+ var $button = $(this),
760
+ contentId = $button.data('toolbar');
761
 
762
+ if (contentId !== undefined && $(contentId).length) {
763
  $button.toolbar({
764
+ content: contentId,
765
  position: 'bottom',
766
  hideOnClick: true,
767
  style: $button.data('style') || null
813
  app.Editor = app.Editor || {};
814
  app.Editor.Toolbar = Toolbar;
815
 
816
+ }(window.jQuery, window.supsystic.Tables || {}));
src/SupsysticTables/Tables/assets/js/tables.model.js CHANGED
@@ -1,4 +1,5 @@
1
  var g_stbDoSaving = false;
 
2
  var g_stbPreviewTimeoutSet = false;
3
  (function ($, app) {
4
 
@@ -75,19 +76,20 @@ var g_stbPreviewTimeoutSet = false;
75
  step = ((typeof app.Models.Tables.step != 'undefined') && parseInt(app.Models.Tables.step)) ? parseInt(app.Models.Tables.step) : 400,
76
  done = true,
77
  ajaxPromise = new $.Deferred().resolve(),
78
- rowsChunks = getChunksArray(rows, step),
79
  rowsData = [];
80
 
81
  for(var i = 0; i < rowsChunks.length; i++) {
82
  rowsData.push({
83
  id: id,
84
  step: step,
85
- last: i == rowsChunks.length - 1 ? 1 : 0,
86
  rows: this._prepareData(rowsChunks[i]) })
87
  }
88
 
89
  $.each(rowsData, function (index, data) {
90
  ajaxPromise = ajaxPromise.then(function() {
 
91
  return self.request('updateRows', data);
92
  },function() {
93
  if(done) {
@@ -142,7 +144,7 @@ var g_stbPreviewTimeoutSet = false;
142
  throw new Error('Invalid table id.');
143
  }
144
 
145
- return this.request('saveSettings', { id: id, settings: settings.serialize() })
146
  };
147
 
148
  TablesModel.prototype.setHistorySettings = function (id, settings) {
@@ -151,7 +153,7 @@ var g_stbPreviewTimeoutSet = false;
151
  throw new Error('Invalid table id.');
152
  }
153
 
154
- return this.request('saveHistorySettings', { id: id, settings: settings.serialize() })
155
  }
156
  };
157
 
@@ -164,7 +166,10 @@ var g_stbPreviewTimeoutSet = false;
164
  editor = self.getEditor(),
165
  rows = rowsResponse[0].rows,
166
  meta = metaResponse[0].meta,
167
- comments = [];
 
 
 
168
 
169
  // Set merged cells
170
  if (typeof meta === 'object' && 'mergedCells' in meta && meta.mergedCells.length) {
@@ -179,7 +184,7 @@ var g_stbPreviewTimeoutSet = false;
179
  cellsMeta = [],
180
  heights = [],
181
  widths = [],
182
- $style = getAdminCellStylesElem();
183
 
184
  $.each(rows, function (x, row) {
185
  var cells = [];
@@ -190,7 +195,7 @@ var g_stbPreviewTimeoutSet = false;
190
  var metaData = {};
191
 
192
  if ('meta' in cell && cell.meta !== undefined) {
193
- var classes = classesRegexp(),
194
  color = classes.color.exec(cell.meta),
195
  background = classes.background.exec(cell.meta),
196
  fontFamily = classes.fontFamily.exec(cell.meta),
@@ -216,7 +221,27 @@ var g_stbPreviewTimeoutSet = false;
216
  var lineHeight = +fontSize[1] + 6;
217
  $style.html($style.html() + ' .'+fontSize[0]+' {font-size:'+fontSize[1]+'px !important; line-height:'+lineHeight+'px !important;}');
218
  }
219
- metaData = $.extend(metaData, { row: x, col: y, className: cell.meta.join(' ') });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
  }
221
  if (cell.formatType) {
222
  metaData = $.extend(metaData, {
@@ -225,7 +250,7 @@ var g_stbPreviewTimeoutSet = false;
225
  formatType: cell.type == 'numeric' ? '' : cell.formatType
226
  });
227
  } else {
228
- if(app.Models.Tables.isNumber(cell.data)) {
229
  metaData = $.extend(metaData, {
230
  type: 'text',
231
  format: '',
@@ -240,12 +265,6 @@ var g_stbPreviewTimeoutSet = false;
240
  metaData.baseType = cell.baseType;
241
  }
242
  switch(cell.formatType) {
243
- /*case 'currency':
244
- metaData.renderer = Handsontable.renderers.CurrencyRenderer;
245
- break;
246
- case 'percent':
247
- metaData.renderer = Handsontable.renderers.PercentRenderer;
248
- break;*/
249
  case 'date':
250
  //one table can contain multiple date formats
251
  metaData.format = cell.format;
@@ -333,6 +352,7 @@ var g_stbPreviewTimeoutSet = false;
333
  // Load extracted metadata
334
  $.each(cellsMeta, function (i, meta) {
335
  editor.setCellMetaObject(meta.row, meta.col, meta);
 
336
  });
337
  }
338
  };
@@ -345,7 +365,10 @@ var g_stbPreviewTimeoutSet = false;
345
  preview = typeof(preview) != 'undefined' ? preview : false;
346
  var self = this,
347
  editor = self.getEditor(),
348
- id = app.getParameterByName('id');
 
 
 
349
 
350
  if(!g_stbDoSaving) {
351
  g_stbDoSaving = true;
@@ -376,59 +399,71 @@ var g_stbPreviewTimeoutSet = false;
376
 
377
  $.each(row, function (y, cell) {
378
  var meta = editor.getCellMeta(x, y),
379
- cellHtml = $(editor.getCell(x, y)),
 
 
 
 
 
 
 
 
 
 
 
 
 
380
  classes = [],
381
- rowData = {
382
  data: cell,
383
  calculatedValue: null,
384
  hidden: false,
385
- hiddenCell: meta.className && meta.className.match('hiddenCell') !== null,
386
- invisibleCell: meta.className && meta.className.match('invisibleCell') !== null
387
  },
388
  mergeCell = editor.mergeCells.mergedCellInfoCollection.getInfo(x, y);
389
 
390
  // set merged params
391
  if(mergeCell !== undefined) {
392
- mergeData.push(mergeCell);
393
- rowData.hidden = true;
394
  }
395
  // set formatted value
396
  cellHtml = cellHtml.clone();
397
  cellHtml.find('.htAutocompleteArrow').remove();
398
- rowData.formattedValue = cellHtml.text();
399
 
400
  // selectable cell data source
401
  if(meta.source && meta.source.length) {
402
  meta.type = 'dropdown';
403
- rowData.source = meta.source;
404
  }
405
 
406
  // Set cell format
407
- rowData.type = meta.type ? meta.type : 'text';
408
- rowData.baseType = meta.baseType ? meta.baseType : 'text';
409
- rowData.formatType = meta.formatType ? meta.formatType : '';
410
 
411
- switch(rowData.formatType) {
412
  case 'currency':
413
- rowData.format = formData.find('[name="currencyFormat"]').val();
414
  break;
415
  case 'percent':
416
- rowData.format = formData.find('[name="percentFormat"]').val();
417
  break;
418
  case 'date':
419
  //one table can contain multiple date formats
420
- rowData.format = meta.format != 'undefined'
421
  ? meta.format
422
  : formData.find('[name="dateFormat"]').val();
423
 
424
- var date = moment(rowData.data, rowData.format);
425
 
426
  if (date.isValid()) {
427
- rowData.dateOrder = date.format('x');
428
  }
429
  break;
430
  default:
431
- rowData.format = meta.format;
432
  break;
433
  }
434
 
@@ -448,23 +483,23 @@ var g_stbPreviewTimeoutSet = false;
448
  }
449
  }
450
  }
451
- rowData.calculatedValue = value;
452
  }
453
  }
454
 
455
  // Set classes for cell
456
- if (meta.className !== undefined) {
457
- $.each(meta.className.split(' '), function (index, element) {
458
  if (element.length) {
459
  classes.push($.trim(element));
460
  }
461
  });
462
  }
463
- rowData.meta = classes;
464
 
465
  // Set comments for cell
466
  if (typeof(meta.comment) != 'undefined') {
467
- rowData.comment = meta.comment;
468
  }
469
 
470
  // Set column width by cells of first table row
@@ -472,7 +507,7 @@ var g_stbPreviewTimeoutSet = false;
472
  columnsWidth.push(editor.getColWidth(y));
473
  }
474
 
475
- currentRow.cells.push(rowData);
476
  });
477
 
478
  // Row height
@@ -480,7 +515,11 @@ var g_stbPreviewTimeoutSet = false;
480
 
481
  rowsData.push(currentRow);
482
  });
483
-
 
 
 
 
484
  metaData = {
485
  mergedCells: mergeData,
486
  columnsWidth: columnsWidth,
@@ -491,13 +530,26 @@ var g_stbPreviewTimeoutSet = false;
491
  };
492
 
493
  // Request to save settings, meta and rows
494
- $.when(
495
- self.setSettings(id, formData),
496
- self.setHistorySettings(id, $('form#history-settings')),
497
- self.setMeta(id, metaData)
498
- ).then(
499
  function() {
500
- self.setRows(id, rowsData, byPart, preview);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
501
  }
502
  );
503
  } else {
@@ -515,10 +567,9 @@ var g_stbPreviewTimeoutSet = false;
515
  setTimeout(function() {
516
  self.getPreview(id, preview);
517
  }, 50);
518
-
519
  } else {
520
  g_stbPreviewTimeoutSet = false;
521
-
522
  var container = preview instanceof $ ? preview : $(preview),
523
  table;
524
 
@@ -530,6 +581,7 @@ var g_stbPreviewTimeoutSet = false;
530
  table = container.find('table');
531
  app.initializeTable(table, app.showTable, function(table) {
532
  self._afterTablePreview(table);
 
533
  });
534
  });
535
  }
@@ -606,16 +658,6 @@ var g_stbPreviewTimeoutSet = false;
606
  return this.request('remove', { id: id });
607
  };
608
 
609
- TablesModel.prototype.isNumber = function (value) {
610
- if (value) {
611
- if (value.toString().match(/^-{0,1}\d+\.{0,1}\d*$/)) {
612
- return true;
613
- }
614
- }
615
-
616
- return false;
617
- };
618
-
619
  TablesModel.prototype.isFormula = function (value) {
620
  if (value) {
621
  if (value[0] === '=') {
@@ -626,37 +668,108 @@ var g_stbPreviewTimeoutSet = false;
626
  };
627
 
628
  TablesModel.prototype.getFormulaResult = function (value, row, col) {
629
- var plugin = app.Editor.Hot.plugin,
630
- cellId = plugin.utils.translateCellCoords({row: row, col: col}),
631
- formula = value.substr(1).toUpperCase(),
632
- newValue = plugin.parse(formula, {row: row, col: col, id: cellId});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
633
 
634
- // check if update needed
635
- var needUpdate = (newValue.error === '#NEED_UPDATE');
 
 
 
 
 
 
 
 
 
 
 
 
 
636
 
637
- if (newValue.error && formula.indexOf('IFERROR') > -1) {
638
- var matches = formula.match(/\((\(*.*\)*),(\(*.*\)*)\)$/);
 
 
 
 
 
 
 
 
639
 
640
- if (matches) {
641
- var secondParse = plugin.parse(matches[2], {row: row, col: col, id: cellId});
642
 
643
- if (!secondParse.error) {
644
- newValue.error = null;
645
- newValue.result = secondParse.result;
646
  }
647
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
648
  }
649
- // update item value and error
650
- plugin.matrix.updateItem(
651
- plugin.matrix.addItem({ id: cellId, formula: formula }),
652
- { value: newValue.result, error: newValue.error, needUpdate: needUpdate }
653
- );
654
- // update cell value in hot
655
- return newValue.error ? newValue.error : newValue.result;
656
  };
657
 
658
  TablesModel.prototype.setCellFormat = function(value, formatType) {
659
- if(value && this.isNumber(value) && !isNaN(value)) {
660
  var languageData = numeral.languageData(),
661
  format = jQuery('input[name="' + formatType + 'Format"]').val(),
662
  delimiters,
@@ -789,4 +902,4 @@ var g_stbPreviewTimeoutSet = false;
789
  app.Models.Tables.step = data.settings.table_step;
790
  }
791
  });
792
- }(window.jQuery, window.supsystic.Tables));
1
  var g_stbDoSaving = false;
2
+ var g_stbDoPreview = false;
3
  var g_stbPreviewTimeoutSet = false;
4
  (function ($, app) {
5
 
76
  step = ((typeof app.Models.Tables.step != 'undefined') && parseInt(app.Models.Tables.step)) ? parseInt(app.Models.Tables.step) : 400,
77
  done = true,
78
  ajaxPromise = new $.Deferred().resolve(),
79
+ rowsChunks = app._getChunksArray(rows, step),
80
  rowsData = [];
81
 
82
  for(var i = 0; i < rowsChunks.length; i++) {
83
  rowsData.push({
84
  id: id,
85
  step: step,
86
+ last: i == (rowsChunks.length - 1) ? 1 : 0,
87
  rows: this._prepareData(rowsChunks[i]) })
88
  }
89
 
90
  $.each(rowsData, function (index, data) {
91
  ajaxPromise = ajaxPromise.then(function() {
92
+ data._maxIter = 3;
93
  return self.request('updateRows', data);
94
  },function() {
95
  if(done) {
144
  throw new Error('Invalid table id.');
145
  }
146
 
147
+ return this.request('saveSettings', { id: id, settings: settings.serialize() });
148
  };
149
 
150
  TablesModel.prototype.setHistorySettings = function (id, settings) {
153
  throw new Error('Invalid table id.');
154
  }
155
 
156
+ return this.request('saveHistorySettings', { id: id, settings: settings.serialize() });
157
  }
158
  };
159
 
166
  editor = self.getEditor(),
167
  rows = rowsResponse[0].rows,
168
  meta = metaResponse[0].meta,
169
+ comments = [],
170
+ toolbar = app.Editor.Tb,
171
+ svlFormatsClass = toolbar.getSvlFormatClass(),
172
+ formatClasses = toolbar.getFormatClasses();
173
 
174
  // Set merged cells
175
  if (typeof meta === 'object' && 'mergedCells' in meta && meta.mergedCells.length) {
184
  cellsMeta = [],
185
  heights = [],
186
  widths = [],
187
+ $style = app.getAdminCellStylesElem();
188
 
189
  $.each(rows, function (x, row) {
190
  var cells = [];
195
  var metaData = {};
196
 
197
  if ('meta' in cell && cell.meta !== undefined) {
198
+ var classes = app.getClassesRegexp(),
199
  color = classes.color.exec(cell.meta),
200
  background = classes.background.exec(cell.meta),
201
  fontFamily = classes.fontFamily.exec(cell.meta),
221
  var lineHeight = +fontSize[1] + 6;
222
  $style.html($style.html() + ' .'+fontSize[0]+' {font-size:'+fontSize[1]+'px !important; line-height:'+lineHeight+'px !important;}');
223
  }
224
+
225
+ var cellClasses = cell.meta,
226
+ curClasses = [],
227
+ dataFormat = [];
228
+
229
+ for (var i = 0; i <= cellClasses.length; i++) {
230
+ if (cellClasses[i] in formatClasses) {
231
+ dataFormat.push(cellClasses[i]);
232
+ } else {
233
+ curClasses.push(cellClasses[i]);
234
+ }
235
+ }
236
+ if (dataFormat.length > 0) {
237
+ if (dataFormat.length == 1) {
238
+ curClasses.push(dataFormat[0]);
239
+ dataFormat = '';
240
+ } else {
241
+ curClasses.push(svlFormatsClass);
242
+ }
243
+ }
244
+ metaData = $.extend(metaData, { row: x, col: y, className: curClasses.join(' '), 'data-formats': dataFormat.length > 0 ? dataFormat.join(' ') : ''});
245
  }
246
  if (cell.formatType) {
247
  metaData = $.extend(metaData, {
250
  formatType: cell.type == 'numeric' ? '' : cell.formatType
251
  });
252
  } else {
253
+ if(app.isNumber(cell.data)) {
254
  metaData = $.extend(metaData, {
255
  type: 'text',
256
  format: '',
265
  metaData.baseType = cell.baseType;
266
  }
267
  switch(cell.formatType) {
 
 
 
 
 
 
268
  case 'date':
269
  //one table can contain multiple date formats
270
  metaData.format = cell.format;
352
  // Load extracted metadata
353
  $.each(cellsMeta, function (i, meta) {
354
  editor.setCellMetaObject(meta.row, meta.col, meta);
355
+ toolbar.setTooltip(meta.row, meta.col);
356
  });
357
  }
358
  };
365
  preview = typeof(preview) != 'undefined' ? preview : false;
366
  var self = this,
367
  editor = self.getEditor(),
368
+ id = app.getParameterByName('id'),
369
+ toolbar = app.Editor.Tb,
370
+ svlFormatsClass = toolbar.getSvlFormatClass(),
371
+ formatClasses = toolbar.getFormatClasses();
372
 
373
  if(!g_stbDoSaving) {
374
  g_stbDoSaving = true;
399
 
400
  $.each(row, function (y, cell) {
401
  var meta = editor.getCellMeta(x, y),
402
+ metaClasses = meta.className;
403
+
404
+ if (metaClasses.indexOf(svlFormatsClass) !== -1) {
405
+ metaClasses = metaClasses.replace(svlFormatsClass, '').trim();
406
+ var dataFormats = ('data-formats' in meta ? meta['data-formats'] : '');
407
+ if (dataFormats.length > 0) {
408
+ for (var c in formatClasses) {
409
+ if (dataFormats.indexOf(c) !== -1) {
410
+ metaClasses += ' ' + c;
411
+ }
412
+ }
413
+ }
414
+ }
415
+ var cellHtml = $(editor.getCell(x, y)),
416
  classes = [],
417
+ cellData = {
418
  data: cell,
419
  calculatedValue: null,
420
  hidden: false,
421
+ hiddenCell: metaClasses && metaClasses.match('hiddenCell') !== null,
422
+ invisibleCell: metaClasses && metaClasses.match('invisibleCell') !== null
423
  },
424
  mergeCell = editor.mergeCells.mergedCellInfoCollection.getInfo(x, y);
425
 
426
  // set merged params
427
  if(mergeCell !== undefined) {
428
+ cellData.hidden = true;
 
429
  }
430
  // set formatted value
431
  cellHtml = cellHtml.clone();
432
  cellHtml.find('.htAutocompleteArrow').remove();
433
+ cellData.formattedValue = cellHtml.text();
434
 
435
  // selectable cell data source
436
  if(meta.source && meta.source.length) {
437
  meta.type = 'dropdown';
438
+ cellData.source = meta.source;
439
  }
440
 
441
  // Set cell format
442
+ cellData.type = meta.type ? meta.type : 'text';
443
+ cellData.baseType = meta.baseType ? meta.baseType : 'text';
444
+ cellData.formatType = meta.formatType ? meta.formatType : '';
445
 
446
+ switch(cellData.formatType) {
447
  case 'currency':
448
+ cellData.format = formData.find('[name="currencyFormat"]').val();
449
  break;
450
  case 'percent':
451
+ cellData.format = formData.find('[name="percentFormat"]').val();
452
  break;
453
  case 'date':
454
  //one table can contain multiple date formats
455
+ cellData.format = meta.format != 'undefined'
456
  ? meta.format
457
  : formData.find('[name="dateFormat"]').val();
458
 
459
+ var date = moment(cellData.data, cellData.format);
460
 
461
  if (date.isValid()) {
462
+ cellData.dateOrder = date.format('x');
463
  }
464
  break;
465
  default:
466
+ cellData.format = meta.format;
467
  break;
468
  }
469
 
483
  }
484
  }
485
  }
486
+ cellData.calculatedValue = value;
487
  }
488
  }
489
 
490
  // Set classes for cell
491
+ if (metaClasses !== undefined) {
492
+ $.each(metaClasses.split(' '), function (index, element) {
493
  if (element.length) {
494
  classes.push($.trim(element));
495
  }
496
  });
497
  }
498
+ cellData.meta = classes;
499
 
500
  // Set comments for cell
501
  if (typeof(meta.comment) != 'undefined') {
502
+ cellData.comment = meta.comment;
503
  }
504
 
505
  // Set column width by cells of first table row
507
  columnsWidth.push(editor.getColWidth(y));
508
  }
509
 
510
+ currentRow.cells.push(cellData);
511
  });
512
 
513
  // Row height
515
 
516
  rowsData.push(currentRow);
517
  });
518
+ if(editor.mergeCells.mergedCellInfoCollection.length) {
519
+ for(var i = 0; i < editor.mergeCells.mergedCellInfoCollection.length; i++) {
520
+ mergeData.push(editor.mergeCells.mergedCellInfoCollection[i]);
521
+ }
522
+ }
523
  metaData = {
524
  mergedCells: mergeData,
525
  columnsWidth: columnsWidth,
530
  };
531
 
532
  // Request to save settings, meta and rows
533
+ var ajaxPromise = new $.Deferred().resolve();
534
+
535
+ ajaxPromise = ajaxPromise.then(
 
 
536
  function() {
537
+ return self.setSettings(id, formData);
538
+ }
539
+ );
540
+ ajaxPromise = ajaxPromise.then(
541
+ function() {
542
+ return self.setHistorySettings(id, $('form#history-settings'));
543
+ }
544
+ );
545
+ ajaxPromise = ajaxPromise.then(
546
+ function() {
547
+ return self.setMeta(id, metaData);
548
+ }
549
+ );
550
+ ajaxPromise = ajaxPromise.then(
551
+ function() {
552
+ return self.setRows(id, rowsData, byPart, preview);
553
  }
554
  );
555
  } else {
567
  setTimeout(function() {
568
  self.getPreview(id, preview);
569
  }, 50);
 
570
  } else {
571
  g_stbPreviewTimeoutSet = false;
572
+ g_stbDoPreview = true;
573
  var container = preview instanceof $ ? preview : $(preview),
574
  table;
575
 
581
  table = container.find('table');
582
  app.initializeTable(table, app.showTable, function(table) {
583
  self._afterTablePreview(table);
584
+ g_stbDoPreview = false;
585
  });
586
  });
587
  }
658
  return this.request('remove', { id: id });
659
  };
660
 
 
 
 
 
 
 
 
 
 
 
661
  TablesModel.prototype.isFormula = function (value) {
662
  if (value) {
663
  if (value[0] === '=') {
668
  };
669
 
670
  TablesModel.prototype.getFormulaResult = function (value, row, col) {
671
+ var instance = app.Editor.Hot;
672
+
673
+ if (instance.formulasEnabled && this.isFormula(value)) {
674
+ // translate coordinates into cellId
675
+ var cellId = instance.plugin.utils.translateCellCoords({row: row, col: col}),
676
+ prevFormula = null,
677
+ formula = null,
678
+ needUpdate = false,
679
+ error, result;
680
+
681
+ if (!cellId) {
682
+ return;
683
+ }
684
+
685
+ // get cell data
686
+ var item = instance.plugin.matrix.getItem(cellId);
687
+
688
+ if (item) {
689
+ needUpdate = !!item.needUpdate;
690
+
691
+ if (item.error) {
692
+ prevFormula = item.formula;
693
+ error = item.error;
694
+
695
+ if (needUpdate) {
696
+ error = null;
697
+ }
698
+ }
699
+ }
700
+
701
+ // check if typed formula or cell value should be recalculated
702
+ if ((value && value[0] === '=') || needUpdate) {
703
+ formula = value.substr(1);
704
+
705
+ if (!error || formula !== prevFormula) {
706
+ var currentItem = item;
707
 
708
+ if (!currentItem) {
709
+ // define item to rulesJS matrix if not exists
710
+ item = { id: cellId, formula: formula };
711
+ // add item to matrix
712
+ currentItem = instance.plugin.matrix.addItem(item);
713
+ }
714
+
715
+ // parse formula
716
+ var newValue = instance.plugin.parse(formula, {row: row, col: col, id: cellId});
717
+
718
+ if (newValue.error && formula.indexOf('IFERROR') > -1) {
719
+ var matches = formula.match(/\((\(*.*\)*),(\(*.*\)*)\)$/);
720
+
721
+ if (matches) {
722
+ var secondParse = instance.plugin.parse(matches[2], {row: row, col: col, id: cellId});
723
 
724
+ if (!secondParse.error) {
725
+ newValue.error = null;
726
+ newValue.result = secondParse.result;
727
+ }
728
+ }
729
+ }
730
+ // check if update needed
731
+ needUpdate = (newValue.error === '#NEED_UPDATE');
732
+ // update item value and error
733
+ instance.plugin.matrix.updateItem(currentItem, { value: newValue.result, error: newValue.error, needUpdate: needUpdate});
734
 
735
+ error = newValue.error;
736
+ result = newValue.result;
737
 
738
+ // update cell value in hot
739
+ value = error || result;
 
740
  }
741
  }
742
+ if (error) {
743
+ // clear cell value
744
+ if (!value) {
745
+ // reset error
746
+ error = null;
747
+ } else {
748
+ // show error
749
+ value = error;
750
+ }
751
+ if (error == '#VALUE!') {
752
+ value = 0;
753
+ }
754
+ }
755
+ // Round float
756
+ /*if (value !== '0' && value !== 0 && value % 1 !== 0) {
757
+ // round float
758
+ var floatValue = parseFloat(value);
759
+ if (floatValue.toString().indexOf('.') !== -1) {
760
+ var afterPointSybolsLength = floatValue.toString().split('.')[1].length;
761
+ if (afterPointSybolsLength > 4) {
762
+ value = floatValue.toFixed(4);
763
+ }
764
+ }
765
+ }*/
766
  }
767
+
768
+ return value;
 
 
 
 
 
769
  };
770
 
771
  TablesModel.prototype.setCellFormat = function(value, formatType) {
772
+ if(value && app.isNumber(value) && !isNaN(value)) {
773
  var languageData = numeral.languageData(),
774
  format = jQuery('input[name="' + formatType + 'Format"]').val(),
775
  delimiters,
902
  app.Models.Tables.step = data.settings.table_step;
903
  }
904
  });
905
+ }(window.jQuery, window.supsystic.Tables));
src/SupsysticTables/Tables/assets/libraries/ruleJS/handsontable.formula.js CHANGED
@@ -137,6 +137,7 @@
137
  } else {
138
  textCell.renderer.apply(this, [instance, TD, row, col, prop, value, cellProperties]);
139
  }
 
140
  };
141
  function incrementString(string){
142
  var number = parseInt(string);
@@ -553,7 +554,7 @@
553
  };
554
 
555
  var textCell = {
556
- renderer: Handsontable.renderers.TextRenderer,
557
  editor: Handsontable.editors.TextEditor
558
  };
559
 
137
  } else {
138
  textCell.renderer.apply(this, [instance, TD, row, col, prop, value, cellProperties]);
139
  }
140
+ return value;
141
  };
142
  function incrementString(string){
143
  var number = parseInt(string);
554
  };
555
 
556
  var textCell = {
557
+ renderer: Handsontable.renderers.HtmlRenderer,
558
  editor: Handsontable.editors.TextEditor
559
  };
560
 
src/SupsysticTables/Tables/assets/libraries/ruleJS/ruleJS.js CHANGED
@@ -1425,7 +1425,7 @@ var ruleJS = (function (root) {
1425
  $table = $table instanceof jQuery ? $table : jQuery($table);
1426
  $table.find('.unescapeHTML').each(function() {
1427
  var cell = jQuery(this),
1428
- cellContent = cell.html().replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"');
1429
 
1430
  cell.html(cellContent);
1431
  });
@@ -1439,7 +1439,8 @@ var ruleJS = (function (root) {
1439
  * @param element
1440
  */
1441
  var parse = function (formula, element) {
1442
- window.supsystic.Tables._currentFormula = formula; // to calculate custom supsystic formulas
 
1443
  window.supsystic.Tables._dateFormat = '';
1444
  window.supsystic.Tables._timeFormat = '';
1445
 
1425
  $table = $table instanceof jQuery ? $table : jQuery($table);
1426
  $table.find('.unescapeHTML').each(function() {
1427
  var cell = jQuery(this),
1428
+ cellContent = cell.html().replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&amp;/g, '&');
1429
 
1430
  cell.html(cellContent);
1431
  });
1439
  * @param element
1440
  */
1441
  var parse = function (formula, element) {
1442
+ formula = window.supsystic.Tables.prepareFormulaToParse(formula); // fix of case sensitive for cells' indexes and formulas' names
1443
+ window.supsystic.Tables._currentFormula = formula; // to calculate custom supsystic formulas
1444
  window.supsystic.Tables._dateFormat = '';
1445
  window.supsystic.Tables._timeFormat = '';
1446
 
src/SupsysticTables/Tables/assets/libraries/ruleJS/ruleJS.lib.full.js CHANGED
@@ -20018,6 +20018,7 @@ this.j$ = this.jStat = (function(Math, undefined) {
20018
 
20019
  Formula.MAX = function () {
20020
  var range = Formula.FLATTEN(arguments);
 
20021
  var n = range.length;
20022
  var max = (n > 0) ? range[0] : 0;
20023
  for (var i = 0; i < n; i++) {
@@ -20037,6 +20038,7 @@ this.j$ = this.jStat = (function(Math, undefined) {
20037
 
20038
  Formula.MIN = function () {
20039
  var range = Formula.FLATTEN(arguments);
 
20040
  var n = range.length;
20041
  var min = (n > 0) ? range[0] : 0;
20042
  for (var i = 0; i < n; i++) {
@@ -20813,15 +20815,18 @@ this.j$ = this.jStat = (function(Math, undefined) {
20813
 
20814
  // Custom supsystic formulas
20815
  Formula.INDEX = function(arrayValues, rowNum, colNum) {
20816
- rowNum = typeof rowNum != 'undefined' && rowNum > 0 ? rowNum : 1;
20817
- colNum = typeof colNum != 'undefined' && colNum > 0 ? colNum : 1;
20818
-
20819
  if ((rowNum < 0) || (colNum < 0)) {
20820
  return '#VALUE!';
20821
  }
20822
  if (!arrayValues) {
20823
  return '#REF!';
20824
  }
 
 
 
 
 
 
20825
  arrayValues = Formula.FLATTEN(arrayValues);
20826
 
20827
  var chunkArr = Formula._CHUNK(arrayValues); // it is transposed array - array of arrays of columns values, not rows
@@ -20829,7 +20834,15 @@ this.j$ = this.jStat = (function(Math, undefined) {
20829
  if(chunkArr && !Formula.ISERROR(chunkArr)) {
20830
  var chunkArrColsCount = chunkArr.length,
20831
  chunkArrRowsCount = typeof chunkArr[0] != 'undefined' ? chunkArr[0].length : 0;
20832
- if (rowNum > chunkArrRowsCount || colNum > chunkArrColsCount) {
 
 
 
 
 
 
 
 
20833
  return '#NUM!';
20834
  }
20835
  return chunkArr[colNum - 1][rowNum - 1];
20018
 
20019
  Formula.MAX = function () {
20020
  var range = Formula.FLATTEN(arguments);
20021
+ range = range.filter(function(x){ return !isNaN(parseFloat(x)); });
20022
  var n = range.length;
20023
  var max = (n > 0) ? range[0] : 0;
20024
  for (var i = 0; i < n; i++) {
20038
 
20039
  Formula.MIN = function () {
20040
  var range = Formula.FLATTEN(arguments);
20041
+ range = range.filter(function(x){ return !isNaN(parseFloat(x)); });
20042
  var n = range.length;
20043
  var min = (n > 0) ? range[0] : 0;
20044
  for (var i = 0; i < n; i++) {
20815
 
20816
  // Custom supsystic formulas
20817
  Formula.INDEX = function(arrayValues, rowNum, colNum) {
 
 
 
20818
  if ((rowNum < 0) || (colNum < 0)) {
20819
  return '#VALUE!';
20820
  }
20821
  if (!arrayValues) {
20822
  return '#REF!';
20823
  }
20824
+ /*if(typeof colNum == 'undefined' && typeof rowNum != 'undefined') {
20825
+ colNum = rowNum;
20826
+ rowNum = 1;
20827
+ }*/
20828
+ rowNum = typeof rowNum != 'undefined' && rowNum > 0 ? rowNum : 1;
20829
+ colNum = typeof colNum != 'undefined' && colNum > 0 ? colNum : 1;
20830
  arrayValues = Formula.FLATTEN(arrayValues);
20831
 
20832
  var chunkArr = Formula._CHUNK(arrayValues); // it is transposed array - array of arrays of columns values, not rows
20834
  if(chunkArr && !Formula.ISERROR(chunkArr)) {
20835
  var chunkArrColsCount = chunkArr.length,
20836
  chunkArrRowsCount = typeof chunkArr[0] != 'undefined' ? chunkArr[0].length : 0;
20837
+ if (rowNum > chunkArrRowsCount) {
20838
+ if(chunkArrRowsCount == 1) {
20839
+ colNum = rowNum;
20840
+ rowNum = chunkArrRowsCount;
20841
+ } else {
20842
+ return '#NUM!';
20843
+ }
20844
+ }
20845
+ if (colNum > chunkArrColsCount) {
20846
  return '#NUM!';
20847
  }
20848
  return chunkArr[colNum - 1][rowNum - 1];
src/SupsysticTables/Tables/views/shortcode.twig CHANGED
@@ -1,26 +1,13 @@
1
  {% macro cell(cell, rowIndex, cellIndex, tag, context) %}
2
- {% set data = cell.data %}
3
-
4
- {% if context.table.settings.styling.paragraphMode %}
5
- {% set data = data | raw | nl2br %}
6
- {% endif %}
7
-
8
- {% if cell.hidden == true %}
9
- {% set display = false %}
10
- {% set colspan = 1 %}
11
- {% set rowspan = 1 %}
12
- {% for mergedCell in context.table.meta.mergedCells %}
13
- {% if mergedCell.row == rowIndex - 1 and mergedCell.col == cellIndex %}
14
- {% set display = true %}
15
- {% set colspan = mergedCell.colspan %}
16
- {% set rowspan = mergedCell.rowspan %}
17
- {% endif %}
18
- {% endfor %}
19
- {% endif %}
20
-
21
  {% set searchByHidden = context.table.settings.searching.searchByHiddenField %}
22
 
23
  {% if cell.hiddenCell != true or cell.hiddenCell == true and searchByHidden == 'on' %}
 
 
 
 
 
 
24
  <{{tag}}
25
  data-cell-id="{{ context.cols[context.countIter] ~ context.cols[context.cellIter] ~ rowIndex }}"
26
  data-x="{{ cellIndex }}"
@@ -48,7 +35,7 @@
48
  {% endif %}
49
 
50
  {% if cell.data[:1] == '=' %}
51
- data-formula="{{ cell.data | slice(1) | upper }}"
52
  {% set data = cell.calculatedValue %}
53
  {% elseif cell.data[:2] == '`=' %}
54
  {% set data = cell.data | slice(1) %}
@@ -85,12 +72,23 @@
85
  {% endif %}
86
 
87
  {# cell.hidden is true if this cell was merged with another cell #}
88
- {% if cell.hidden == 1 %}
 
 
 
 
 
 
 
 
 
 
89
  {% if display == false %}
90
  data-hide="true"
 
 
 
91
  {% endif %}
92
- data-colspan="{{ colspan }}"
93
- data-rowspan="{{ rowspan }}"
94
  {% endif %}
95
  >{{ data | raw }}</{{tag}}>
96
  {% endif %}
@@ -317,16 +315,20 @@
317
  {% for row in bodyRows %}
318
  {% set rowNumber = loop.index + (head ? headRowsCount : 0) %}
319
  {% set existBodyRow = false %}
 
320
 
321
  {% for cellIndex, cell in row.cells %}
322
  {% if cell.hiddenCell == false %}
323
  {% set existBodyRow = true %}
324
  {% endif %}
 
 
 
325
  {% endfor %}
326
 
327
  {% if existBodyRow == true %}
328
  <tr
329
- {% if row.height != 'NaN' and row.height matches '/^[0-9]*\\.?[0-9]+$/' %}
330
  style="height: {{ row.height }}px"
331
  {% endif %}
332
  >
1
  {% macro cell(cell, rowIndex, cellIndex, tag, context) %}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  {% set searchByHidden = context.table.settings.searching.searchByHiddenField %}
3
 
4
  {% if cell.hiddenCell != true or cell.hiddenCell == true and searchByHidden == 'on' %}
5
+ {% set data = cell.data %}
6
+
7
+ {% if context.table.settings.styling.paragraphMode %}
8
+ {% set data = data | raw | nl2br %}
9
+ {% endif %}
10
+
11
  <{{tag}}
12
  data-cell-id="{{ context.cols[context.countIter] ~ context.cols[context.cellIter] ~ rowIndex }}"
13
  data-x="{{ cellIndex }}"
35
  {% endif %}
36
 
37
  {% if cell.data[:1] == '=' %}
38
+ data-formula="{{ cell.data | slice(1) }}"
39
  {% set data = cell.calculatedValue %}
40
  {% elseif cell.data[:2] == '`=' %}
41
  {% set data = cell.data | slice(1) %}
72
  {% endif %}
73
 
74
  {# cell.hidden is true if this cell was merged with another cell #}
75
+ {% if cell.hidden == true %}
76
+ {% set display = false %}
77
+ {% set colspan = 1 %}
78
+ {% set rowspan = 1 %}
79
+ {% for mergedCell in context.table.meta.mergedCells %}
80
+ {% if mergedCell.row == rowIndex - 1 and mergedCell.col == cellIndex %}
81
+ {% set display = true %}
82
+ {% set colspan = mergedCell.colspan %}
83
+ {% set rowspan = mergedCell.rowspan %}
84
+ {% endif %}
85
+ {% endfor %}
86
  {% if display == false %}
87
  data-hide="true"
88
+ {% else %}
89
+ data-colspan="{{ colspan }}"
90
+ data-rowspan="{{ rowspan }}"
91
  {% endif %}
 
 
92
  {% endif %}
93
  >{{ data | raw }}</{{tag}}>
94
  {% endif %}
315
  {% for row in bodyRows %}
316
  {% set rowNumber = loop.index + (head ? headRowsCount : 0) %}
317
  {% set existBodyRow = false %}
318
+ {% set rowHeightExists = false %}
319
 
320
  {% for cellIndex, cell in row.cells %}
321
  {% if cell.hiddenCell == false %}
322
  {% set existBodyRow = true %}
323
  {% endif %}
324
+ {% if cell.meta is iterable and 'invisibleCell' not in cell.meta %}
325
+ {% set rowHeightExists = true %}
326
+ {% endif %}
327
  {% endfor %}
328
 
329
  {% if existBodyRow == true %}
330
  <tr
331
+ {% if rowHeightExists == true and row.height != 'NaN' and row.height matches '/^[0-9]*\\.?[0-9]+$/' %}
332
  style="height: {{ row.height }}px"
333
  {% endif %}
334
  >
src/SupsysticTables/Tables/views/view.twig CHANGED
@@ -454,6 +454,20 @@
454
  </div>
455
  </div>
456
  <div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
457
  <div class="title-place">
458
  <h3>{{ environment.translate('Data Formats') }}</h3>
459
  </div>
@@ -869,15 +883,8 @@
869
  <div class="setting-item col-md-6 col-sm-6 col-xs-12">
870
  <label for="save-editable-fields-unavailable">
871
  {{ environment.translate('Save Frontend Fields') }}
872
- {{ tooltip.icon(environment.translate('Allows to save data to the table through the frontend fields. See the next buttons on the editor toolbar:<br />
873
- Add editable field<br />
874
- Add dropdown list')) }}
875
- <br>
876
- <span>
877
- <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'editable_fields_feature' }) }}">
878
- {{ environment.translate('PRO option') }}
879
- </a>
880
- </span>
881
  </label>
882
  </div>
883
  <div class="setting-item col-md-6 col-sm-6 col-xs-12">
@@ -887,16 +894,9 @@
887
  <div class="setting-wrapper row">
888
  <div class="setting-item col-md-6 col-sm-6 col-xs-12">
889
  <label for="editable-fields-logged-in-unavailable">
890
- {{ environment.translate('Use Frontend Fields for Logged In Users Only') }}
891
- {{ tooltip.icon(environment.translate('Allows to <a href="%s" target="_blank">use frontend fields only for logged in users</a>. See the next buttons on the editor toolbar:<br />
892
- Add editable field<br />
893
- Add dropdown list') | format('//supsystic.com/documentation/editable-fields-logged-users/')) }}
894
- <br>
895
- <span>
896
- <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'editable_fields_for_logged_in_only' }) }}">
897
- {{ environment.translate('PRO option') }}
898
- </a>
899
- </span>
900
  </label>
901
  </div>
902
  <div class="setting-item col-md-6 col-sm-6 col-xs-12">
@@ -906,14 +906,9 @@
906
  <div class="setting-wrapper row editable-fields-logged-in-options">
907
  <div class="setting-item col-md-6 col-sm-6 col-xs-12">
908
  <label for="editable-fields-roles-unavailable">
909
- {{ environment.translate('Use Editable Fields for Current Roles') }}
910
- {{ tooltip.icon(environment.translate('Allows to use editable fields only for users with selected roles. If there are no chosen roles - all logged in users will have ability to use the editable fields.')) }}
911
- <br>
912
- <span>
913
- <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'editable_fields_for_current_roles' }) }}">
914
- {{ environment.translate('PRO option') }}
915
- </a>
916
- </span>
917
  </label>
918
  </div>
919
  <div class="setting-item col-md-6 col-sm-6 col-xs-12">
@@ -924,26 +919,87 @@
924
  </div>
925
  {% endif %}
926
  {% if environment.isPro() == false %}
927
- <div class="title-place">
928
- <h3>{{ environment.translate('Export / Import') }}</h3>
929
- </div>
930
- <div class="setting-wrapper row">
931
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
932
- <label for="features-export-unavailable">
933
- {{ environment.translate('Frontend Export') }}
934
- {{ tooltip.icon(environment.translate('Allows to export table in pdf, csv, xls formats from the front-end. Choose needed formats')) }}
935
- <br>
936
- <span>
937
- <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'export_feature' }) }}">
938
- {{ environment.translate('PRO option') }}
939
- </a>
940
- </span>
941
- </label>
942
  </div>
943
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
944
- <input type="checkbox" disabled="disabled" id="features-export-unavailable"/>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
945
  </div>
946
- </div>
947
  {% endif %}
948
  {{ environment.getDispatcher().dispatch('tables-view-features', [table]) }}
949
  <!-- /.form-table -->
454
  </div>
455
  </div>
456
  <div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
457
+ <div class="title-place">
458
+ <h3>{{ environment.translate('Options') }}</h3>
459
+ </div>
460
+ <div class="setting-wrapper row">
461
+ <div class="setting-item col-md-6 col-sm-6 col-xs-12">
462
+ <label for="disable-table-cache">
463
+ {{ environment.translate('Disable Table Cache') }}
464
+ {{ tooltip.icon(environment.translate('Disable the internal plugin cache for table. Internal cache can affect to work of shortcodes inside the table content, for example, if shortcodes is depending on loading some scripts, etc.')) }}
465
+ </label>
466
+ </div>
467
+ <div class="setting-item col-md-6 col-sm-6 col-xs-12">
468
+ <input type="checkbox" name="disableCache" id="disable-table-cache" {{ checkbox.checked(table.settings.disableCache) }} />
469
+ </div>
470
+ </div>
471
  <div class="title-place">
472
  <h3>{{ environment.translate('Data Formats') }}</h3>
473
  </div>
883
  <div class="setting-item col-md-6 col-sm-6 col-xs-12">
884
  <label for="save-editable-fields-unavailable">
885
  {{ environment.translate('Save Frontend Fields') }}
886
+ {{ tooltip.icon(environment.translate('Allows to save data to the table through the frontend fields. See the next buttons on the editor toolbar:<br />Add editable field<br />Add dropdown list')) }}
887
+ <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'editable_fields_feature' }) }}">{{ environment.translate('PRO option') }}</a>
 
 
 
 
 
 
 
888
  </label>
889
  </div>
890
  <div class="setting-item col-md-6 col-sm-6 col-xs-12">
894
  <div class="setting-wrapper row">
895
  <div class="setting-item col-md-6 col-sm-6 col-xs-12">
896
  <label for="editable-fields-logged-in-unavailable">
897
+ {{ environment.translate('Use for Logged In Users Only') }}
898
+ {{ tooltip.icon(environment.translate('Allows to <a href="%s" target="_blank">use frontend fields only for logged in users</a>. See the next buttons on the editor toolbar:<br />Add editable field<br />Add dropdown list') | format('//supsystic.com/documentation/editable-fields-logged-users/')) }}
899
+ <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'editable_fields_for_logged_in_only' }) }}">{{ environment.translate('PRO option') }}</a>
 
 
 
 
 
 
 
900
  </label>
901
  </div>
902
  <div class="setting-item col-md-6 col-sm-6 col-xs-12">
906
  <div class="setting-wrapper row editable-fields-logged-in-options">
907
  <div class="setting-item col-md-6 col-sm-6 col-xs-12">
908
  <label for="editable-fields-roles-unavailable">
909
+ {{ environment.translate('Use for Current Roles Only') }}
910
+ {{ tooltip.icon(environment.translate('Allows to use frontend fields only for users with selected roles. If there are no chosen roles - all logged in users will have ability to use the frontend fields.')) }}
911
+ <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'editable_fields_for_current_roles' }) }}">{{ environment.translate('PRO option') }}</a>
 
 
 
 
 
912
  </label>
913
  </div>
914
  <div class="setting-item col-md-6 col-sm-6 col-xs-12">
919
  </div>
920
  {% endif %}
921
  {% if environment.isPro() == false %}
922
+ <div class="title-place">
923
+ <h3>{{ environment.translate('Export / Import') }}</h3>
 
 
 
 
 
 
 
 
 
 
 
 
 
924
  </div>
925
+ <div class="setting-wrapper row">
926
+ <div class="setting-item col-md-6 col-sm-6 col-xs-12">
927
+ <label for="features-export-unavailable">
928
+ {{ environment.translate('Frontend Export') }}
929
+ {{ tooltip.icon(environment.translate('Allows to export table in pdf, csv, xls formats from the front-end. Choose needed formats')) }}
930
+ <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'export_feature' }) }}">{{ environment.translate('PRO option') }}</a>
931
+ </label>
932
+ </div>
933
+ <div class="setting-item col-md-6 col-sm-6 col-xs-12">
934
+ <select name="features[export][]" disabled="disabled" id="features-export-unavailable" data-placeholder="{{ environment.translate('Select Some Options')}}">
935
+ <option>{{ environment.translate('Select Some Options')}}</option>
936
+ </select>
937
+ </div>
938
+ </div>
939
+ <div class="setting-wrapper row">
940
+ <div class="setting-item col-md-6 col-sm-6 col-xs-12">
941
+ <label for="features-export-pdf-paper-size-unavailable">
942
+ {{ environment.translate('PDF Paper Size') }}
943
+ {{ tooltip.icon(environment.translate('Choose the paper size for PDF pages')) }}
944
+ </label>
945
+ <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'export_feature_pdf_paper_size' }) }}">{{ environment.translate('PRO option') }}</a>
946
+ </div>
947
+ <div class="setting-item col-md-6 col-sm-6 col-xs-12">
948
+ <select name="pdfPaperSize" disabled="disabled" id="features-export-pdf-paper-size-unavailable" data-placeholder="{{ environment.translate('Automatic')}}">
949
+ <option>{{ environment.translate('Automatic')}}</option>
950
+ </select>
951
+ </div>
952
+ </div>
953
+ <div class="setting-wrapper row">
954
+ <div class="setting-item col-md-6 col-sm-6 col-xs-12">
955
+ <label for="features-export-pdf-orientation-unavailable">
956
+ {{ environment.translate('PDF Page Orientation') }}
957
+ {{ tooltip.icon(environment.translate('Choose the orientation for PDF pages')) }}
958
+ </label>
959
+ <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'export_feature_pdf_orientation' }) }}">{{ environment.translate('PRO option') }}</a>
960
+ </div>
961
+ <div class="setting-item col-md-6 col-sm-6 col-xs-12">
962
+ <select name="pdfOrientation" disabled="disabled" id="features-export-pdf-orientation-unavailable" data-placeholder="{{ environment.translate('Portrait')}}">
963
+ <option>{{ environment.translate('Portrait')}}</option>
964
+ </select>
965
+ </div>
966
+ </div>
967
+ <div class="setting-wrapper row">
968
+ <div class="setting-item col-md-6 col-sm-6 col-xs-12">
969
+ <label for="features-export-pdf-use-export-font-unavailable">
970
+ {{ environment.translate('PDF Export Font') }}
971
+ {{ tooltip.icon(environment.translate('If you use some specific characters (greek, cyrillic etc.) it is better to check this box for PDF export.')) }}
972
+ </label>
973
+ <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'export_feature_pdf_use_export_font' }) }}">{{ environment.translate('PRO option') }}</a>
974
+ </div>
975
+ <div class="setting-item col-md-6 col-sm-6 col-xs-12">
976
+ <input type="checkbox" name="pdfUseExportFont" disabled="disabled" id="features-export-pdf-use-export-font-unavailable" />
977
+ </div>
978
+ </div>
979
+ <div class="setting-wrapper row">
980
+ <div class="setting-item col-md-6 col-sm-6 col-xs-12">
981
+ <label for="features-export-select-logo-unavailable">
982
+ {{ environment.translate('Export Logo') }}
983
+ {{ tooltip.icon(environment.translate('Automticaly appends selected logo for output pdf or printing')) }}
984
+ </label>
985
+ <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'export_feature_select_logo' }) }}">{{ environment.translate('PRO option') }}</a>
986
+ </div>
987
+ <div class="setting-item col-md-6 col-sm-6 col-xs-12">
988
+ <button class="button" disabled="disabled" id="features-export-select-logo-unavailable">{{ environment.translate('Select Logo') }}</button>
989
+ </div>
990
+ </div>
991
+ <div class="setting-wrapper row">
992
+ <div class="setting-item col-md-6 col-sm-6 col-xs-12">
993
+ <label for="google-tables-automatically-update-unavailable">
994
+ {{ environment.translate('Autoimport from Google Sheet') }}
995
+ {{ tooltip.icon(environment.translate('If checked - table data on frontend will be overloaded from selected Google Sheet. <a href="%s" tagget="_blank">Read more</a> about how organize Auto Import form Google Sheets') | format('//supsystic.com/documentation/synchronization-table-google-sheet/')) }}
996
+ </label>
997
+ <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'google_tables_automatically_update' }) }}">{{ environment.translate('PRO option') }}</a>
998
+ </div>
999
+ <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1000
+ <input type="checkbox" disabled="disabled" name="features[google_tables_automatically_update]" id="google-tables-automatically-update-unavailable" />
1001
+ </div>
1002
  </div>
 
1003
  {% endif %}
1004
  {{ environment.getDispatcher().dispatch('tables-view-features', [table]) }}
1005
  <!-- /.form-table -->
src/SupsysticTables/Ui/Asset.php CHANGED
@@ -49,7 +49,7 @@ abstract class SupsysticTables_Ui_Asset implements SupsysticTables_Ui_AssetInter
49
 
50
  if (defined('WP_DEBUG') && WP_DEBUG) {
51
  $this->cachingAllowed = false;
52
- $this->version = uniqid('_', false);
53
  }
54
  }
55
 
@@ -255,9 +255,9 @@ abstract class SupsysticTables_Ui_Asset implements SupsysticTables_Ui_AssetInter
255
  */
256
  public function setVersion($version)
257
  {
258
- if (!$this->cachingAllowed) {
259
  $version = uniqid($version.'_');
260
- }
261
 
262
  $this->version = (string)$version;
263
 
49
 
50
  if (defined('WP_DEBUG') && WP_DEBUG) {
51
  $this->cachingAllowed = false;
52
+ //$this->version = uniqid('_', false);
53
  }
54
  }
55
 
255
  */
256
  public function setVersion($version)
257
  {
258
+ /*if (!$this->cachingAllowed) {
259
  $version = uniqid($version.'_');
260
+ }*/
261
 
262
  $this->version = (string)$version;
263