Data Tables Generator by Supsystic - Version 1.9.77

Version Description

/ 11.06.2019 = * Small fix for Edit link on frontend

Download this release

Release Info

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

Code changes from version 1.9.71 to 1.9.77

Files changed (55) hide show
  1. app/SupsysticTables.php +1 -1
  2. app/assets/css/supsystic-ui.css +8 -88
  3. app/assets/js/notify.js +2 -1
  4. app/assets/js/supsystic.ui.js +12 -2
  5. app/templates/layout.twig +2 -0
  6. index.php +1 -1
  7. readme.txt +62 -24
  8. src/SupsysticTables/Core/BaseModule.php +1 -1
  9. src/SupsysticTables/Core/Model/Core.php +3 -0
  10. src/SupsysticTables/Core/Module.php +13 -1
  11. src/SupsysticTables/Core/assets/css/base.css +87 -1
  12. src/SupsysticTables/Core/assets/js/core.js +139 -24
  13. src/SupsysticTables/Core/assets/js/jquery.tooltipster.min.js +2 -1
  14. src/SupsysticTables/Core/assets/js/lib/dataTables.customExtensions.js +48 -0
  15. src/SupsysticTables/Core/assets/js/lib/jquery.dataTables.min.js +2 -2
  16. src/SupsysticTables/Diagram/views/partials/tabContent.twig +4 -2
  17. src/SupsysticTables/Overview/assets/css/overview.css +29 -1
  18. src/SupsysticTables/Promo/Controller.php +17 -2
  19. src/SupsysticTables/Promo/Model/Promo.php +74 -0
  20. src/SupsysticTables/Promo/Model/classes/lib/Base/MixpanelBase.php +67 -0
  21. src/SupsysticTables/Promo/Model/classes/lib/ConsumerStrategies/AbstractConsumer.php +57 -0
  22. src/SupsysticTables/Promo/Model/classes/lib/ConsumerStrategies/CurlConsumer.php +221 -0
  23. src/SupsysticTables/Promo/Model/classes/lib/ConsumerStrategies/FileConsumer.php +38 -0
  24. src/SupsysticTables/Promo/Model/classes/lib/ConsumerStrategies/SocketConsumer.php +308 -0
  25. src/SupsysticTables/Promo/Model/classes/lib/Mixpanel.php +302 -0
  26. src/SupsysticTables/Promo/Model/classes/lib/Producers/MixpanelBaseProducer.php +229 -0
  27. src/SupsysticTables/Promo/Model/classes/lib/Producers/MixpanelEvents.php +164 -0
  28. src/SupsysticTables/Promo/Model/classes/lib/Producers/MixpanelPeople.php +147 -0
  29. src/SupsysticTables/Promo/Module.php +106 -0
  30. src/SupsysticTables/Promo/assets/js/admin.plugins.js +90 -0
  31. src/SupsysticTables/Promo/views/discountMessage.twig +38 -0
  32. src/SupsysticTables/Promo/views/pluginDeactivation.twig +70 -0
  33. src/SupsysticTables/Tables/Controller.php +17 -4
  34. src/SupsysticTables/Tables/Module.php +85 -14
  35. src/SupsysticTables/Tables/assets/css/tables.shortcode.css +12 -0
  36. src/SupsysticTables/Tables/assets/css/tables.view.css +217 -19
  37. src/SupsysticTables/Tables/assets/img/database.gif +0 -0
  38. src/SupsysticTables/Tables/assets/img/history_table.gif +0 -0
  39. src/SupsysticTables/Tables/assets/js/editor/tables.editor.js +26 -3
  40. src/SupsysticTables/Tables/assets/js/editor/tables.editor.toolbar.js +1 -0
  41. src/SupsysticTables/Tables/assets/js/tables.model.js +442 -208
  42. src/SupsysticTables/Tables/assets/js/tables.view.js +297 -18
  43. src/SupsysticTables/Tables/assets/libraries/ruleJS/handsontable.formula.js +2 -1
  44. src/SupsysticTables/Tables/assets/libraries/ruleJS/ruleJS.js +47 -14
  45. src/SupsysticTables/Tables/assets/libraries/ruleJS/ruleJS.lib.full.js +1 -0
  46. src/SupsysticTables/Tables/views/partials/historyTabContent.twig +1 -1
  47. src/SupsysticTables/Tables/views/partials/sourceTab.twig +6 -0
  48. src/SupsysticTables/Tables/views/partials/sourceTabContent.twig +20 -0
  49. src/SupsysticTables/Tables/views/shortcode.twig +21 -8
  50. src/SupsysticTables/Tables/views/styles.twig +4 -1
  51. src/SupsysticTables/Tables/views/view.twig +718 -397
  52. src/SupsysticTables/Ui/views/tooltip.twig +1 -1
  53. src/SupsysticTables/Woocommerce/assets/img/wooadsfool.gif +0 -0
  54. src/SupsysticTables/Woocommerce/views/partials/tab.twig +1 -1
  55. src/SupsysticTables/Woocommerce/views/partials/tabContent.twig +1 -1
app/SupsysticTables.php CHANGED
@@ -18,7 +18,7 @@ class SupsysticTables
18
 
19
  $menuSlug = 'supsystic-tables';
20
  $pluginPath = dirname(dirname(__FILE__));
21
- $environment = new Rsc_Environment('st', '1.9.71', $pluginPath);
22
 
23
  /* Configure */
24
  $environment->configure(
18
 
19
  $menuSlug = 'supsystic-tables';
20
  $pluginPath = dirname(dirname(__FILE__));
21
+ $environment = new Rsc_Environment('st', '1.9.77', $pluginPath);
22
 
23
  /* Configure */
24
  $environment->configure(
app/assets/css/supsystic-ui.css CHANGED
@@ -73,7 +73,8 @@
73
 
74
  .supsystic-plugin .supsystic-content .supsystic-container {
75
  margin-left: 75px;
76
- /*margin-top: 10px;*/
 
77
  }
78
 
79
  .supsystic-plugin .supsystic-content .supsystic-navigation {
@@ -237,92 +238,7 @@ ul.supsystic-bar-controls > li.separator {
237
 
238
  /* jQuery UI Dialog */
239
 
240
- .ui-dialog {
241
- box-shadow: 1px 1px 10px #ccc;
242
- -webkit-box-shadow: 1px 1px 10px #ccc;
243
- -moz-box-shadow: 1px 1px 10px #ccc;
244
- -ms-box-shadow: 1px 1px 10px #ccc;
245
- -o-box-shadow: 1px 1px 10px #ccc;
246
- }
247
-
248
- .ui-dialog .ui-dialog-titlebar {
249
- line-height: 25px;
250
- }
251
 
252
- .ui-dialog .ui-dialog-titlebar-close {
253
- display: none;
254
- }
255
-
256
- .ui-dialog .ui-dialog-buttonpane {
257
- padding: 0 !important;
258
- margin-top: 10px !important;
259
- border: none !important;
260
- text-align: right !important;
261
- }
262
-
263
- .ui-dialog .ui-dialog-content {
264
- position: relative;
265
- border: 0;
266
- padding: .5em 1em;
267
- background: none;
268
- overflow: visible !important;
269
- }
270
-
271
- .ui-dialog .ui-dialog-buttonpane button {
272
- margin: 0 10px 0 0 !important;
273
- outline: 0;
274
- }
275
-
276
- .ui-button-text-only .ui-button-text {
277
- padding: 0 !important;
278
- }
279
-
280
- .ui-dialog .ui-dialog-title {
281
- float: none !important;
282
- font-size: 17px;
283
- }
284
-
285
- .ui-widget {
286
- font-family: Verdana,Arial,Helvetica,sans-serif;
287
- font-size: 1.1em;
288
- }
289
-
290
- .ui-widget-overlay {
291
- background: #000 !important;
292
- opacity: .3;
293
- -ms-filter: Alpha(opacity=30);
294
- filter: Alpha(opacity=30);
295
- position: fixed;
296
- top: 0;
297
- left: 0;
298
- width: 100%;
299
- height: 100%;
300
- }
301
-
302
- .ui-widget-overlay.ui-front {
303
- z-index: 10;
304
- }
305
-
306
- .ui-dialog.ui-widget-content {
307
- background: #fff !important;
308
- padding: 15px 5px !important;
309
- z-index: 100001;
310
- }
311
-
312
- .ui-widget-content input {
313
- width: 100%;
314
- height: auto;
315
- }
316
-
317
- .ui-widget-header {
318
- border: none !important;
319
- border-bottom: 1px solid #ddd !important;
320
- background: none !important;
321
- color: #777 !important;
322
- border-radius: 0 !important;
323
- padding: 0 10px 15px 10px !important;
324
- font-weight: normal !important;
325
- }
326
 
327
  .ui-dialog-titlebar-close {
328
  background: none !important;
@@ -526,8 +442,8 @@ h3.nav-tab-wrapper {
526
  .supsystic-plugin .button,
527
  .supsystic-plugin .paginate_button,
528
  .supsystic-plugin .button-primary,
529
- .ui-button,
530
- .ui-button.ui-state-default {
531
  font-size: 15px !important;
532
  height: 35px !important;
533
  -webkit-border-radius: 0 !important;
@@ -604,6 +520,10 @@ h3.nav-tab-wrapper {
604
  line-height: 20px !important;
605
  }
606
 
 
 
 
 
607
  /*sticky items*/
608
 
609
  .supsystic-sticky-active {
73
 
74
  .supsystic-plugin .supsystic-content .supsystic-container {
75
  margin-left: 75px;
76
+ /*overflow: hidden;
77
+ margin-top: 10px;*/
78
  }
79
 
80
  .supsystic-plugin .supsystic-content .supsystic-navigation {
238
 
239
  /* jQuery UI Dialog */
240
 
 
 
 
 
 
 
 
 
 
 
 
241
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
 
243
  .ui-dialog-titlebar-close {
244
  background: none !important;
442
  .supsystic-plugin .button,
443
  .supsystic-plugin .paginate_button,
444
  .supsystic-plugin .button-primary,
445
+ .ui-button:not(.ui-dialog-titlebar-close),
446
+ .ui-button.ui-state-default:not(.ui-dialog-titlebar-close) {
447
  font-size: 15px !important;
448
  height: 35px !important;
449
  -webkit-border-radius: 0 !important;
520
  line-height: 20px !important;
521
  }
522
 
523
+ .fa.supsystic-tooltip {
524
+ color:#52bac5;
525
+ }
526
+
527
  /*sticky items*/
528
 
529
  .supsystic-sticky-active {
app/assets/js/notify.js CHANGED
@@ -13,7 +13,8 @@
13
  top: '3.3em',
14
  padding: '1em',
15
  'background-color': 'white',
16
- 'box-shadow': '0px 0px 6px 0px rgba(0,0,0,0.1)'
 
17
  });
18
 
19
  $wrapper.wrapInner(this);
13
  top: '3.3em',
14
  padding: '1em',
15
  'background-color': 'white',
16
+ 'box-shadow': '0px 0px 6px 0px rgba(0,0,0,0.1)',
17
+ 'z-index': 99999
18
  });
19
 
20
  $wrapper.wrapInner(this);
app/assets/js/supsystic.ui.js CHANGED
@@ -28,6 +28,15 @@
28
  $(this).addClass('current');
29
  }
30
  });
 
 
 
 
 
 
 
 
 
31
  /* Bootstrap Tooltips */
32
  // $('body').tooltip({
33
  // selector: '.supsystic-plugin [data-toggle="tooltip"]',
@@ -38,8 +47,9 @@
38
  contentAsHTML: true,
39
  interactive: true,
40
  position: 'top-left',
41
- updateAnimation: true,
42
- animation: 'swing',
 
43
  functionReady: function(origin) {
44
  $('img').load(function(){
45
  origin.tooltipster('reposition');
28
  $(this).addClass('current');
29
  }
30
  });
31
+ var navWidth = $('.supsystic-navigation').width();
32
+ $('.supsystic-navigation a span').each(function(){
33
+ var el = $(this),
34
+ fontSize = parseFloat(el.css('font-size'));
35
+ while(el.width() > navWidth){
36
+ el.css('font-size', fontSize -= 1);
37
+ }
38
+ });
39
+
40
  /* Bootstrap Tooltips */
41
  // $('body').tooltip({
42
  // selector: '.supsystic-plugin [data-toggle="tooltip"]',
47
  contentAsHTML: true,
48
  interactive: true,
49
  position: 'top-left',
50
+ delay: 1000,
51
+ updateAnimation: false,
52
+ animation: '',
53
  functionReady: function(origin) {
54
  $('img').load(function(){
55
  origin.tooltipster('reposition');
app/templates/layout.twig CHANGED
@@ -52,6 +52,8 @@
52
  <!-- /.supsystic-navigation supsystic-sticky supsystic-sticky-active -->
53
  <div class="supsystic-container">
54
  {{ environment.getDispatcher().dispatch('notices') }}
 
 
55
  {% block content %}{% endblock %}
56
 
57
  <div id="dtgAddDialog" style="display: none;" title="{{ environment.translate('Add new table') }}" style="min-height: 70px;">
52
  <!-- /.supsystic-navigation supsystic-sticky supsystic-sticky-active -->
53
  <div class="supsystic-container">
54
  {{ environment.getDispatcher().dispatch('notices') }}
55
+ {{ environment.getDispatcher().dispatch('messages') }}
56
+
57
  {% block content %}{% endblock %}
58
 
59
  <div id="dtgAddDialog" style="display: none;" title="{{ environment.translate('Add new table') }}" style="min-height: 70px;">
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.9.71
8
  * Author: supsystic.com
9
  * Author URI: http://supsystic.com
10
  */
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.9.77
8
  * Author: supsystic.com
9
  * Author URI: http://supsystic.com
10
  */
readme.txt CHANGED
@@ -1,44 +1,32 @@
1
  === Data Tables Generator by Supsystic ===
2
  Contributors: supsystic.com
3
  Tags: csv, excel, table, tablesorter,data table, table, database, table generator, builder, generator, cells, chart, charting, charts, column chart, gauge chart, graph, graphs, html5, line chart, pie chart, scatter chart, spreadsheet, visualise data, Woo, Woo Commerce, WooCommerce, product table, woocommerce product, product tables, catalog, product catalog, price list, pricing list, order forms, woocommerce tables, wholesale
4
- Tested up to: 5.1.0
5
- Stable tag: 1.9.71
6
 
7
  Create data tables with charts and graphs. Custom design, navigation, searching and ordering functions. Export to PDF, CSV, Print. Excel spreadsheet. WooCommerce Integration.
8
 
9
  == Description ==
10
 
11
- Create and manage tables from the admin panel quickly, easily and effectively. Each Data Table can be used as a data source for creating DIAGRAMS & CHART. Create responsive, interactive data tables using sorting, searching, pagination, filtering and more.
12
- List the products with responsive [WooCommerce Product Table](https://supsystic.com/plugins/woocommerce-product-table?utm_source=wordpress&utm_medium=description&utm_campaign=woocommercedatatable "WooCommerce Product Table"). Perfect for product list views, order forms, wholesale, product catalogs.
13
- Tables do not require HTML/CSS knowledge, this plugin is really easy for beginners. Definitively the powerful and easy to use Data Tables.
14
 
15
- [Data Tables by Supsystic](http://supsystic.com/plugins/data-tables-generator-plugin?utm_source=wordpress&utm_medium=description&utm_campaign=datatables "Data Tables WordPress plugin") plugin features:
16
 
17
- * No coding required, [Responsive Modes](https://supsystic.com/feature/responsive-modes-feature/?utm_source=wordpress&utm_medium=responsivemodes&utm_campaign=datatables "Responsive Modes")
 
 
 
18
  * [FrontEnd Table Editing](https://supsystic.com/example/drop-down-bar/?utm_source=wordpress&utm_medium=frontendediting&utm_campaign=datatables "FrontEnd Data Table Editing Example")
19
- * [FrontEnd Table export - CSV, Excel, PDF](https://supsystic.com/example/export-import-of-tables?utm_source=wordpress&utm_medium=export&utm_campaign=datatables "Export & Import of Tables")
20
- * [Diagrams, Charts and Graphs](https://supsystic.com/example/table-with-diagram-examplehttps://supsystic.com/example/table-with-diagram-example/?utm_source=wordpress&utm_medium=screenshotscharts&utm_campaign=datatables "Data Table With Google Charts")
21
- * [Formulas support, HTML tables support for data cells](https://supsystic.com/example/table-with-calculations-example?utm_source=wordpress&utm_medium=calculations&utm_campaign=datatables "Table with Calculations")
22
  * [Images, Links & Video support](https://supsystic.com/example/table-with-pictures-and-links-example?utm_source=wordpress&utm_medium=vedeo&utm_campaign=datatables "Images, Links & Video support")
23
- * [WooCommerce Integration](https://supsystic.com/plugins/woocommerce-product-table?utm_source=wordpress&utm_medium=description&utm_campaign=woocommercedatatable "WooCommerce Product Table")
24
- * [Table Properties Variations](https://woo.supsystic.com/table-properties-variations?utm_source=wordpress&utm_medium=propertiesvariations&utm_campaign=woocommercedatatable "WooCommerce Product Table Properties Variations")
25
- * [Quantities and Multiple add to cart](https://supsystic.com/feature/quantities-multiple-add-to-cart?utm_source=wordpress&utm_medium=multipleaddtocart&utm_campaign=woocommercedatatable "Quantities and Multiple add to cart")
26
- * [Product Table online builder](https://supsystic.com/feature/product-table-online-builder?utm_source=wordpress&utm_medium=builder&utm_campaign=datatables "Product Table online builder")
27
- * "Bold" and "Italic" font style support for the data table cells
28
- * [Navigation with Searching, Sorting, Pagination functions](https://supsystic.com/example/table-with-sorting-and-search-example?utm_source=wordpress&utm_medium=tablenavigation&utm_campaign=datatables "Data Table navigation with Searching and Ordering functions")
29
- * [Various style setting appropriated for any sites type](https://supsystic.com/documentation/table-styling?utm_source=wordpress&utm_medium=tabledesign&utm_campaign=datatables "Table Design")
30
- * [Collapsible rows on front-end](https://supsystic.com/example/collapsible-rows-on-front-end/?utm_source=wordpress&utm_medium=collapsiblerows&utm_campaign=datatables "Collapsible rows")
31
- * [Server-side processing technology](https://supsystic.com/example/tables-with-server-side-processing-example?utm_source=wordpress&utm_medium=serversideprocessing&utm_campaign=datatables "Server-side processing")
32
- * SEO friendly, content of DataTable picked up by search engines
33
- * [Table data and Diagrams interaction](https://supsystic.com/example/table-and-diagrams-interaction?utm_source=wordpress&utm_medium=serversideprocessing&utm_campaign=datatables "Table data and Diagrams interaction")
34
  * [Automatic import from Google Sheets](https://supsystic.com/documentation/synchronization-table-google-sheet?utm_source=wordpress&utm_medium=featuresgoogle&utm_campaign=datatables "Autoupdates from Google Sheets")
35
  * [Database Source](https://supsystic.com/feature/database-source?utm_source=wordpress&utm_medium=featuresgoogle&utm_campaign=datatables "Database Source")
36
- * [All Data Table Examples](http://supsystic.com/data-tables-examples?utm_source=wordpress&utm_medium=databasesource&utm_campaign=datatables "Data Table Examples")
37
-
38
- Data Tables Generator allows you to process and manage SEO friendly data tables quickly and easily. This plugin can structure information and can be adjusted to fit every need. Many ways of functional and visual customization of the tables improve site design and let you modify it to cater to a particular individual or a specific task. The intuitive Settings panel and the responsive Editor save lots of time that you would much rather allocate for other useful things or relaxation. Tables are responsive and awesome on all devices.
39
 
40
  [youtube https://www.youtube.com/watch?v=RZ2I-aCiLZE]
41
 
 
 
42
  = Data Tables Plugin Support =
43
 
44
  If you have any problem or a tailored request for the Data Tables Generator by Supsystic, please [let us know](http://supsystic.com/contact-us/ "Contact Us")!
@@ -226,6 +214,56 @@ Create custom order forms which increase your conversion rate!
226
 
227
  == Changelog ==
228
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
  = 1.9.71 / 25.02.2019 =
230
  * Fix of formulas: SUMIF. Fix of applying of current date to datepicker for empty edited cells of Date type
231
  * Exclude images it tables from lazy loading by Jetpack
1
  === Data Tables Generator by Supsystic ===
2
  Contributors: supsystic.com
3
  Tags: csv, excel, table, tablesorter,data table, table, database, table generator, builder, generator, cells, chart, charting, charts, column chart, gauge chart, graph, graphs, html5, line chart, pie chart, scatter chart, spreadsheet, visualise data, Woo, Woo Commerce, WooCommerce, product table, woocommerce product, product tables, catalog, product catalog, price list, pricing list, order forms, woocommerce tables, wholesale
4
+ Tested up to: 5.2.1
5
+ Stable tag: 1.9.77
6
 
7
  Create data tables with charts and graphs. Custom design, navigation, searching and ordering functions. Export to PDF, CSV, Print. Excel spreadsheet. WooCommerce Integration.
8
 
9
  == Description ==
10
 
11
+ Create responsive data tables with sorting, searching, pagination, filtering and more. Easy-to-use tables, charts and data management. * [Data Table Examples](http://supsystic.com/data-tables-examples?utm_source=wordpress&utm_medium=databasesource&utm_campaign=datatables "Data Table Examples")
 
 
12
 
13
+ [Data Tables WordPress plugin](http://supsystic.com/plugins/data-tables-generator-plugin?utm_source=wordpress&utm_medium=description&utm_campaign=datatables "Data Tables WordPress plugin") features:
14
 
15
+ * [Responsive Modes](https://supsystic.com/feature/responsive-modes-feature/?utm_source=wordpress&utm_medium=responsivemodes&utm_campaign=datatables "Responsive Modes") and [Large Tables](https://supsystic.com/example/tables-with-server-side-processing-example/ "Large Tables") support
16
+ * [Diagrams, Charts and Graphs](https://supsystic.com/example/table-with-diagram-example/?utm_source=wordpress&utm_medium=screenshotscharts&utm_campaign=datatables "Data Table With Google Charts")
17
+ * [Formulas and HTML support](https://supsystic.com/example/table-with-calculations-example?utm_source=wordpress&utm_medium=calculations&utm_campaign=datatables "Formulas and HTML support")
18
+ * [Filters, Search, Sorting and Pagination](https://supsystic.com/example/table-with-sorting-and-search-example?utm_source=wordpress&utm_medium=tablenavigation&utm_campaign=datatables "Data Table navigation with Searching and Ordering functions")
19
  * [FrontEnd Table Editing](https://supsystic.com/example/drop-down-bar/?utm_source=wordpress&utm_medium=frontendediting&utm_campaign=datatables "FrontEnd Data Table Editing Example")
20
+ * [Table export and import from CSV, Excel, PDF](https://supsystic.com/example/export-import-of-tables?utm_source=wordpress&utm_medium=export&utm_campaign=datatables "Export & Import of Tables")
 
 
21
  * [Images, Links & Video support](https://supsystic.com/example/table-with-pictures-and-links-example?utm_source=wordpress&utm_medium=vedeo&utm_campaign=datatables "Images, Links & Video support")
22
+ * [WooCommerce Product Table](https://supsystic.com/plugins/woocommerce-product-table?utm_source=wordpress&utm_medium=description&utm_campaign=woocommercedatatable "WooCommerce Product Table")
 
 
 
 
 
 
 
 
 
 
23
  * [Automatic import from Google Sheets](https://supsystic.com/documentation/synchronization-table-google-sheet?utm_source=wordpress&utm_medium=featuresgoogle&utm_campaign=datatables "Autoupdates from Google Sheets")
24
  * [Database Source](https://supsystic.com/feature/database-source?utm_source=wordpress&utm_medium=featuresgoogle&utm_campaign=datatables "Database Source")
 
 
 
25
 
26
  [youtube https://www.youtube.com/watch?v=RZ2I-aCiLZE]
27
 
28
+ Data Tables Generator allows you to process and manage SEO friendly data tables quickly and easily. This plugin can structure information and can be adjusted to fit every need. Many ways of functional and visual customization of the tables improve site design and let you modify it to cater to a particular individual or a specific task. The intuitive Settings panel and the responsive Editor save lots of time that you would much rather allocate for other useful things or relaxation. Tables are responsive and awesome on all devices.
29
+
30
  = Data Tables Plugin Support =
31
 
32
  If you have any problem or a tailored request for the Data Tables Generator by Supsystic, please [let us know](http://supsystic.com/contact-us/ "Contact Us")!
214
 
215
  == Changelog ==
216
 
217
+ = 1.9.77 / 11.06.2019 =
218
+ * Small fix for Edit link on frontend
219
+
220
+ = 1.9.76 / 30.04.2019 =
221
+ * Hot fixes for 1.9.75 release - now all things with any configurations work great!
222
+ * Fixed recalc complex forlumas
223
+ * Fixed lightbox image with link issue
224
+ * Add edit link for admin after table
225
+
226
+ = 1.9.75 / 24.04.2019 =
227
+ * Added variable products
228
+ * Fix for frontend diagrams refresh
229
+ * Fix column search
230
+ * Added export remote images and import images from Google Sheets
231
+ * Fixed column width for horizontal mode
232
+ * Fix deactivation gialog
233
+ * Fixed merged cells by searching
234
+ * Minor issues fix
235
+
236
+ = 1.9.74 / 03.04.2019 =
237
+ * Fix for CSS
238
+ * Fix of importing hyperlinks from MS Excel and Google Spreadsheet
239
+ * Fix of excluding rows / columns from diagrams range. Add ability to set excluding rows / columns by rows / columns indexes
240
+ * Fix of applying of default sorting
241
+ * Added display variation attributes
242
+ * Added strip, hover and highlighting for custom styles
243
+ * Added select attribute for woo-tables
244
+ * Added the ability to trigger import from external code
245
+ * Minor issues fix
246
+
247
+ = 1.9.73 / 15.03.2019 =
248
+ * Custom styles lables fix
249
+ * IE table loading bug fix
250
+ * Minor issues fix
251
+
252
+ = 1.9.72 / 13.03.2019 =
253
+ * For Woo-addon added export in Excell, fixed export in PDF and fixed export self-hosted images for all tables
254
+ * Changed interface for settings
255
+ * Add option: Export Links Position
256
+ * Fixed formulas for wide tables
257
+ * Added live Preview
258
+ * Fix for slashes
259
+ * Fix currency format for editor
260
+ * Added wc errors output
261
+ * Added font adaptation for navigation bar
262
+ * Fix for style tooltip and overview
263
+ * Added Table Styling Settings
264
+ * Moved big ad files to cdn server
265
+ * Added Tags Column for woo-addon
266
+
267
  = 1.9.71 / 25.02.2019 =
268
  * Fix of formulas: SUMIF. Fix of applying of current date to datepicker for empty edited cells of Date type
269
  * Exclude images it tables from lazy loading by Jetpack
src/SupsysticTables/Core/BaseModule.php CHANGED
@@ -13,7 +13,7 @@ abstract class SupsysticTables_Core_BaseModule extends Rsc_Mvc_Module
13
  $dispathcer = $this->getEnvironment()->getDispatcher();
14
  $dispathcer->on('after_ui_loaded', array($this, 'afterUiLoaded'));
15
  $dispathcer->on('after_modules_loaded', array($this, 'afterModulesLoaded'));
16
- add_action('admin_enqueue_scripts', array($this, 'adminEnqueueScriptsAction'));
17
 
18
  }
19
 
13
  $dispathcer = $this->getEnvironment()->getDispatcher();
14
  $dispathcer->on('after_ui_loaded', array($this, 'afterUiLoaded'));
15
  $dispathcer->on('after_modules_loaded', array($this, 'afterModulesLoaded'));
16
+ //add_action('admin_enqueue_scripts', array($this, 'adminEnqueueScriptsAction'));
17
 
18
  }
19
 
src/SupsysticTables/Core/Model/Core.php CHANGED
@@ -30,6 +30,9 @@ class SupsysticTables_Core_Model_Core extends SupsysticTables_Core_BaseModel
30
  if($this->checkQueryOnColumnNotExists($q)) {
31
  $this->db->query($q);
32
  }
 
 
 
33
  } else {
34
  $this->delta($q);
35
  }
30
  if($this->checkQueryOnColumnNotExists($q)) {
31
  $this->db->query($q);
32
  }
33
+ }
34
+ elseif ('delete' === substr(strtolower($q), 0, 6)) {
35
+ $this->db->query($q);
36
  } else {
37
  $this->delta($q);
38
  }
src/SupsysticTables/Core/Module.php CHANGED
@@ -16,7 +16,8 @@ class SupsysticTables_Core_Module extends SupsysticTables_Core_BaseModule
16
 
17
  private $frontendMethods = array(
18
  'ajax' => array(
19
- 'tables' => array('saveEditableFields', 'getPageRows')
 
20
  ),
21
  'post' => array(
22
  'importer' => array('import'),
@@ -129,6 +130,14 @@ class SupsysticTables_Core_Module extends SupsysticTables_Core_BaseModule
129
  ->setVersion($pluginVersion)
130
  );
131
 
 
 
 
 
 
 
 
 
132
  /* Tooltipster */
133
  $ui->add(
134
  $ui->createStyle('tables-tooltipster')
@@ -419,6 +428,9 @@ class SupsysticTables_Core_Module extends SupsysticTables_Core_BaseModule
419
 
420
  return $homepage . '?' . http_build_query($parameters);
421
  }
 
 
 
422
 
423
  public function addPregReplaceFilter($input, $regexp, $replace)
424
  {
16
 
17
  private $frontendMethods = array(
18
  'ajax' => array(
19
+ 'tables' => array('saveEditableFields', 'getPageRows'),
20
+ 'woocommerce' => array('productsAddToCart')
21
  ),
22
  'post' => array(
23
  'importer' => array('import'),
130
  ->setVersion($pluginVersion)
131
  );
132
 
133
+ $ui->add(
134
+ $ui->createStyle('supsystic-tables-base')
135
+ ->setHookName($hookName)
136
+ ->setModuleSource($this, 'css/base.css')
137
+ ->setCachingAllowed($cachingAllowed)
138
+ ->setVersion($pluginVersion)
139
+ );
140
+
141
  /* Tooltipster */
142
  $ui->add(
143
  $ui->createStyle('tables-tooltipster')
428
 
429
  return $homepage . '?' . http_build_query($parameters);
430
  }
431
+ public function getCdnUrl() {
432
+ return (is_ssl() ? 'https' : 'http').'://supsystic-42d7.kxcdn.com/';
433
+ }
434
 
435
  public function addPregReplaceFilter($input, $regexp, $replace)
436
  {
src/SupsysticTables/Core/assets/css/base.css CHANGED
@@ -1,3 +1,89 @@
1
  #toplevel_page_supsystic-tables .wp-submenu.wp-submenu-wrap .wp-first-item {
2
  display: none;
3
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  #toplevel_page_supsystic-tables .wp-submenu.wp-submenu-wrap .wp-first-item {
2
  display: none;
3
+ }
4
+ .ui-dialog .ui-dialog-titlebar {
5
+ line-height: 25px;
6
+ }
7
+
8
+ .ui-dialog .ui-dialog-titlebar-close {
9
+ display: none;
10
+ }
11
+
12
+ .ui-dialog .ui-dialog-buttonpane {
13
+ padding: 0 !important;
14
+ margin-top: 10px !important;
15
+ border: none !important;
16
+ text-align: right !important;
17
+ }
18
+
19
+ .ui-dialog .ui-dialog-content {
20
+ position: relative;
21
+ border: 0;
22
+ padding: .5em 1em;
23
+ background: none;
24
+ overflow: visible !important;
25
+ }
26
+
27
+ .ui-dialog .ui-dialog-buttonpane button {
28
+ margin: 0 10px 0 0 !important;
29
+ outline: 0;
30
+ }
31
+
32
+ .ui-button-text-only .ui-button-text {
33
+ padding: 0 !important;
34
+ }
35
+
36
+ .ui-dialog .ui-dialog-title {
37
+ float: none !important;
38
+ font-size: 17px;
39
+ }
40
+
41
+ .ui-widget {
42
+ font-family: Verdana,Arial,Helvetica,sans-serif;
43
+ font-size: 1.1em;
44
+ }
45
+
46
+ .ui-widget-content input {
47
+ width: 100%;
48
+ height: auto;
49
+ }
50
+
51
+ .ui-dialog {
52
+ box-shadow: 1px 1px 10px #ccc;
53
+ -webkit-box-shadow: 1px 1px 10px #ccc;
54
+ -moz-box-shadow: 1px 1px 10px #ccc;
55
+ -ms-box-shadow: 1px 1px 10px #ccc;
56
+ -o-box-shadow: 1px 1px 10px #ccc;
57
+ }
58
+
59
+ .ui-widget-overlay {
60
+ background: #000 !important;
61
+ opacity: .3;
62
+ -ms-filter: Alpha(opacity=30);
63
+ filter: Alpha(opacity=30);
64
+ position: fixed;
65
+ top: 0;
66
+ left: 0;
67
+ width: 100%;
68
+ height: 100%;
69
+ }
70
+
71
+ .ui-widget-overlay.ui-front {
72
+ z-index: 10;
73
+ }
74
+
75
+ .ui-dialog.ui-widget-content {
76
+ background: #fff !important;
77
+ padding: 15px 5px !important;
78
+ z-index: 100001;
79
+ }
80
+
81
+ .ui-widget-header {
82
+ border: none !important;
83
+ border-bottom: 1px solid #ddd !important;
84
+ background: none !important;
85
+ color: #777 !important;
86
+ border-radius: 0 !important;
87
+ padding: 0 10px 15px 10px !important;
88
+ font-weight: normal !important;
89
+ }
src/SupsysticTables/Core/assets/js/core.js CHANGED
@@ -170,6 +170,17 @@ var g_stbServerSideProcessingIsActive = false;
170
  return deferred.promise();
171
  });
172
 
 
 
 
 
 
 
 
 
 
 
 
173
  vendor[appName].initTablesOnPage = (function() {
174
  this._initTablesOnPage();
175
  });
@@ -183,13 +194,7 @@ var g_stbServerSideProcessingIsActive = false;
183
  firstTableFirstRow = '';
184
 
185
  if($(window).width() <= 991) {
186
- $('div .supsystic-tables-wrap').each(function () {
187
- var ssDiv = $(this),
188
- widthMobile = ssDiv.data('table-width-mobile');
189
- if(typeof(widthMobile) != 'undefined') {
190
- ssDiv.css('display', (widthMobile == 'auto' ? 'inline-block' : '')).css('width', widthMobile);
191
- }
192
- });
193
  }
194
  $('.supsystic-table').each(function () {
195
  self.initializeTable(this, self.showTable, function(table) {
@@ -246,6 +251,7 @@ var g_stbServerSideProcessingIsActive = false;
246
  }
247
  if(typeof self.getTableInstanceById(table.data('id')).fnAdjustColumnSizing == 'function' ) {
248
  setTimeout(function(){
 
249
  self.getTableInstanceById(table.data('id')).fnAdjustColumnSizing(false);
250
  }, 350);
251
  }
@@ -333,6 +339,7 @@ var g_stbServerSideProcessingIsActive = false;
333
  stateSave: false,
334
  api: true,
335
  retrieve: true,
 
336
  initComplete: callback,
337
  headerCallback: function( thead, data, start, end, display ) {
338
  $(thead).closest('thead').find('th').each(function() {
@@ -343,7 +350,13 @@ var g_stbServerSideProcessingIsActive = false;
343
  $(tfoot).closest('tfoot').find('th').each(function() {
344
  self.setStylesToCell(this);
345
  });
346
- }
 
 
 
 
 
 
347
  };
348
 
349
  g_stbServerSideProcessing = $table.data('server-side-processing') && $table.data('server-side-processing') == 'on';
@@ -397,7 +410,6 @@ var g_stbServerSideProcessingIsActive = false;
397
  searchingSettings.resultOnly ||
398
  searchingSettings.strictMatching
399
  ) {
400
-
401
  $.fn.dataTable.ext.search.push(function(settings, data) {
402
  var $searchInput = $(settings.nTableWrapper).find('.dataTables_filter input'),
403
  searchValue = $searchInput.val();
@@ -499,13 +511,13 @@ var g_stbServerSideProcessingIsActive = false;
499
  multipleSorting = $table.data('multiple-sorting'),
500
  disableSorting = $table.data('disable-sorting');
501
 
502
- if (!$table.data('head')) {
503
  sortingDisable = ['_all'];
504
  }
505
  if(disableSorting && disableSorting.length) {
506
  sortingDisable = disableSorting;
507
  }
508
- if (multipleSorting && multipleSorting.length) {
509
  aaSorting = multipleSorting;
510
  } else {
511
  var columnsCount = $table.find('tr:first th').length,
@@ -523,6 +535,7 @@ var g_stbServerSideProcessingIsActive = false;
523
  { "sortable": true, "targets": sortingEnable }
524
  ];
525
  config.aaSorting = aaSorting;
 
526
  }
527
  if ($table.data('pagination-length')) {
528
  var paginationLength = String($table.data('pagination-length'));
@@ -631,6 +644,8 @@ var g_stbServerSideProcessingIsActive = false;
631
  }
632
  }
633
  if ($table.width() > $table.parent().width()) {
 
 
634
  api.responsive.recalc();
635
  return;
636
  }
@@ -654,6 +669,15 @@ var g_stbServerSideProcessingIsActive = false;
654
  } else if (responsiveMode === 2) {
655
  // Responsive Mode: Horizontal Scroll
656
  config.scrollX = true;
 
 
 
 
 
 
 
 
 
657
  }
658
  if(responsiveMode === 2 || responsiveMode === 3) {
659
  // Responsive Mode: 2 - Horizontal Scroll, 3 - Disable Responsivity
@@ -836,6 +860,9 @@ var g_stbServerSideProcessingIsActive = false;
836
  if(searching && ('columnSearch' in searching) && searching.columnSearch == 'on') {
837
  self.setColumnSearch($table);
838
  }
 
 
 
839
  });
840
  if(addInstance) {
841
  this.setTableInstance(tableInstance);
@@ -902,6 +929,11 @@ var g_stbServerSideProcessingIsActive = false;
902
  var table = $(this),
903
  tableSelector = '#supsystic-table-' + table.data('view-id') + ' #supsystic-table-' + table.data('id');
904
  self.applyTableEventClb(self.pageEvent, 50, tableSelector);
 
 
 
 
 
905
  });
906
 
907
  // Frontend fields
@@ -920,9 +952,6 @@ var g_stbServerSideProcessingIsActive = false;
920
  self.setAllFields($table, $editableFields, $selectableFields);
921
  } else {
922
  self.createEditableFields($table, $editableFields);
923
- }
924
- if(typeof(self.setImgLightbox) == 'function'){
925
- self.setImgLightbox($table);
926
  }
927
  $table.on('init.dt', function() {
928
  $table.on('responsive-resize.dt responsive-display.dt draw.dt', function() {
@@ -932,6 +961,9 @@ var g_stbServerSideProcessingIsActive = false;
932
  });
933
  }
934
  }
 
 
 
935
 
936
  // apply page.dt event by change table pagination via select
937
  var paginationSelect = $tableWrap.find('.dataTables_length select');
@@ -954,25 +986,28 @@ var g_stbServerSideProcessingIsActive = false;
954
  if(responsiveMode === 2 || fixedHeader || fixedFooter) {
955
  // Responsive Mode: Horizontal Scroll
956
  $(window).on('resize', $table, function(event) {
957
- var tBody = $tableWrap.find('.dataTables_scrollBody'),
958
  tBodyTable = tBody.find('.supsystic-table');
959
 
960
  if(tBody.width() > tBodyTable.width() || $tableWrap.width() > tBodyTable.width()) {
961
  tBody.width(tBodyTable.width());
962
  $tableWrap.find('.dataTables_scrollHead, .dataTables_scrollFoot, .dataTables_scrollBody').width(tBodyTable.width() + 1);
 
 
 
 
963
  }
964
  if(tBody.isHorizontallyScrollable()){
965
  tBody.css({'border-bottom' : 'none'});
966
  }else{
967
  tBody.removeStyle('border-bottom');
968
  }
969
- if(g_stbServerSideProcessing) {
970
- if(typeof self.getTableInstanceById(viewId).fnAdjustColumnSizing == 'function' ) {
971
- setTimeout(function(){
972
- self.getTableInstanceById(table.data('id')).fnAdjustColumnSizing(false);
973
- }, 350);
974
- }
975
- }
976
  }).trigger('resize');
977
 
978
  // need resize twice to get better frontend view
@@ -1204,8 +1239,9 @@ var g_stbServerSideProcessingIsActive = false;
1204
  if(inputs.length == 0) {
1205
  return;
1206
  }
1207
- $(document).off('keyup change', ".dataTables_wrapper:first .stbColumnsSearchWrapper .search-column")
1208
- .on('keyup change', ".dataTables_wrapper:first .stbColumnsSearchWrapper .search-column",function () {
 
1209
  var input = $(this),
1210
  position = input.parents('th:first').index(),
1211
  value = this.value,
@@ -1779,4 +1815,83 @@ function toeInArray(needle, haystack) {
1779
  });
1780
  });
1781
  };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1782
  }(jQuery));
170
  return deferred.promise();
171
  });
172
 
173
+ vendor[appName].setTableMobileWidth = (function(isMobile) {
174
+ $('div .supsystic-tables-wrap').each(function () {
175
+ isMobile = (typeof(isMobile) == 'undefined' ? true : isMobile);
176
+ var ssDiv = $(this),
177
+ widthAttr = ssDiv.data('table-width-' + (isMobile ? 'mobile' : 'fixed'));
178
+ if(typeof(widthAttr) != 'undefined') {
179
+ ssDiv.css('display', (widthAttr == 'auto' ? 'inline-block' : '')).css('width', widthAttr);
180
+ }
181
+ });
182
+ });
183
+
184
  vendor[appName].initTablesOnPage = (function() {
185
  this._initTablesOnPage();
186
  });
194
  firstTableFirstRow = '';
195
 
196
  if($(window).width() <= 991) {
197
+ self.setTableMobileWidth();
 
 
 
 
 
 
198
  }
199
  $('.supsystic-table').each(function () {
200
  self.initializeTable(this, self.showTable, function(table) {
251
  }
252
  if(typeof self.getTableInstanceById(table.data('id')).fnAdjustColumnSizing == 'function' ) {
253
  setTimeout(function(){
254
+ table.trigger('responsive-resize.dt');
255
  self.getTableInstanceById(table.data('id')).fnAdjustColumnSizing(false);
256
  }, 350);
257
  }
339
  stateSave: false,
340
  api: true,
341
  retrieve: true,
342
+ processing: true,
343
  initComplete: callback,
344
  headerCallback: function( thead, data, start, end, display ) {
345
  $(thead).closest('thead').find('th').each(function() {
350
  $(tfoot).closest('tfoot').find('th').each(function() {
351
  self.setStylesToCell(this);
352
  });
353
+ },
354
+ // order param disable the default table sorting.
355
+ // it should be here because of Woocommerce addon:
356
+ // it has no hidden header for tables without header
357
+ // and in triggers an error during initializing.
358
+ // order param should be disabled later during sorting activation
359
+ order: []
360
  };
361
 
362
  g_stbServerSideProcessing = $table.data('server-side-processing') && $table.data('server-side-processing') == 'on';
410
  searchingSettings.resultOnly ||
411
  searchingSettings.strictMatching
412
  ) {
 
413
  $.fn.dataTable.ext.search.push(function(settings, data) {
414
  var $searchInput = $(settings.nTableWrapper).find('.dataTables_filter input'),
415
  searchValue = $searchInput.val();
511
  multipleSorting = $table.data('multiple-sorting'),
512
  disableSorting = $table.data('disable-sorting');
513
 
514
+ if(!$table.data('head')) {
515
  sortingDisable = ['_all'];
516
  }
517
  if(disableSorting && disableSorting.length) {
518
  sortingDisable = disableSorting;
519
  }
520
+ if(multipleSorting && multipleSorting.length) {
521
  aaSorting = multipleSorting;
522
  } else {
523
  var columnsCount = $table.find('tr:first th').length,
535
  { "sortable": true, "targets": sortingEnable }
536
  ];
537
  config.aaSorting = aaSorting;
538
+ delete defaultFeatures.order;
539
  }
540
  if ($table.data('pagination-length')) {
541
  var paginationLength = String($table.data('pagination-length'));
644
  }
645
  }
646
  if ($table.width() > $table.parent().width()) {
647
+ $table.css('width', '100%');
648
+ $table.css('max-width', '100%');
649
  api.responsive.recalc();
650
  return;
651
  }
669
  } else if (responsiveMode === 2) {
670
  // Responsive Mode: Horizontal Scroll
671
  config.scrollX = true;
672
+ var firstRow = $table.find('tbody tr:first-child td');
673
+ if(firstRow.length) {
674
+ var cntCols = firstRow.length;
675
+ $table.find('thead tr:first-child th').each(function(i, th){
676
+ if(cntCols > i && $(th).css('width')) {
677
+ firstRow.eq(i).css('width', $(th).css('width'));
678
+ }
679
+ });
680
+ }
681
  }
682
  if(responsiveMode === 2 || responsiveMode === 3) {
683
  // Responsive Mode: 2 - Horizontal Scroll, 3 - Disable Responsivity
860
  if(searching && ('columnSearch' in searching) && searching.columnSearch == 'on') {
861
  self.setColumnSearch($table);
862
  }
863
+ if(!g_stbServerSideProcessing && $table.data('merged')) {
864
+ tableInstance.fnResetFakeRowspan();
865
+ }
866
  });
867
  if(addInstance) {
868
  this.setTableInstance(tableInstance);
929
  var table = $(this),
930
  tableSelector = '#supsystic-table-' + table.data('view-id') + ' #supsystic-table-' + table.data('id');
931
  self.applyTableEventClb(self.pageEvent, 50, tableSelector);
932
+ if($table.data('pagination-scroll') == 'on') {
933
+ $('html, body').animate({
934
+ scrollTop: table.closest('.dataTables_wrapper').offset().top
935
+ }, 100);
936
+ }
937
  });
938
 
939
  // Frontend fields
952
  self.setAllFields($table, $editableFields, $selectableFields);
953
  } else {
954
  self.createEditableFields($table, $editableFields);
 
 
 
955
  }
956
  $table.on('init.dt', function() {
957
  $table.on('responsive-resize.dt responsive-display.dt draw.dt', function() {
961
  });
962
  }
963
  }
964
+ if(typeof(self.setImgLightbox) == 'function'){
965
+ self.setImgLightbox($table);
966
+ }
967
 
968
  // apply page.dt event by change table pagination via select
969
  var paginationSelect = $tableWrap.find('.dataTables_length select');
986
  if(responsiveMode === 2 || fixedHeader || fixedFooter) {
987
  // Responsive Mode: Horizontal Scroll
988
  $(window).on('resize', $table, function(event) {
989
+ var tBody = $tableWrap.find('.dataTables_scrollBody'),
990
  tBodyTable = tBody.find('.supsystic-table');
991
 
992
  if(tBody.width() > tBodyTable.width() || $tableWrap.width() > tBodyTable.width()) {
993
  tBody.width(tBodyTable.width());
994
  $tableWrap.find('.dataTables_scrollHead, .dataTables_scrollFoot, .dataTables_scrollBody').width(tBodyTable.width() + 1);
995
+ /*
996
+ var scrollTables = $tableWrap.find('.dataTables_scrollHead, .dataTables_scrollFoot');
997
+ scrollTables.width(tBodyTable.width() + 1);
998
+ scrollTables.find('table').width(tBodyTable.width() + 1);*/
999
  }
1000
  if(tBody.isHorizontallyScrollable()){
1001
  tBody.css({'border-bottom' : 'none'});
1002
  }else{
1003
  tBody.removeStyle('border-bottom');
1004
  }
1005
+ var table = self.getTableInstanceById($table.data('id'));
1006
+ if(typeof table.fnAdjustColumnSizing == 'function' ) {
1007
+ setTimeout(function(){
1008
+ table.fnAdjustColumnSizing(false);
1009
+ }, 350);
1010
+ }
 
1011
  }).trigger('resize');
1012
 
1013
  // need resize twice to get better frontend view
1239
  if(inputs.length == 0) {
1240
  return;
1241
  }
1242
+ //$(document).off('keyup change', ".dataTables_wrapper:first .stbColumnsSearchWrapper .search-column")
1243
+ // .on('keyup change', ".dataTables_wrapper:first .stbColumnsSearchWrapper .search-column",function () {
1244
+ inputs.off('keyup.dtg change.dtg').on('keyup.dtg change.dtg',function () {
1245
  var input = $(this),
1246
  position = input.parents('th:first').index(),
1247
  value = this.value,
1815
  });
1816
  });
1817
  };
1818
+
1819
+ if (!Array.from) {
1820
+ // Fix of compatibility with IE browser to use ES6 feature
1821
+ Array.from = (function () {
1822
+ var toStr = Object.prototype.toString;
1823
+ var isCallable = function (fn) {
1824
+ return typeof fn === 'function' || toStr.call(fn) === '[object Function]';
1825
+ };
1826
+ var toInteger = function (value) {
1827
+ var number = Number(value);
1828
+ if (isNaN(number)) { return 0; }
1829
+ if (number === 0 || !isFinite(number)) { return number; }
1830
+ return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
1831
+ };
1832
+ var maxSafeInteger = Math.pow(2, 53) - 1;
1833
+ var toLength = function (value) {
1834
+ var len = toInteger(value);
1835
+ return Math.min(Math.max(len, 0), maxSafeInteger);
1836
+ };
1837
+
1838
+ // The length property of the from method is 1.
1839
+ return function from(arrayLike/*, mapFn, thisArg */) {
1840
+ // 1. Let C be the this value.
1841
+ var C = this;
1842
+
1843
+ // 2. Let items be ToObject(arrayLike).
1844
+ var items = Object(arrayLike);
1845
+
1846
+ // 3. ReturnIfAbrupt(items).
1847
+ if (arrayLike == null) {
1848
+ throw new TypeError('Array.from requires an array-like object - not null or undefined');
1849
+ }
1850
+
1851
+ // 4. If mapfn is undefined, then let mapping be false.
1852
+ var mapFn = arguments.length > 1 ? arguments[1] : void undefined;
1853
+ var T;
1854
+ if (typeof mapFn !== 'undefined') {
1855
+ // 5. else
1856
+ // 5. a If IsCallable(mapfn) is false, throw a TypeError exception.
1857
+ if (!isCallable(mapFn)) {
1858
+ throw new TypeError('Array.from: when provided, the second argument must be a function');
1859
+ }
1860
+
1861
+ // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined.
1862
+ if (arguments.length > 2) {
1863
+ T = arguments[2];
1864
+ }
1865
+ }
1866
+
1867
+ // 10. Let lenValue be Get(items, "length").
1868
+ // 11. Let len be ToLength(lenValue).
1869
+ var len = toLength(items.length);
1870
+
1871
+ // 13. If IsConstructor(C) is true, then
1872
+ // 13. a. Let A be the result of calling the [[Construct]] internal method
1873
+ // of C with an argument list containing the single item len.
1874
+ // 14. a. Else, Let A be ArrayCreate(len).
1875
+ var A = isCallable(C) ? Object(new C(len)) : new Array(len);
1876
+
1877
+ // 16. Let k be 0.
1878
+ var k = 0;
1879
+ // 17. Repeat, while k < len… (also steps a - h)
1880
+ var kValue;
1881
+ while (k < len) {
1882
+ kValue = items[k];
1883
+ if (mapFn) {
1884
+ A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k);
1885
+ } else {
1886
+ A[k] = kValue;
1887
+ }
1888
+ k += 1;
1889
+ }
1890
+ // 18. Let putStatus be Put(A, "length", len, true).
1891
+ A.length = len;
1892
+ // 20. Return A.
1893
+ return A;
1894
+ };
1895
+ }());
1896
+ }
1897
  }(jQuery));
src/SupsysticTables/Core/assets/js/jquery.tooltipster.min.js CHANGED
@@ -1 +1,2 @@
1
- /* Tooltipster v3.3.0 */;(function(e,t,n){function s(t,n){this.bodyOverflowX;this.callbacks={hide:[],show:[]};this.checkInterval=null;this.Content;this.$el=e(t);this.$elProxy;this.elProxyPosition;this.enabled=true;this.options=e.extend({},i,n);this.mouseIsOverProxy=false;this.namespace="tooltipster-"+Math.round(Math.random()*1e5);this.Status="hidden";this.timerHide=null;this.timerShow=null;this.$tooltip;this.options.iconTheme=this.options.iconTheme.replace(".","");this.options.theme=this.options.theme.replace(".","");this._init()}function o(t,n){var r=true;e.each(t,function(e,i){if(typeof n[e]==="undefined"||t[e]!==n[e]){r=false;return false}});return r}function f(){return!a&&u}function l(){var e=n.body||n.documentElement,t=e.style,r="transition";if(typeof t[r]=="string"){return true}v=["Moz","Webkit","Khtml","O","ms"],r=r.charAt(0).toUpperCase()+r.substr(1);for(var i=0;i<v.length;i++){if(typeof t[v[i]+r]=="string"){return true}}return false}var r="tooltipster",i={animation:"fade",arrow:true,arrowColor:"",autoClose:true,content:null,contentAsHTML:false,contentCloning:true,debug:true,delay:200,minWidth:0,maxWidth:null,functionInit:function(e,t){},functionBefore:function(e,t){t()},functionReady:function(e,t){},functionAfter:function(e){},hideOnClick:false,icon:"(?)",iconCloning:true,iconDesktop:false,iconTouch:false,iconTheme:"tooltipster-icon",interactive:false,interactiveTolerance:350,multiple:false,offsetX:0,offsetY:0,onlyOne:false,position:"top",positionTracker:false,positionTrackerCallback:function(e){if(this.option("trigger")=="hover"&&this.option("autoClose")){this.hide()}},restoration:"current",speed:350,timer:0,theme:"tooltipster-default",touchDevices:true,trigger:"hover",updateAnimation:true};s.prototype={_init:function(){var t=this;if(n.querySelector){var r=null;if(t.$el.data("tooltipster-initialTitle")===undefined){r=t.$el.attr("title");if(r===undefined)r=null;t.$el.data("tooltipster-initialTitle",r)}if(t.options.content!==null){t._content_set(t.options.content)}else{t._content_set(r)}var i=t.options.functionInit.call(t.$el,t.$el,t.Content);if(typeof i!=="undefined")t._content_set(i);t.$el.removeAttr("title").addClass("tooltipstered");if(!u&&t.options.iconDesktop||u&&t.options.iconTouch){if(typeof t.options.icon==="string"){t.$elProxy=e('<span class="'+t.options.iconTheme+'"></span>');t.$elProxy.text(t.options.icon)}else{if(t.options.iconCloning)t.$elProxy=t.options.icon.clone(true);else t.$elProxy=t.options.icon}t.$elProxy.insertAfter(t.$el)}else{t.$elProxy=t.$el}if(t.options.trigger=="hover"){t.$elProxy.on("mouseenter."+t.namespace,function(){if(!f()||t.options.touchDevices){t.mouseIsOverProxy=true;t._show()}}).on("mouseleave."+t.namespace,function(){if(!f()||t.options.touchDevices){t.mouseIsOverProxy=false}});if(u&&t.options.touchDevices){t.$elProxy.on("touchstart."+t.namespace,function(){t._showNow()})}}else if(t.options.trigger=="click"){t.$elProxy.on("click."+t.namespace,function(){if(!f()||t.options.touchDevices){t._show()}})}}},_show:function(){var e=this;if(e.Status!="shown"&&e.Status!="appearing"){if(e.options.delay){e.timerShow=setTimeout(function(){if(e.options.trigger=="click"||e.options.trigger=="hover"&&e.mouseIsOverProxy){e._showNow()}},e.options.delay)}else e._showNow()}},_showNow:function(n){var r=this;r.options.functionBefore.call(r.$el,r.$el,function(){if(r.enabled&&r.Content!==null){if(n)r.callbacks.show.push(n);r.callbacks.hide=[];clearTimeout(r.timerShow);r.timerShow=null;clearTimeout(r.timerHide);r.timerHide=null;if(r.options.onlyOne){e(".tooltipstered").not(r.$el).each(function(t,n){var r=e(n),i=r.data("tooltipster-ns");e.each(i,function(e,t){var n=r.data(t),i=n.status(),s=n.option("autoClose");if(i!=="hidden"&&i!=="disappearing"&&s){n.hide()}})})}var i=function(){r.Status="shown";e.each(r.callbacks.show,function(e,t){t.call(r.$el)});r.callbacks.show=[]};if(r.Status!=="hidden"){var s=0;if(r.Status==="disappearing"){r.Status="appearing";if(l()){r.$tooltip.clearQueue().removeClass("tooltipster-dying").addClass("tooltipster-"+r.options.animation+"-show");if(r.options.speed>0)r.$tooltip.delay(r.options.speed);r.$tooltip.queue(i)}else{r.$tooltip.stop().fadeIn(i)}}else if(r.Status==="shown"){i()}}else{r.Status="appearing";var s=r.options.speed;r.bodyOverflowX=e("body").css("overflow-x");e("body").css("overflow-x","hidden");var o="tooltipster-"+r.options.animation,a="-webkit-transition-duration: "+r.options.speed+"ms; -webkit-animation-duration: "+r.options.speed+"ms; -moz-transition-duration: "+r.options.speed+"ms; -moz-animation-duration: "+r.options.speed+"ms; -o-transition-duration: "+r.options.speed+"ms; -o-animation-duration: "+r.options.speed+"ms; -ms-transition-duration: "+r.options.speed+"ms; -ms-animation-duration: "+r.options.speed+"ms; transition-duration: "+r.options.speed+"ms; animation-duration: "+r.options.speed+"ms;",f=r.options.minWidth?"min-width:"+Math.round(r.options.minWidth)+"px;":"",c=r.options.maxWidth?"max-width:"+Math.round(r.options.maxWidth)+"px;":"",h=r.options.interactive?"pointer-events: auto;":"";r.$tooltip=e('<div class="tooltipster-base '+r.options.theme+'" style="'+f+" "+c+" "+h+" "+a+'"><div class="tooltipster-content"></div></div>');if(l())r.$tooltip.addClass(o);r._content_insert();r.$tooltip.appendTo("body");r.reposition();r.options.functionReady.call(r.$el,r.$el,r.$tooltip);if(l()){r.$tooltip.addClass(o+"-show");if(r.options.speed>0)r.$tooltip.delay(r.options.speed);r.$tooltip.queue(i)}else{r.$tooltip.css("display","none").fadeIn(r.options.speed,i)}r._interval_set();e(t).on("scroll."+r.namespace+" resize."+r.namespace,function(){r.reposition()});if(r.options.autoClose){e("body").off("."+r.namespace);if(r.options.trigger=="hover"){if(u){setTimeout(function(){e("body").on("touchstart."+r.namespace,function(){r.hide()})},0)}if(r.options.interactive){if(u){r.$tooltip.on("touchstart."+r.namespace,function(e){e.stopPropagation()})}var p=null;r.$elProxy.add(r.$tooltip).on("mouseleave."+r.namespace+"-autoClose",function(){clearTimeout(p);p=setTimeout(function(){r.hide()},r.options.interactiveTolerance)}).on("mouseenter."+r.namespace+"-autoClose",function(){clearTimeout(p)})}else{r.$elProxy.on("mouseleave."+r.namespace+"-autoClose",function(){r.hide()})}if(r.options.hideOnClick){r.$elProxy.on("click."+r.namespace+"-autoClose",function(){r.hide()})}}else if(r.options.trigger=="click"){setTimeout(function(){e("body").on("click."+r.namespace+" touchstart."+r.namespace,function(){r.hide()})},0);if(r.options.interactive){r.$tooltip.on("click."+r.namespace+" touchstart."+r.namespace,function(e){e.stopPropagation()})}}}}if(r.options.timer>0){r.timerHide=setTimeout(function(){r.timerHide=null;r.hide()},r.options.timer+s)}}})},_interval_set:function(){var t=this;t.checkInterval=setInterval(function(){if(e("body").find(t.$el).length===0||e("body").find(t.$elProxy).length===0||t.Status=="hidden"||e("body").find(t.$tooltip).length===0){if(t.Status=="shown"||t.Status=="appearing")t.hide();t._interval_cancel()}else{if(t.options.positionTracker){var n=t._repositionInfo(t.$elProxy),r=false;if(o(n.dimension,t.elProxyPosition.dimension)){if(t.$elProxy.css("position")==="fixed"){if(o(n.position,t.elProxyPosition.position))r=true}else{if(o(n.offset,t.elProxyPosition.offset))r=true}}if(!r){t.reposition();t.options.positionTrackerCallback.call(t,t.$el)}}}},200)},_interval_cancel:function(){clearInterval(this.checkInterval);this.checkInterval=null},_content_set:function(e){if(typeof e==="object"&&e!==null&&this.options.contentCloning){e=e.clone(true)}this.Content=e},_content_insert:function(){var e=this,t=this.$tooltip.find(".tooltipster-content");if(typeof e.Content==="string"&&!e.options.contentAsHTML){t.text(e.Content)}else{t.empty().append(e.Content)}},_update:function(e){var t=this;t._content_set(e);if(t.Content!==null){if(t.Status!=="hidden"){t._content_insert();t.reposition();if(t.options.updateAnimation){if(l()){t.$tooltip.css({width:"","-webkit-transition":"all "+t.options.speed+"ms, width 0ms, height 0ms, left 0ms, top 0ms","-moz-transition":"all "+t.options.speed+"ms, width 0ms, height 0ms, left 0ms, top 0ms","-o-transition":"all "+t.options.speed+"ms, width 0ms, height 0ms, left 0ms, top 0ms","-ms-transition":"all "+t.options.speed+"ms, width 0ms, height 0ms, left 0ms, top 0ms",transition:"all "+t.options.speed+"ms, width 0ms, height 0ms, left 0ms, top 0ms"}).addClass("tooltipster-content-changing");setTimeout(function(){if(t.Status!="hidden"){t.$tooltip.removeClass("tooltipster-content-changing");setTimeout(function(){if(t.Status!=="hidden"){t.$tooltip.css({"-webkit-transition":t.options.speed+"ms","-moz-transition":t.options.speed+"ms","-o-transition":t.options.speed+"ms","-ms-transition":t.options.speed+"ms",transition:t.options.speed+"ms"})}},t.options.speed)}},t.options.speed)}else{t.$tooltip.fadeTo(t.options.speed,.5,function(){if(t.Status!="hidden"){t.$tooltip.fadeTo(t.options.speed,1)}})}}}}else{t.hide()}},_repositionInfo:function(e){return{dimension:{height:e.outerHeight(false),width:e.outerWidth(false)},offset:e.offset(),position:{left:parseInt(e.css("left")),top:parseInt(e.css("top"))}}},hide:function(n){var r=this;if(n)r.callbacks.hide.push(n);r.callbacks.show=[];clearTimeout(r.timerShow);r.timerShow=null;clearTimeout(r.timerHide);r.timerHide=null;var i=function(){e.each(r.callbacks.hide,function(e,t){t.call(r.$el)});r.callbacks.hide=[]};if(r.Status=="shown"||r.Status=="appearing"){r.Status="disappearing";var s=function(){r.Status="hidden";if(typeof r.Content=="object"&&r.Content!==null){r.Content.detach()}r.$tooltip.remove();r.$tooltip=null;e(t).off("."+r.namespace);e("body").off("."+r.namespace).css("overflow-x",r.bodyOverflowX);e("body").off("."+r.namespace);r.$elProxy.off("."+r.namespace+"-autoClose");r.options.functionAfter.call(r.$el,r.$el);i()};if(l()){r.$tooltip.clearQueue().removeClass("tooltipster-"+r.options.animation+"-show").addClass("tooltipster-dying");if(r.options.speed>0)r.$tooltip.delay(r.options.speed);r.$tooltip.queue(s)}else{r.$tooltip.stop().fadeOut(r.options.speed,s)}}else if(r.Status=="hidden"){i()}return r},show:function(e){this._showNow(e);return this},update:function(e){return this.content(e)},content:function(e){if(typeof e==="undefined"){return this.Content}else{this._update(e);return this}},reposition:function(){var n=this;if(e("body").find(n.$tooltip).length!==0){n.$tooltip.css("width","");n.elProxyPosition=n._repositionInfo(n.$elProxy);var r=null,i=e(t).width(),s=n.elProxyPosition,o=n.$tooltip.outerWidth(false),u=n.$tooltip.innerWidth()+1,a=n.$tooltip.outerHeight(false);if(n.$elProxy.is("area")){var f=n.$elProxy.attr("shape"),l=n.$elProxy.parent().attr("name"),c=e('img[usemap="#'+l+'"]'),h=c.offset().left,p=c.offset().top,d=n.$elProxy.attr("coords")!==undefined?n.$elProxy.attr("coords").split(","):undefined;if(f=="circle"){var v=parseInt(d[0]),m=parseInt(d[1]),g=parseInt(d[2]);s.dimension.height=g*2;s.dimension.width=g*2;s.offset.top=p+m-g;s.offset.left=h+v-g}else if(f=="rect"){var v=parseInt(d[0]),m=parseInt(d[1]),y=parseInt(d[2]),b=parseInt(d[3]);s.dimension.height=b-m;s.dimension.width=y-v;s.offset.top=p+m;s.offset.left=h+v}else if(f=="poly"){var w=[],E=[],S=0,x=0,T=0,N=0,C="even";for(var k=0;k<d.length;k++){var L=parseInt(d[k]);if(C=="even"){if(L>T){T=L;if(k===0){S=T}}if(L<S){S=L}C="odd"}else{if(L>N){N=L;if(k==1){x=N}}if(L<x){x=L}C="even"}}s.dimension.height=N-x;s.dimension.width=T-S;s.offset.top=p+x;s.offset.left=h+S}else{s.dimension.height=c.outerHeight(false);s.dimension.width=c.outerWidth(false);s.offset.top=p;s.offset.left=h}}var A=0,O=0,M=0,_=parseInt(n.options.offsetY),D=parseInt(n.options.offsetX),P=n.options.position;function H(){var n=e(t).scrollLeft();if(A-n<0){r=A-n;A=n}if(A+o-n>i){r=A-(i+n-o);A=i+n-o}}function B(n,r){if(s.offset.top-e(t).scrollTop()-a-_-12<0&&r.indexOf("top")>-1){P=n}if(s.offset.top+s.dimension.height+a+12+_>e(t).scrollTop()+e(t).height()&&r.indexOf("bottom")>-1){P=n;M=s.offset.top-a-_-12}}if(P=="top"){var j=s.offset.left+o-(s.offset.left+s.dimension.width);A=s.offset.left+D-j/2;M=s.offset.top-a-_-12;H();B("bottom","top")}if(P=="top-left"){A=s.offset.left+D;M=s.offset.top-a-_-12;H();B("bottom-left","top-left")}if(P=="top-right"){A=s.offset.left+s.dimension.width+D-o;M=s.offset.top-a-_-12;H();B("bottom-right","top-right")}if(P=="bottom"){var j=s.offset.left+o-(s.offset.left+s.dimension.width);A=s.offset.left-j/2+D;M=s.offset.top+s.dimension.height+_+12;H();B("top","bottom")}if(P=="bottom-left"){A=s.offset.left+D;M=s.offset.top+s.dimension.height+_+12;H();B("top-left","bottom-left")}if(P=="bottom-right"){A=s.offset.left+s.dimension.width+D-o;M=s.offset.top+s.dimension.height+_+12;H();B("top-right","bottom-right")}if(P=="left"){A=s.offset.left-D-o-12;O=s.offset.left+D+s.dimension.width+12;var F=s.offset.top+a-(s.offset.top+s.dimension.height);M=s.offset.top-F/2-_;if(A<0&&O+o>i){var I=parseFloat(n.$tooltip.css("border-width"))*2,q=o+A-I;n.$tooltip.css("width",q+"px");a=n.$tooltip.outerHeight(false);A=s.offset.left-D-q-12-I;F=s.offset.top+a-(s.offset.top+s.dimension.height);M=s.offset.top-F/2-_}else if(A<0){A=s.offset.left+D+s.dimension.width+12;r="left"}}if(P=="right"){A=s.offset.left+D+s.dimension.width+12;O=s.offset.left-D-o-12;var F=s.offset.top+a-(s.offset.top+s.dimension.height);M=s.offset.top-F/2-_;if(A+o>i&&O<0){var I=parseFloat(n.$tooltip.css("border-width"))*2,q=i-A-I;n.$tooltip.css("width",q+"px");a=n.$tooltip.outerHeight(false);F=s.offset.top+a-(s.offset.top+s.dimension.height);M=s.offset.top-F/2-_}else if(A+o>i){A=s.offset.left-D-o-12;r="right"}}if(n.options.arrow){var R="tooltipster-arrow-"+P;if(n.options.arrowColor.length<1){var U=n.$tooltip.css("background-color")}else{var U=n.options.arrowColor}if(!r){r=""}else if(r=="left"){R="tooltipster-arrow-right";r=""}else if(r=="right"){R="tooltipster-arrow-left";r=""}else{r="left:"+Math.round(r)+"px;"}if(P=="top"||P=="top-left"||P=="top-right"){var z=parseFloat(n.$tooltip.css("border-bottom-width")),W=n.$tooltip.css("border-bottom-color")}else if(P=="bottom"||P=="bottom-left"||P=="bottom-right"){var z=parseFloat(n.$tooltip.css("border-top-width")),W=n.$tooltip.css("border-top-color")}else if(P=="left"){var z=parseFloat(n.$tooltip.css("border-right-width")),W=n.$tooltip.css("border-right-color")}else if(P=="right"){var z=parseFloat(n.$tooltip.css("border-left-width")),W=n.$tooltip.css("border-left-color")}else{var z=parseFloat(n.$tooltip.css("border-bottom-width")),W=n.$tooltip.css("border-bottom-color")}if(z>1){z++}var X="";if(z!==0){var V="",J="border-color: "+W+";";if(R.indexOf("bottom")!==-1){V="margin-top: -"+Math.round(z)+"px;"}else if(R.indexOf("top")!==-1){V="margin-bottom: -"+Math.round(z)+"px;"}else if(R.indexOf("left")!==-1){V="margin-right: -"+Math.round(z)+"px;"}else if(R.indexOf("right")!==-1){V="margin-left: -"+Math.round(z)+"px;"}X='<span class="tooltipster-arrow-border" style="'+V+" "+J+';"></span>'}n.$tooltip.find(".tooltipster-arrow").remove();var K='<div class="'+R+' tooltipster-arrow" style="'+r+'">'+X+'<span style="border-color:'+U+';"></span></div>';n.$tooltip.append(K)}n.$tooltip.css({top:Math.round(M)+"px",left:Math.round(A)+"px"})}return n},enable:function(){this.enabled=true;return this},disable:function(){this.hide();this.enabled=false;return this},destroy:function(){var t=this;t.hide();if(t.$el[0]!==t.$elProxy[0]){t.$elProxy.remove()}t.$el.removeData(t.namespace).off("."+t.namespace);var n=t.$el.data("tooltipster-ns");if(n.length===1){var r=null;if(t.options.restoration==="previous"){r=t.$el.data("tooltipster-initialTitle")}else if(t.options.restoration==="current"){r=typeof t.Content==="string"?t.Content:e("<div></div>").append(t.Content).html()}if(r){t.$el.attr("title",r)}t.$el.removeClass("tooltipstered").removeData("tooltipster-ns").removeData("tooltipster-initialTitle")}else{n=e.grep(n,function(e,n){return e!==t.namespace});t.$el.data("tooltipster-ns",n)}return t},elementIcon:function(){return this.$el[0]!==this.$elProxy[0]?this.$elProxy[0]:undefined},elementTooltip:function(){return this.$tooltip?this.$tooltip[0]:undefined},option:function(e,t){if(typeof t=="undefined")return this.options[e];else{this.options[e]=t;return this}},status:function(){return this.Status}};e.fn[r]=function(){var t=arguments;if(this.length===0){if(typeof t[0]==="string"){var n=true;switch(t[0]){case"setDefaults":e.extend(i,t[1]);break;default:n=false;break}if(n)return true;else return this}else{return this}}else{if(typeof t[0]==="string"){var r="#*$~&";this.each(function(){var n=e(this).data("tooltipster-ns"),i=n?e(this).data(n[0]):null;if(i){if(typeof i[t[0]]==="function"){var s=i[t[0]](t[1],t[2])}else{throw new Error('Unknown method .tooltipster("'+t[0]+'")')}if(s!==i){r=s;return false}}else{throw new Error("You called Tooltipster's \""+t[0]+'" method on an uninitialized element')}});return r!=="#*$~&"?r:this}else{var o=[],u=t[0]&&typeof t[0].multiple!=="undefined",a=u&&t[0].multiple||!u&&i.multiple,f=t[0]&&typeof t[0].debug!=="undefined",l=f&&t[0].debug||!f&&i.debug;this.each(function(){var n=false,r=e(this).data("tooltipster-ns"),i=null;if(!r){n=true}else if(a){n=true}else if(l){console.log('Tooltipster: one or more tooltips are already attached to this element: ignoring. Use the "multiple" option to attach more tooltips.')}if(n){i=new s(this,t[0]);if(!r)r=[];r.push(i.namespace);e(this).data("tooltipster-ns",r);e(this).data(i.namespace,i)}o.push(i)});if(a)return o;else return this}}};var u=!!("ontouchstart"in t);var a=false;e("body").one("mousemove",function(){a=true})})(jQuery,window,document);
 
1
+ /* Tooltipster v3.3.0 */ ;
2
+ !function(t,o,e){function i(o,e){this.bodyOverflowX,this.callbacks={hide:[],show:[]},this.checkInterval=null,this.Content,this.$el=t(o),this.$elProxy,this.elProxyPosition,this.enabled=!0,this.options=t.extend({},l,e),this.mouseIsOverProxy=!1,this.namespace="tooltipster-"+Math.round(1e5*Math.random()),this.Status="hidden",this.timerHide=null,this.timerShow=null,this.$tooltip,this.options.iconTheme=this.options.iconTheme.replace(".",""),this.options.theme=this.options.theme.replace(".",""),this._init()}function n(o,e){var i=!0;return t.each(o,function(t,n){if(void 0===e[t]||o[t]!==e[t])return i=!1,!1}),i}function s(){return!p&&a}function r(){var t=(e.body||e.documentElement).style,o="transition";if("string"==typeof t[o])return!0;v=["Moz","Webkit","Khtml","O","ms"],o=o.charAt(0).toUpperCase()+o.substr(1);for(var i=0;i<v.length;i++)if("string"==typeof t[v[i]+o])return!0;return!1}var l={animation:"fade",arrow:!0,arrowColor:"",autoClose:!0,content:null,contentAsHTML:!1,contentCloning:!0,debug:!0,delay:200,minWidth:0,maxWidth:null,functionInit:function(t,o){},functionBefore:function(t,o){o()},functionReady:function(t,o){},functionAfter:function(t){},hideOnClick:!1,icon:"(?)",iconCloning:!0,iconDesktop:!1,iconTouch:!1,iconTheme:"tooltipster-icon",interactive:!1,interactiveTolerance:350,multiple:!1,offsetX:0,offsetY:0,onlyOne:!1,position:"top",positionTracker:!1,positionTrackerCallback:function(t){"hover"==this.option("trigger")&&this.option("autoClose")&&this.hide()},restoration:"current",speed:350,timer:0,theme:"tooltipster-default",touchDevices:!0,trigger:"hover",updateAnimation:!0};i.prototype={_init:function(){var o=this;if(e.querySelector){var i=null;void 0===o.$el.data("tooltipster-initialTitle")&&(void 0===(i=o.$el.attr("title"))&&(i=null),o.$el.data("tooltipster-initialTitle",i)),null!==o.options.content?o._content_set(o.options.content):o._content_set(i);var n=o.options.functionInit.call(o.$el,o.$el,o.Content);void 0!==n&&o._content_set(n),o.$el.removeAttr("title").addClass("tooltipstered"),!a&&o.options.iconDesktop||a&&o.options.iconTouch?("string"==typeof o.options.icon?(o.$elProxy=t('<span class="'+o.options.iconTheme+'"></span>'),o.$elProxy.text(o.options.icon)):o.options.iconCloning?o.$elProxy=o.options.icon.clone(!0):o.$elProxy=o.options.icon,o.$elProxy.insertAfter(o.$el)):o.$elProxy=o.$el,"hover"==o.options.trigger?(o.$elProxy.on("mouseenter."+o.namespace,function(){s()&&!o.options.touchDevices||(o.mouseIsOverProxy=!0,o._show())}).on("mouseleave."+o.namespace,function(){s()&&!o.options.touchDevices||(o.mouseIsOverProxy=!1)}),a&&o.options.touchDevices&&o.$elProxy.on("touchstart."+o.namespace,function(){o._showNow()})):"click"==o.options.trigger&&o.$elProxy.on("click."+o.namespace,function(){s()&&!o.options.touchDevices||o._show()})}},_show:function(){var t=this;"shown"!=t.Status&&"appearing"!=t.Status&&(t.options.delay?t.timerShow=setTimeout(function(){("click"==t.options.trigger||"hover"==t.options.trigger&&t.mouseIsOverProxy)&&t._showNow()},t.options.delay):t._showNow())},_showNow:function(e){var i=this;i.options.functionBefore.call(i.$el,i.$el,function(){if(i.enabled&&null!==i.Content){e&&i.callbacks.show.push(e),i.callbacks.hide=[],clearTimeout(i.timerShow),i.timerShow=null,clearTimeout(i.timerHide),i.timerHide=null,i.options.onlyOne&&t(".tooltipstered").not(i.$el).each(function(o,e){var i=t(e),n=i.data("tooltipster-ns");t.each(n,function(t,o){var e=i.data(o),n=e.status(),s=e.option("autoClose");"hidden"!==n&&"disappearing"!==n&&s&&e.hide()})});var n=function(){i.Status="shown",t.each(i.callbacks.show,function(t,o){o.call(i.$el)}),i.callbacks.show=[]};if("hidden"!==i.Status){"disappearing"===i.Status?(i.Status="appearing",r()?(i.$tooltip.clearQueue().removeClass("tooltipster-dying").addClass("tooltipster-"+i.options.animation+"-show"),i.options.speed>0&&i.$tooltip.delay(i.options.speed),i.$tooltip.queue(n)):i.$tooltip.stop().fadeIn(n)):"shown"===i.Status&&n()}else{i.Status="appearing";i.options.speed;i.bodyOverflowX=t("body").css("overflow-x"),t("body").css("overflow-x","hidden");var s="tooltipster-"+i.options.animation,l="-webkit-transition-duration: "+i.options.speed+"ms; -webkit-animation-duration: "+i.options.speed+"ms; -moz-transition-duration: "+i.options.speed+"ms; -moz-animation-duration: "+i.options.speed+"ms; -o-transition-duration: "+i.options.speed+"ms; -o-animation-duration: "+i.options.speed+"ms; -ms-transition-duration: "+i.options.speed+"ms; -ms-animation-duration: "+i.options.speed+"ms; transition-duration: "+i.options.speed+"ms; animation-duration: "+i.options.speed+"ms;",p=i.options.minWidth?"min-width:"+Math.round(i.options.minWidth)+"px;":"",f=i.options.maxWidth?"max-width:"+Math.round(i.options.maxWidth)+"px;":"",d=i.options.interactive?"pointer-events: auto;":"";if(i.$tooltip=t('<div class="tooltipster-base '+i.options.theme+'" style="'+p+" "+f+" "+d+" "+l+'"><div class="tooltipster-content"></div></div>'),r()&&i.$tooltip.addClass(s),i._content_insert(),i.$tooltip.appendTo("body"),i.reposition(),i.options.functionReady.call(i.$el,i.$el,i.$tooltip),r()?(i.$tooltip.addClass(s+"-show"),i.options.speed>0&&i.$tooltip.delay(i.options.speed),i.$tooltip.queue(n)):i.$tooltip.css("display","none").fadeIn(i.options.speed,n),i._interval_set(),t(o).on("scroll."+i.namespace+" resize."+i.namespace,function(){i.reposition()}),i.options.autoClose)if(t("body").off("."+i.namespace),"hover"==i.options.trigger){if(a&&setTimeout(function(){t("body").on("touchstart."+i.namespace,function(){i.hide()})},0),i.options.interactive){a&&i.$tooltip.on("touchstart."+i.namespace,function(t){t.stopPropagation()});var c=null;i.$elProxy.add(i.$tooltip).on("mouseleave."+i.namespace+"-autoClose",function(){clearTimeout(c),c=setTimeout(function(){i.hide()},0)}).on("mouseenter."+i.namespace+"-autoClose",function(){clearTimeout(c)})}else i.$elProxy.on("mouseleave."+i.namespace+"-autoClose",function(){i.hide()});i.options.hideOnClick&&i.$elProxy.on("click."+i.namespace+"-autoClose",function(){i.hide()})}else"click"==i.options.trigger&&(setTimeout(function(){t("body").on("click."+i.namespace+" touchstart."+i.namespace,function(){i.hide()})},0),i.options.interactive&&i.$tooltip.on("click."+i.namespace+" touchstart."+i.namespace,function(t){t.stopPropagation()}))}i.options.timer>0&&(i.timerHide=setTimeout(function(){i.timerHide=null,i.hide()},0))}})},_interval_set:function(){var o=this;o.checkInterval=setInterval(function(){if(0===t("body").find(o.$el).length||0===t("body").find(o.$elProxy).length||"hidden"==o.Status||0===t("body").find(o.$tooltip).length)"shown"!=o.Status&&"appearing"!=o.Status||o.hide(),o._interval_cancel();else if(o.options.positionTracker){var e=o._repositionInfo(o.$elProxy),i=!1;n(e.dimension,o.elProxyPosition.dimension)&&("fixed"===o.$elProxy.css("position")?n(e.position,o.elProxyPosition.position)&&(i=!0):n(e.offset,o.elProxyPosition.offset)&&(i=!0)),i||(o.reposition(),o.options.positionTrackerCallback.call(o,o.$el))}},200)},_interval_cancel:function(){clearInterval(this.checkInterval),this.checkInterval=null},_content_set:function(t){"object"==typeof t&&null!==t&&this.options.contentCloning&&(t=t.clone(!0)),this.Content=t},_content_insert:function(){var t=this,o=this.$tooltip.find(".tooltipster-content");"string"!=typeof t.Content||t.options.contentAsHTML?o.empty().append(t.Content):o.text(t.Content)},_update:function(t){var o=this;o._content_set(t),null!==o.Content?"hidden"!==o.Status&&(o._content_insert(),o.reposition(),o.options.updateAnimation&&(r()?(o.$tooltip.css({width:"","-webkit-transition":"all "+o.options.speed+"ms, width 0ms, height 0ms, left 0ms, top 0ms","-moz-transition":"all "+o.options.speed+"ms, width 0ms, height 0ms, left 0ms, top 0ms","-o-transition":"all "+o.options.speed+"ms, width 0ms, height 0ms, left 0ms, top 0ms","-ms-transition":"all "+o.options.speed+"ms, width 0ms, height 0ms, left 0ms, top 0ms",transition:"all "+o.options.speed+"ms, width 0ms, height 0ms, left 0ms, top 0ms"}).addClass("tooltipster-content-changing"),setTimeout(function(){"hidden"!=o.Status&&(o.$tooltip.removeClass("tooltipster-content-changing"),setTimeout(function(){"hidden"!==o.Status&&o.$tooltip.css({"-webkit-transition":o.options.speed+"ms","-moz-transition":o.options.speed+"ms","-o-transition":o.options.speed+"ms","-ms-transition":o.options.speed+"ms",transition:o.options.speed+"ms"})},o.options.speed))},o.options.speed)):o.$tooltip.fadeTo(o.options.speed,.5,function(){"hidden"!=o.Status&&o.$tooltip.fadeTo(o.options.speed,1)}))):o.hide()},_repositionInfo:function(t){return{dimension:{height:t.outerHeight(!1),width:t.outerWidth(!1)},offset:t.offset(),position:{left:parseInt(t.css("left")),top:parseInt(t.css("top"))}}},hide:function(e){var i=this;e&&i.callbacks.hide.push(e),i.callbacks.show=[],clearTimeout(i.timerShow),i.timerShow=null,clearTimeout(i.timerHide),i.timerHide=null;var n=function(){t.each(i.callbacks.hide,function(t,o){o.call(i.$el)}),i.callbacks.hide=[]};if("shown"==i.Status||"appearing"==i.Status){i.Status="disappearing";r()?(i.$tooltip.clearQueue().removeClass("tooltipster-"+i.options.animation+"-show").addClass("tooltipster-dying"),i.options.speed>0&&i.$tooltip.delay(),i.$tooltip.queue(function(){i.Status="hidden","object"==typeof i.Content&&null!==i.Content&&i.Content.detach(),i.$tooltip.remove(),i.$tooltip=null,t(o).off("."+i.namespace),t("body").off("."+i.namespace).css("overflow-x",i.bodyOverflowX),t("body").off("."+i.namespace),i.$elProxy.off("."+i.namespace+"-autoClose"),i.options.functionAfter.call(i.$el,i.$el),n()})):i.$tooltip.stop().fadeOut()}else"hidden"==i.Status&&n();return i},show:function(t){return this._showNow(t),this},update:function(t){return this.content(t)},content:function(t){return void 0===t?this.Content:(this._update(t),this)},reposition:function(){var e=this;if(0!==t("body").find(e.$tooltip).length){e.$tooltip.css("width",""),e.elProxyPosition=e._repositionInfo(e.$elProxy);var i=null,n=t(o).width(),s=e.elProxyPosition,r=e.$tooltip.outerWidth(!1),l=(e.$tooltip.innerWidth(),e.$tooltip.outerHeight(!1));if(e.$elProxy.is("area")){var a=e.$elProxy.attr("shape"),p=e.$elProxy.parent().attr("name"),f=t('img[usemap="#'+p+'"]'),d=f.offset().left,c=f.offset().top,h=void 0!==e.$elProxy.attr("coords")?e.$elProxy.attr("coords").split(","):void 0;if("circle"==a){var u=parseInt(h[0]),m=parseInt(h[1]),v=parseInt(h[2]);s.dimension.height=2*v,s.dimension.width=2*v,s.offset.top=c+m-v,s.offset.left=d+u-v}else if("rect"==a){u=parseInt(h[0]),m=parseInt(h[1]);var $=parseInt(h[2]),g=parseInt(h[3]);s.dimension.height=g-m,s.dimension.width=$-u,s.offset.top=c+m,s.offset.left=d+u}else if("poly"==a){for(var w=0,y=0,b=0,x=0,C="even",P=0;P<h.length;P++){var _=parseInt(h[P]);"even"==C?(_>b&&(b=_,0===P&&(w=b)),_<w&&(w=_),C="odd"):(_>x&&(x=_,1==P&&(y=x)),_<y&&(y=_),C="even")}s.dimension.height=x-y,s.dimension.width=b-w,s.offset.top=c+y,s.offset.left=d+w}else s.dimension.height=f.outerHeight(!1),s.dimension.width=f.outerWidth(!1),s.offset.top=c,s.offset.left=d}var k=0,T=0,I=0,S=parseInt(e.options.offsetY),O=parseInt(e.options.offsetX),H=e.options.position;function M(){var e=t(o).scrollLeft();k-e<0&&(i=k-e,k=e),k+r-e>n&&(i=k-(n+e-r),k=n+e-r)}function D(e,i){s.offset.top-t(o).scrollTop()-l-S-12<0&&i.indexOf("top")>-1&&(H=e),s.offset.top+s.dimension.height+l+12+S>t(o).scrollTop()+t(o).height()&&i.indexOf("bottom")>-1&&(H=e,I=s.offset.top-l-S-12)}if("top"==H){var W=s.offset.left+r-(s.offset.left+s.dimension.width);k=s.offset.left+O-W/2,I=s.offset.top-l-S-12,M(),D("bottom","top")}if("top-left"==H&&(k=s.offset.left-7+O,I=s.offset.top-l-S-12,M(),D("bottom-left","top-left")),"top-right"==H&&(k=s.offset.left+s.dimension.width+O-r,I=s.offset.top-l-S-12,M(),D("bottom-right","top-right")),"bottom"==H){W=s.offset.left+r-(s.offset.left+s.dimension.width);k=s.offset.left-W/2+O,I=s.offset.top+s.dimension.height+S+12,M(),D("top","bottom")}if("bottom-left"==H&&(k=s.offset.left-7+O,I=s.offset.top+s.dimension.height+S+12,M(),D("top-left","bottom-left")),"bottom-right"==H&&(k=s.offset.left+s.dimension.width+O-r,I=s.offset.top+s.dimension.height+S+12,M(),D("top-right","bottom-right")),"left"==H){k=s.offset.left-O-r-12,T=s.offset.left+O+s.dimension.width+12;var A=s.offset.top+l-(s.offset.top+s.dimension.height);if(I=s.offset.top-A/2-S,k<0&&T+r>n){var z=2*parseFloat(e.$tooltip.css("border-width")),F=r+k-z;e.$tooltip.css("width",F+"px"),l=e.$tooltip.outerHeight(!1),k=s.offset.left-O-F-12-z,A=s.offset.top+l-(s.offset.top+s.dimension.height),I=s.offset.top-A/2-S}else k<0&&(k=s.offset.left+O+s.dimension.width+12,i="left")}if("right"==H){k=s.offset.left+O+s.dimension.width+12,T=s.offset.left-O-r-12;A=s.offset.top+l-(s.offset.top+s.dimension.height);if(I=s.offset.top-A/2-S,k+r>n&&T<0){z=2*parseFloat(e.$tooltip.css("border-width")),F=n-k-z;e.$tooltip.css("width",F+"px"),l=e.$tooltip.outerHeight(!1),A=s.offset.top+l-(s.offset.top+s.dimension.height),I=s.offset.top-A/2-S}else k+r>n&&(k=s.offset.left-O-r-12,i="right")}if(e.options.arrow){var N="tooltipster-arrow-"+H;if(e.options.arrowColor.length<1)var X=e.$tooltip.css("background-color");else X=e.options.arrowColor;if(i?"left"==i?(N="tooltipster-arrow-right",i=""):"right"==i?(N="tooltipster-arrow-left",i=""):i="left:"+Math.round(i)+"px;":i="","top"==H||"top-left"==H||"top-right"==H)var q=parseFloat(e.$tooltip.css("border-bottom-width")),j=e.$tooltip.css("border-bottom-color");else if("bottom"==H||"bottom-left"==H||"bottom-right"==H)q=parseFloat(e.$tooltip.css("border-top-width")),j=e.$tooltip.css("border-top-color");else if("left"==H)q=parseFloat(e.$tooltip.css("border-right-width")),j=e.$tooltip.css("border-right-color");else if("right"==H)q=parseFloat(e.$tooltip.css("border-left-width")),j=e.$tooltip.css("border-left-color");else q=parseFloat(e.$tooltip.css("border-bottom-width")),j=e.$tooltip.css("border-bottom-color");q>1&&q++;var E="";if(0!==q){var L="",Q="border-color: "+j+";";-1!==N.indexOf("bottom")?L="margin-top: -"+Math.round(q)+"px;":-1!==N.indexOf("top")?L="margin-bottom: -"+Math.round(q)+"px;":-1!==N.indexOf("left")?L="margin-right: -"+Math.round(q)+"px;":-1!==N.indexOf("right")&&(L="margin-left: -"+Math.round(q)+"px;"),E='<span class="tooltipster-arrow-border" style="'+L+" "+Q+';"></span>'}e.$tooltip.find(".tooltipster-arrow").remove();var U='<div class="'+N+' tooltipster-arrow" style="'+i+'">'+E+'<span style="border-color:'+X+';"></span></div>';e.$tooltip.append(U)}e.$tooltip.css({top:Math.round(I)+"px",left:Math.round(k)+"px"})}return e},enable:function(){return this.enabled=!0,this},disable:function(){return this.hide(),this.enabled=!1,this},destroy:function(){var o=this;o.hide(),o.$el[0]!==o.$elProxy[0]&&o.$elProxy.remove(),o.$el.removeData(o.namespace).off("."+o.namespace);var e=o.$el.data("tooltipster-ns");if(1===e.length){var i=null;"previous"===o.options.restoration?i=o.$el.data("tooltipster-initialTitle"):"current"===o.options.restoration&&(i="string"==typeof o.Content?o.Content:t("<div></div>").append(o.Content).html()),i&&o.$el.attr("title",i),o.$el.removeClass("tooltipstered").removeData("tooltipster-ns").removeData("tooltipster-initialTitle")}else e=t.grep(e,function(t,e){return t!==o.namespace}),o.$el.data("tooltipster-ns",e);return o},elementIcon:function(){return this.$el[0]!==this.$elProxy[0]?this.$elProxy[0]:void 0},elementTooltip:function(){return this.$tooltip?this.$tooltip[0]:void 0},option:function(t,o){return void 0===o?this.options[t]:(this.options[t]=o,this)},status:function(){return this.Status}},t.fn.tooltipster=function(){var o=arguments;if(0===this.length){if("string"==typeof o[0]){var e=!0;switch(o[0]){case"setDefaults":t.extend(l,o[1]);break;default:e=!1}return!!e||this}return this}if("string"==typeof o[0]){var n="#*$~&";return this.each(function(){var e=t(this).data("tooltipster-ns"),i=e?t(this).data(e[0]):null;if(!i)throw new Error("You called Tooltipster's \""+o[0]+'" method on an uninitialized element');if("function"!=typeof i[o[0]])throw new Error('Unknown method .tooltipster("'+o[0]+'")');var s=i[o[0]](o[1],o[2]);if(s!==i)return n=s,!1}),"#*$~&"!==n?n:this}var s=[],r=o[0]&&void 0!==o[0].multiple,a=r&&o[0].multiple||!r&&l.multiple,p=o[0]&&void 0!==o[0].debug,f=p&&o[0].debug||!p&&l.debug;return this.each(function(){var e=!1,n=t(this).data("tooltipster-ns"),r=null;n?a?e=!0:f&&console.log('Tooltipster: one or more tooltips are already attached to this element: ignoring. Use the "multiple" option to attach more tooltips.'):e=!0,e&&(r=new i(this,o[0]),n||(n=[]),n.push(r.namespace),t(this).data("tooltipster-ns",n),t(this).data(r.namespace,r)),s.push(r)}),a?s:this};var a=!!("ontouchstart"in o),p=!1;t("body").one("mousemove",function(){p=!0})}(jQuery,window,document);
src/SupsysticTables/Core/assets/js/lib/dataTables.customExtensions.js CHANGED
@@ -90,6 +90,54 @@
90
  }
91
  return this;
92
  };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
 
94
  $.extend( $.fn.dataTableExt.oSort, {
95
  "natural-asc": function ( a, b ) {
90
  }
91
  return this;
92
  };
93
+ $.fn.dataTableExt.oApi.fnResetFakeRowspan = function (oSettings) {
94
+ if(oSettings) {
95
+ var displayRows = oSettings.aiDisplay,
96
+ mergedData = $(oSettings.nTable).data('merged');
97
+ if(!mergedData || mergedData.length == 0 || displayRows.length == 0) return this;
98
+
99
+ var rows = oSettings.aoData,
100
+ rowNums = {};
101
+ $.each(displayRows, function(index, rowNum) {
102
+ var cells = rows[rowNum].anCells;
103
+ rowNums[cells[0].getAttribute('data-y')] = rowNum;
104
+ for(var i = 0; i < cells.length; i++) {
105
+ $(cells[i]).css('display', '');
106
+ cells[i].setAttribute('rowspan', 1);
107
+ cells[i].setAttribute('colspan', 1);
108
+ }
109
+ });
110
+ $.each(mergedData, function(index, value) {
111
+ var firstRow = Number(value.row) + 1,
112
+ lastRow = firstRow + Number(value.rowspan) - 1,
113
+ colspan = Number(value.colspan),
114
+ firstCol = Number(value.col),
115
+ lastCol = firstCol + colspan - 1,
116
+ rowspan = 0;
117
+ for(var r = firstRow; r <= lastRow; r++) {
118
+ if(r in rowNums) {
119
+ if(rowspan == 0) {
120
+ firstRow = r;
121
+ }
122
+ for(var c = firstCol + (firstRow == r ? 1 : 0); c <= lastCol; c++) {
123
+ rows[rowNums[r]].anCells[c].style.display = 'none';
124
+ }
125
+ rowspan++;
126
+ }
127
+ }
128
+ if(rowspan > 0) {
129
+ var mergedCell = rows[rowNums[firstRow]].anCells[firstCol];
130
+ if(rowspan > 1) {
131
+ mergedCell.setAttribute('rowspan', rowspan);
132
+ }
133
+ if(colspan > 1) {
134
+ mergedCell.setAttribute('colspan', colspan);
135
+ }
136
+ }
137
+ });
138
+ }
139
+ return this;
140
+ };
141
 
142
  $.extend( $.fn.dataTableExt.oSort, {
143
  "natural-asc": function ( a, b ) {
src/SupsysticTables/Core/assets/js/lib/jquery.dataTables.min.js CHANGED
@@ -75,8 +75,8 @@ d);if(b)D.console&&console.log&&console.log(c);else if(b=m.ext,b=b.sErrMode||b.e
75
  e&&h.isArray(d)?d.slice():d);return a}function Wa(a,b,c){h(a).bind("click.DT",b,function(b){a.blur();c(b)}).bind("keypress.DT",b,function(a){13===a.which&&(a.preventDefault(),c(a))}).bind("selectstart.DT",function(){return!1})}function z(a,b,c,d){c&&a[b].push({fn:c,sName:d})}function u(a,b,c,d){var e=[];b&&(e=h.map(a[b].slice().reverse(),function(b){return b.fn.apply(a.oInstance,d)}));null!==c&&(b=h.Event(c+".dt"),h(a.nTable).trigger(b,d),e.push(b.result));return e}function Sa(a){var b=a._iDisplayStart,
76
  c=a.fnDisplayEnd(),d=a._iDisplayLength;b>=c&&(b=c-d);b-=b%d;if(-1===d||0>b)b=0;a._iDisplayStart=b}function Na(a,b){var c=a.renderer,d=m.ext.renderer[b];return h.isPlainObject(c)&&c[b]?d[c[b]]||d._:"string"===typeof c?d[c]||d._:d._}function y(a){return a.oFeatures.bServerSide?"ssp":a.ajax||a.sAjaxSource?"ajax":"dom"}function ya(a,b){var c=[],c=Mb.numbers_length,d=Math.floor(c/2);b<=c?c=W(0,b):a<=d?(c=W(0,c-2),c.push("ellipsis"),c.push(b-1)):(a>=b-1-d?c=W(b-(c-2),b):(c=W(a-d+2,a+d-1),c.push("ellipsis"),
77
  c.push(b-1)),c.splice(0,0,"ellipsis"),c.splice(0,0,0));c.DT_el="span";return c}function db(a){h.each({num:function(b){return za(b,a)},"num-fmt":function(b){return za(b,a,Xa)},"html-num":function(b){return za(b,a,Aa)},"html-num-fmt":function(b){return za(b,a,Aa,Xa)}},function(b,c){v.type.order[b+a+"-pre"]=c;b.match(/^html\-/)&&(v.type.search[b+a]=v.type.search.html)})}function Nb(a){return function(){var b=[xa(this[m.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return m.ext.internal[a].apply(this,
78
- b)}}var m=function(a){this.$=function(a,b){return this.api(!0).$(a,b)};this._=function(a,b){return this.api(!0).rows(a,b).data()};this.api=function(a){return a?new r(xa(this[v.iApiIndex])):new r(this)};this.fnAddData=function(a,b){var c=this.api(!0),d=h.isArray(a)&&(h.isArray(a[0])||h.isPlainObject(a[0]))?c.rows.add(a):c.row.add(a);(b===k||b)&&c.draw();return d.flatten().toArray()};this.fnAdjustColumnSizing=function(a){var b=this.api(!0).columns.adjust(),c=b.settings()[0],d=c.oScroll;a===k||a?b.draw(!1):
79
- (""!==d.sX||""!==d.sY)&&ka(c)};this.fnClearTable=function(a){var b=this.api(!0).clear();(a===k||a)&&b.draw()};this.fnClose=function(a){this.api(!0).row(a).child.hide()};this.fnDeleteRow=function(a,b,c){var d=this.api(!0),a=d.rows(a),e=a.settings()[0],h=e.aoData[a[0][0]];a.remove();b&&b.call(this,e,h);(c===k||c)&&d.draw();return h};this.fnDestroy=function(a){this.api(!0).destroy(a)};this.fnDraw=function(a){this.api(!0).draw(a)};this.fnFilter=function(a,b,c,d,e,h){e=this.api(!0);null===b||b===k?e.search(a,
80
  c,d,h):e.column(b).search(a,c,d,h);e.draw()};this.fnGetData=function(a,b){var c=this.api(!0);if(a!==k){var d=a.nodeName?a.nodeName.toLowerCase():"";return b!==k||"td"==d||"th"==d?c.cell(a,b).data():c.row(a).data()||null}return c.data().toArray()};this.fnGetNodes=function(a){var b=this.api(!0);return a!==k?b.row(a).node():b.rows().nodes().flatten().toArray()};this.fnGetPosition=function(a){var b=this.api(!0),c=a.nodeName.toUpperCase();return"TR"==c?b.row(a).index():"TD"==c||"TH"==c?(a=b.cell(a).index(),
81
  [a.row,a.columnVisible,a.column]):null};this.fnIsOpen=function(a){return this.api(!0).row(a).child.isShown()};this.fnOpen=function(a,b,c){return this.api(!0).row(a).child(b,c).show().child()[0]};this.fnPageChange=function(a,b){var c=this.api(!0).page(a);(b===k||b)&&c.draw(!1)};this.fnSetColumnVis=function(a,b,c){a=this.api(!0).column(a).visible(b);(c===k||c)&&a.columns.adjust().draw()};this.fnSettings=function(){return xa(this[v.iApiIndex])};this.fnSort=function(a){this.api(!0).order(a).draw()};this.fnSortListener=
82
  function(a,b,c){this.api(!0).order.listener(a,b,c)};this.fnUpdate=function(a,b,c,d,e){var h=this.api(!0);c===k||null===c?h.row(b).data(a):h.cell(b,c).data(a);(e===k||e)&&h.columns.adjust();(d===k||d)&&h.draw();return 0};this.fnVersionCheck=v.fnVersionCheck;var b=this,c=a===k,d=this.length;c&&(a={});this.oApi=this.internal=v.internal;for(var e in m.ext.internal)e&&(this[e]=Nb(e));this.each(function(){var e={},e=1<d?Lb(e,a,!0):a,g=0,j,i=this.getAttribute("id"),n=!1,l=m.defaults,q=h(this);if("table"!=
75
  e&&h.isArray(d)?d.slice():d);return a}function Wa(a,b,c){h(a).bind("click.DT",b,function(b){a.blur();c(b)}).bind("keypress.DT",b,function(a){13===a.which&&(a.preventDefault(),c(a))}).bind("selectstart.DT",function(){return!1})}function z(a,b,c,d){c&&a[b].push({fn:c,sName:d})}function u(a,b,c,d){var e=[];b&&(e=h.map(a[b].slice().reverse(),function(b){return b.fn.apply(a.oInstance,d)}));null!==c&&(b=h.Event(c+".dt"),h(a.nTable).trigger(b,d),e.push(b.result));return e}function Sa(a){var b=a._iDisplayStart,
76
  c=a.fnDisplayEnd(),d=a._iDisplayLength;b>=c&&(b=c-d);b-=b%d;if(-1===d||0>b)b=0;a._iDisplayStart=b}function Na(a,b){var c=a.renderer,d=m.ext.renderer[b];return h.isPlainObject(c)&&c[b]?d[c[b]]||d._:"string"===typeof c?d[c]||d._:d._}function y(a){return a.oFeatures.bServerSide?"ssp":a.ajax||a.sAjaxSource?"ajax":"dom"}function ya(a,b){var c=[],c=Mb.numbers_length,d=Math.floor(c/2);b<=c?c=W(0,b):a<=d?(c=W(0,c-2),c.push("ellipsis"),c.push(b-1)):(a>=b-1-d?c=W(b-(c-2),b):(c=W(a-d+2,a+d-1),c.push("ellipsis"),
77
  c.push(b-1)),c.splice(0,0,"ellipsis"),c.splice(0,0,0));c.DT_el="span";return c}function db(a){h.each({num:function(b){return za(b,a)},"num-fmt":function(b){return za(b,a,Xa)},"html-num":function(b){return za(b,a,Aa)},"html-num-fmt":function(b){return za(b,a,Aa,Xa)}},function(b,c){v.type.order[b+a+"-pre"]=c;b.match(/^html\-/)&&(v.type.search[b+a]=v.type.search.html)})}function Nb(a){return function(){var b=[xa(this[m.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return m.ext.internal[a].apply(this,
78
+ b)}}var m=function(a){this.$=function(a,b){return this.api(!0).$(a,b)};this._=function(a,b){return this.api(!0).rows(a,b).data()};this.api=function(a){return a?new r(xa(this[v.iApiIndex])):new r(this)};this.fnAddData=function(a,b){var c=this.api(!0),d=h.isArray(a)&&(h.isArray(a[0])||h.isPlainObject(a[0]))?c.rows.add(a):c.row.add(a);(b===k||b)&&c.draw();return d.flatten().toArray()};this.fnAdjustColumnSizing=function(a){var b=this.api(!0).columns.adjust(),c=b.settings()[0],d=null;if((typeof(c)!=='undefined')&&(typeof(c.oScroll)!=='undefined')){d=c.oScroll;}a===k||a?b.draw(!1):
79
+ ((d!=null)&&(""!==d.sX||""!==d.sY))&&ka(c)};this.fnClearTable=function(a){var b=this.api(!0).clear();(a===k||a)&&b.draw()};this.fnClose=function(a){this.api(!0).row(a).child.hide()};this.fnDeleteRow=function(a,b,c){var d=this.api(!0),a=d.rows(a),e=a.settings()[0],h=e.aoData[a[0][0]];a.remove();b&&b.call(this,e,h);(c===k||c)&&d.draw();return h};this.fnDestroy=function(a){this.api(!0).destroy(a)};this.fnDraw=function(a){this.api(!0).draw(a)};this.fnFilter=function(a,b,c,d,e,h){e=this.api(!0);null===b||b===k?e.search(a,
80
  c,d,h):e.column(b).search(a,c,d,h);e.draw()};this.fnGetData=function(a,b){var c=this.api(!0);if(a!==k){var d=a.nodeName?a.nodeName.toLowerCase():"";return b!==k||"td"==d||"th"==d?c.cell(a,b).data():c.row(a).data()||null}return c.data().toArray()};this.fnGetNodes=function(a){var b=this.api(!0);return a!==k?b.row(a).node():b.rows().nodes().flatten().toArray()};this.fnGetPosition=function(a){var b=this.api(!0),c=a.nodeName.toUpperCase();return"TR"==c?b.row(a).index():"TD"==c||"TH"==c?(a=b.cell(a).index(),
81
  [a.row,a.columnVisible,a.column]):null};this.fnIsOpen=function(a){return this.api(!0).row(a).child.isShown()};this.fnOpen=function(a,b,c){return this.api(!0).row(a).child(b,c).show().child()[0]};this.fnPageChange=function(a,b){var c=this.api(!0).page(a);(b===k||b)&&c.draw(!1)};this.fnSetColumnVis=function(a,b,c){a=this.api(!0).column(a).visible(b);(c===k||c)&&a.columns.adjust().draw()};this.fnSettings=function(){return xa(this[v.iApiIndex])};this.fnSort=function(a){this.api(!0).order(a).draw()};this.fnSortListener=
82
  function(a,b,c){this.api(!0).order.listener(a,b,c)};this.fnUpdate=function(a,b,c,d,e){var h=this.api(!0);c===k||null===c?h.row(b).data(a):h.cell(b,c).data(a);(e===k||e)&&h.columns.adjust();(d===k||d)&&h.draw();return 0};this.fnVersionCheck=v.fnVersionCheck;var b=this,c=a===k,d=this.length;c&&(a={});this.oApi=this.internal=v.internal;for(var e in m.ext.internal)e&&(this[e]=Nb(e));this.each(function(){var e={},e=1<d?Lb(e,a,!0):a,g=0,j,i=this.getAttribute("id"),n=!1,l=m.defaults,q=h(this);if("table"!=
src/SupsysticTables/Diagram/views/partials/tabContent.twig CHANGED
@@ -5,9 +5,11 @@
5
  {% import '@ui/tooltip.twig' as tooltip %}
6
  <div class="col-xs-12">
7
  <h3 style="display:inline-block;">
8
- {{ environment.translate('Diagrams') }}&nbsp;
9
- {{ tooltip.icon('The Data Table Generator contains all the types of diagrams you need. Сreate, manage and embed interactive charts into your WordPress posts and pages. You can preview the diagram right from a tab on the plugin screen. <a target="_blank" href="https://supsystic.com/example/table-with-diagram-example/"></br>Read more</a>' | raw, 'top', true)}}
10
  </h3>
 
 
 
11
  </br>
12
  <a href="{{ url }}" class="button button-hero" target="_blank">
13
  {{ environment.translate('Get PRO') }}
5
  {% import '@ui/tooltip.twig' as tooltip %}
6
  <div class="col-xs-12">
7
  <h3 style="display:inline-block;">
8
+ {{ environment.translate('Diagrams') }}
 
9
  </h3>
10
+ <div class="description" style="font-size: 16px;">
11
+ {{ environment.translate('The Data Table Generator contains all the types of diagrams you need. Сreate, manage and embed interactive charts into your WordPress posts and pages. You can preview the diagram right from a tab on the plugin screen.') }} {{ '<a target="_blank" href="https://supsystic.com/example/table-with-diagram-example/"></br>Read more</a>' | raw }}
12
+ </div>
13
  </br>
14
  <a href="{{ url }}" class="button button-hero" target="_blank">
15
  {{ environment.translate('Get PRO') }}
src/SupsysticTables/Overview/assets/css/overview.css CHANGED
@@ -128,4 +128,32 @@
128
  }
129
  #contact-form-dialog a:focus {
130
  outline: none;
131
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  }
129
  #contact-form-dialog a:focus {
130
  outline: none;
131
+ }
132
+
133
+ .supsystic-overview .faq-title,
134
+ .supsystic-overview-news h3 {
135
+ padding: 0px;
136
+ margin-bottom: 4px;
137
+ background-color: transparent;
138
+ }
139
+ .supsystic-overview-news-container h3 {
140
+ border-bottom: 1px solid #d6d6d6;
141
+ padding-bottom: 10px;
142
+ margin-bottom: 20px;
143
+ }
144
+ .supsystic-overview-news h2, .supsystic-overview-news h3 {
145
+ font-size: 1em;
146
+ font-weight: bold;
147
+ border-bottom: none;
148
+ padding:0px;
149
+ margin:0px;
150
+ margin-top:20px;
151
+ }
152
+ .supsystic-overview-news h2, .supsystic-overview-news h3:first-child {
153
+ margin-top:0px;
154
+ }
155
+ .supsystic-overview .supsystic-overview-news p {
156
+ font-size:14px;
157
+ font-weight: 600;
158
+ margin:0px;
159
+ }
src/SupsysticTables/Promo/Controller.php CHANGED
@@ -34,5 +34,20 @@ class SupsysticTables_Promo_Controller extends SupsysticTables_Core_BaseControll
34
  update_user_meta(get_current_user_id(), 'supsystic-tables-tutorial_was_showed', 0);
35
  return $this->redirect($this->generateUrl('overview', 'index', array('supsystic_tutorial' => 'begin')));
36
  }
37
- }
38
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  update_user_meta(get_current_user_id(), 'supsystic-tables-tutorial_was_showed', 0);
35
  return $this->redirect($this->generateUrl('overview', 'index', array('supsystic_tutorial' => 'begin')));
36
  }
37
+
38
+ /**
39
+ * Just let us know. Love is Sharing
40
+ * @param Rsc_Http_Request $request
41
+ * @return Rsc_Http_Response
42
+ */
43
+ public function saveDeactivateDataAction(Rsc_Http_Request $request)
44
+ {
45
+ $this->getModel('promo')->saveDeactivateData(array(
46
+ 'deactivate_reason' => $request->query->get('deactivate_reason'),
47
+ 'better_plugin' => $request->query->get('better_plugin'),
48
+ 'other' => $request->query->get('other'),
49
+ ));
50
+
51
+ return $this->ajaxSuccess();
52
+ }
53
+ }
src/SupsysticTables/Promo/Model/Promo.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class SupsysticTables_Promo_Model_Promo extends SupsysticTables_Core_BaseModel
3
+ {
4
+ private $_bigCli;
5
+
6
+ public function firstRun() {
7
+ $this->_bigStatAdd('Welcome Show');
8
+ update_option($this->getPrefix(). 'plug_welcome_show', time()); // Remember this
9
+ }
10
+
11
+ private function _getBigStatClient() {
12
+ if(!$this->_bigCli) {
13
+ $path = $this->environment->getConfig()->get('plugin_source'). '/'
14
+ . $this->environment->getConfig()->get('plugin_prefix'). '/'
15
+ . 'Promo/Model/classes/lib/Mixpanel.php';
16
+ if(!class_exists('Mixpanel') && is_file($path)) {
17
+ require_once($path);
18
+ }
19
+ if(class_exists('Mixpanel')) {
20
+ $opts = array();
21
+ if(!function_exists('curl_init')) {
22
+ $opts['consumer'] = 'socket';
23
+ }
24
+ if(class_exists('Mixpanel')) {
25
+ $this->_bigCli = Mixpanel::getInstance("463025c1f6d80420eb95689073ce1b7a", $opts);
26
+ }
27
+ }
28
+ }
29
+ return $this->_bigCli;
30
+ }
31
+ private function _bigStatAdd( $key, $properties = array() ) {
32
+ if(function_exists('json_encode')) {
33
+ $this->_getBigStatClient();
34
+ if($this->_bigCli) {
35
+ $this->_bigCli->track( $key, $properties );
36
+ }
37
+ }
38
+ }
39
+
40
+ public function saveDeactivateData( $d ) {
41
+ $deactivateParams = array();
42
+ $reasonsLabels = array(
43
+ 'not_working' => 'Not working',
44
+ 'found_better' => 'Found better',
45
+ 'not_need' => 'Not need',
46
+ 'temporary' => 'Temporary',
47
+ 'other' => 'Other',
48
+ );
49
+ $deactivateParams['Reason'] = isset($d['deactivate_reason']) && $d['deactivate_reason']
50
+ ? $reasonsLabels[ $d['deactivate_reason'] ]
51
+ : 'No reason';
52
+ if(isset($d['deactivate_reason']) && $d['deactivate_reason']) {
53
+ switch( $d['deactivate_reason'] ) {
54
+ case 'found_better':
55
+ $deactivateParams['Better plugin'] = $d['better_plugin'];
56
+ break;
57
+ case 'other':
58
+ $deactivateParams['Other'] = $d['other'];
59
+ break;
60
+ }
61
+ }
62
+ $this->_bigStatAdd('Deactivated', $deactivateParams);
63
+ $startUsage = get_option($this->getPrefix(). 'plug_welcome_show');
64
+ if($startUsage) {
65
+ $usedTime = time() - $startUsage;
66
+ $this->_bigStatAdd('Used Time', array(
67
+ 'Seconds' => $usedTime,
68
+ 'Hours' => round($usedTime / 60 / 60),
69
+ 'Days' => round($usedTime / 60 / 60 / 24)
70
+ ));
71
+ }
72
+ return true;
73
+ }
74
+ }
src/SupsysticTables/Promo/Model/classes/lib/Base/MixpanelBase.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * This a Base class which all Mixpanel classes extend from to provide some very basic
5
+ * debugging and logging functionality. It also serves to persist $_options across the library.
6
+ *
7
+ */
8
+ class Base_MixpanelBase {
9
+
10
+
11
+ /**
12
+ * Default options that can be overridden via the $options constructor arg
13
+ * @var array
14
+ */
15
+ private $_defaults = array(
16
+ "max_batch_size" => 50, // the max batch size Mixpanel will accept is 50,
17
+ "max_queue_size" => 1000, // the max num of items to hold in memory before flushing
18
+ "debug" => true, // enable/disable debug mode
19
+ "consumer" => "curl", // which consumer to use
20
+ "host" => "api.mixpanel.com", // the host name for api calls
21
+ "events_endpoint" => "/track", // host relative endpoint for events
22
+ "people_endpoint" => "/engage", // host relative endpoint for people updates
23
+ "use_ssl" => true, // use ssl when available
24
+ "error_callback" => null // callback to use on consumption failures
25
+ );
26
+
27
+
28
+ /**
29
+ * An array of options to be used by the Mixpanel library.
30
+ * @var array
31
+ */
32
+ protected $_options = array();
33
+
34
+
35
+ /**
36
+ * Construct a new MixpanelBase object and merge custom options with defaults
37
+ * @param array $options
38
+ */
39
+ public function __construct($options = array()) {
40
+ $options = array_merge($this->_defaults, $options);
41
+ $this->_options = $options;
42
+ }
43
+
44
+
45
+ /**
46
+ * Log a message to PHP's error log
47
+ * @param $msg
48
+ */
49
+ protected function _log($msg) {
50
+ // No logs for us
51
+ return;
52
+ $arr = debug_backtrace();
53
+ $class = $arr[0]['class'];
54
+ $line = $arr[0]['line'];
55
+ error_log ( "[ $class - line $line ] : " . $msg );
56
+ }
57
+
58
+
59
+ /**
60
+ * Returns true if in debug mode, false if in production mode
61
+ * @return bool
62
+ */
63
+ protected function _debug() {
64
+ return array_key_exists("debug", $this->_options) && $this->_options["debug"] == true;
65
+ }
66
+
67
+ }
src/SupsysticTables/Promo/Model/classes/lib/ConsumerStrategies/AbstractConsumer.php ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/../Base/MixpanelBase.php");
3
+
4
+ /**
5
+ * Provides some base methods for use by a Consumer implementation
6
+ */
7
+ abstract class ConsumerStrategies_AbstractConsumer extends Base_MixpanelBase {
8
+
9
+ /**
10
+ * Creates a new AbstractConsumer
11
+ * @param array $options
12
+ */
13
+ function __construct($options = array()) {
14
+
15
+ parent::__construct($options);
16
+
17
+ if ($this->_debug()) {
18
+ $this->_log("Instantiated new Consumer");
19
+ }
20
+
21
+ }
22
+
23
+ /**
24
+ * Encode an array to be persisted
25
+ * @param array $params
26
+ * @return string
27
+ */
28
+ protected function _encode($params) {
29
+ return base64_encode(json_encode($params));
30
+ }
31
+
32
+ /**
33
+ * Handles errors that occur in a consumer
34
+ * @param $code
35
+ * @param $msg
36
+ */
37
+ protected function _handleError($code, $msg) {
38
+ if (isset($this->_options['error_callback'])) {
39
+ $handler = $this->_options['error_callback'];
40
+ call_user_func($handler, $code, $msg);
41
+ }
42
+
43
+ if ($this->_debug()) {
44
+ $arr = debug_backtrace();
45
+ $class = get_class($arr[0]['object']);
46
+ $line = $arr[0]['line'];
47
+ error_log ( "[ $class - line $line ] : " . print_r($msg, true) );
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Persist a batch of messages in whatever way the implementer sees fit
53
+ * @param array $batch an array of messages to consume
54
+ * @return boolean success or fail
55
+ */
56
+ abstract function persist($batch);
57
+ }
src/SupsysticTables/Promo/Model/classes/lib/ConsumerStrategies/CurlConsumer.php ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/AbstractConsumer.php");
3
+
4
+ /**
5
+ * Consumes messages and sends them to a host/endpoint using cURL
6
+ */
7
+ class ConsumerStrategies_CurlConsumer extends ConsumerStrategies_AbstractConsumer {
8
+
9
+ /**
10
+ * @var string the host to connect to (e.g. api.mixpanel.com)
11
+ */
12
+ protected $_host;
13
+
14
+
15
+ /**
16
+ * @var string the host-relative endpoint to write to (e.g. /engage)
17
+ */
18
+ protected $_endpoint;
19
+
20
+
21
+ /**
22
+ * @var int connect_timeout The number of seconds to wait while trying to connect. Default is 5 seconds.
23
+ */
24
+ protected $_connect_timeout;
25
+
26
+
27
+ /**
28
+ * @var int timeout The maximum number of seconds to allow cURL call to execute. Default is 30 seconds.
29
+ */
30
+ protected $_timeout;
31
+
32
+
33
+ /**
34
+ * @var string the protocol to use for the cURL connection
35
+ */
36
+ protected $_protocol;
37
+
38
+
39
+ /**
40
+ * @var bool|null true to fork the cURL process (using exec) or false to use PHP's cURL extension. false by default
41
+ */
42
+ protected $_fork = null;
43
+
44
+
45
+ /**
46
+ * Creates a new CurlConsumer and assigns properties from the $options array
47
+ * @param array $options
48
+ * @throws Exception
49
+ */
50
+ function __construct($options) {
51
+ parent::__construct($options);
52
+
53
+ $this->_host = $options['host'];
54
+ $this->_endpoint = $options['endpoint'];
55
+ $this->_connect_timeout = array_key_exists('connect_timeout', $options) ? $options['connect_timeout'] : 5;
56
+ $this->_timeout = array_key_exists('timeout', $options) ? $options['timeout'] : 30;
57
+ $this->_protocol = array_key_exists('use_ssl', $options) && $options['use_ssl'] == true ? "https" : "http";
58
+ $this->_fork = array_key_exists('fork', $options) ? ($options['fork'] == true) : false;
59
+
60
+ // ensure the environment is workable for the given settings
61
+ if ($this->_fork == true) {
62
+ $exists = function_exists('exec');
63
+ if (!$exists) {
64
+ throw new Exception('The "exec" function must exist to use the cURL consumer in "fork" mode. Try setting fork = false or use another consumer.');
65
+ }
66
+ $disabled = explode(', ', ini_get('disable_functions'));
67
+ $enabled = !in_array('exec', $disabled);
68
+ if (!$enabled) {
69
+ throw new Exception('The "exec" function must be enabled to use the cURL consumer in "fork" mode. Try setting fork = false or use another consumer.');
70
+ }
71
+ } else {
72
+ if (!function_exists('curl_init')) {
73
+ throw new Exception('The cURL PHP extension is required to use the cURL consumer with fork = false. Try setting fork = true or use another consumer.');
74
+ }
75
+ }
76
+ }
77
+
78
+
79
+ /**
80
+ * Write to the given host/endpoint using either a forked cURL process or using PHP's cURL extension
81
+ * @param array $batch
82
+ * @return bool
83
+ */
84
+ public function persist($batch) {
85
+ if (count($batch) > 0) {
86
+ $data = "data=" . $this->_encode($batch);
87
+ $url = $this->_protocol . "://" . $this->_host . $this->_endpoint;
88
+ if ($this->_fork) {
89
+ return $this->_execute_forked($url, $data);
90
+ } else {
91
+ return $this->_execute($url, $data);
92
+ }
93
+ } else {
94
+ return true;
95
+ }
96
+ }
97
+
98
+
99
+ /**
100
+ * Write using the cURL php extension
101
+ * @param $url
102
+ * @param $data
103
+ * @return bool
104
+ */
105
+ protected function _execute($url, $data) {
106
+ if ($this->_debug()) {
107
+ $this->_log("Making blocking cURL call to $url");
108
+ }
109
+
110
+ $ch = curl_init();
111
+ curl_setopt($ch, CURLOPT_URL, $url);
112
+ curl_setopt($ch, CURLOPT_HEADER, 0);
113
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->_connect_timeout);
114
+ curl_setopt($ch, CURLOPT_TIMEOUT, $this->_timeout);
115
+ curl_setopt($ch, CURLOPT_POST, 1);
116
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
117
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
118
+ $response = curl_exec($ch);
119
+ if (false === $response) {
120
+ $curl_error = curl_error($ch);
121
+ $curl_errno = curl_errno($ch);
122
+ curl_close($ch);
123
+ $this->_handleError($curl_errno, $curl_error);
124
+ return false;
125
+ } else {
126
+ curl_close($ch);
127
+ if (trim($response) == "1") {
128
+ return true;
129
+ } else {
130
+ $this->_handleError(0, $response);
131
+ return false;
132
+ }
133
+ }
134
+ }
135
+
136
+
137
+ /**
138
+ * Write using a forked cURL process
139
+ * @param $url
140
+ * @param $data
141
+ * @return bool
142
+ */
143
+ protected function _execute_forked($url, $data) {
144
+
145
+ if ($this->_debug()) {
146
+ $this->_log("Making forked cURL call to $url");
147
+ }
148
+
149
+ $exec = 'curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d ' . $data . ' "' . $url . '"';
150
+
151
+ if(!$this->_debug()) {
152
+ $exec .= " >/dev/null 2>&1 &";
153
+ }
154
+
155
+ exec($exec, $output, $return_var);
156
+
157
+ if ($return_var != 0) {
158
+ $this->_handleError($return_var, $output);
159
+ }
160
+
161
+ return $return_var == 0;
162
+ }
163
+
164
+ /**
165
+ * @return int
166
+ */
167
+ public function getConnectTimeout()
168
+ {
169
+ return $this->_connect_timeout;
170
+ }
171
+
172
+ /**
173
+ * @return string
174
+ */
175
+ public function getEndpoint()
176
+ {
177
+ return $this->_endpoint;
178
+ }
179
+
180
+ /**
181
+ * @return bool|null
182
+ */
183
+ public function getFork()
184
+ {
185
+ return $this->_fork;
186
+ }
187
+
188
+ /**
189
+ * @return string
190
+ */
191
+ public function getHost()
192
+ {
193
+ return $this->_host;
194
+ }
195
+
196
+ /**
197
+ * @return array
198
+ */
199
+ public function getOptions()
200
+ {
201
+ return $this->_options;
202
+ }
203
+
204
+ /**
205
+ * @return string
206
+ */
207
+ public function getProtocol()
208
+ {
209
+ return $this->_protocol;
210
+ }
211
+
212
+ /**
213
+ * @return int
214
+ */
215
+ public function getTimeout()
216
+ {
217
+ return $this->_timeout;
218
+ }
219
+
220
+
221
+ }
src/SupsysticTables/Promo/Model/classes/lib/ConsumerStrategies/FileConsumer.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/AbstractConsumer.php");
3
+ /**
4
+ * Consumes messages and writes them to a file
5
+ */
6
+ class ConsumerStrategies_FileConsumer extends ConsumerStrategies_AbstractConsumer {
7
+
8
+ /**
9
+ * @var string path to a file that we want to write the messages to
10
+ */
11
+ private $_file;
12
+
13
+
14
+ /**
15
+ * Creates a new FileConsumer and assigns properties from the $options array
16
+ * @param array $options
17
+ */
18
+ function __construct($options) {
19
+ parent::__construct($options);
20
+
21
+ // what file to write to?
22
+ $this->_file = array_key_exists("file", $options) ? $options['file'] : dirname(__FILE__)."/../../messages.txt";
23
+ }
24
+
25
+
26
+ /**
27
+ * Append $batch to a file
28
+ * @param array $batch
29
+ * @return bool
30
+ */
31
+ public function persist($batch) {
32
+ if (count($batch) > 0) {
33
+ return file_put_contents($this->_file, json_encode($batch)."\n", FILE_APPEND | LOCK_EX) !== false;
34
+ } else {
35
+ return true;
36
+ }
37
+ }
38
+ }
src/SupsysticTables/Promo/Model/classes/lib/ConsumerStrategies/SocketConsumer.php ADDED
@@ -0,0 +1,308 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Portions of this class were borrowed from
4
+ * https://github.com/segmentio/analytwtbp-php/blob/master/lib/Analytwtbp/Consumer/Socket.php.
5
+ * Thanks for the work!
6
+ *
7
+ * WWWWWW||WWWWWW
8
+ * W W W||W W W
9
+ * ||
10
+ * ( OO )__________
11
+ * / | \
12
+ * /o o| MIT \
13
+ * \___/||_||__||_|| *
14
+ * || || || ||
15
+ * _||_|| _||_||
16
+ * (__|__|(__|__|
17
+ * (The MIT License)
18
+ *
19
+ * Copyright (c) 2013 Segment.io Inc. friends@segment.io
20
+ *
21
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
22
+ * documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the
23
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
24
+ * permit persons to whom the Software is furnished to do so, subject to the following conditions:
25
+ *
26
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
27
+ * Software.
28
+ *
29
+ * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
30
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
31
+ * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
32
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33
+ */
34
+ require_once(dirname(__FILE__) . "/AbstractConsumer.php");
35
+
36
+ /**
37
+ * Consumes messages and writes them to host/endpoint using a persistent socket
38
+ */
39
+ class ConsumerStrategies_SocketConsumer extends ConsumerStrategies_AbstractConsumer {
40
+
41
+ /**
42
+ * @var string the host to connect to (e.g. api.mixpanel.com)
43
+ */
44
+ private $_host;
45
+
46
+
47
+ /**
48
+ * @var string the host-relative endpoint to write to (e.g. /engage)
49
+ */
50
+ private $_endpoint;
51
+
52
+
53
+ /**
54
+ * @var int connect_timeout the socket connection timeout in seconds
55
+ */
56
+ private $_connect_timeout;
57
+
58
+
59
+ /**
60
+ * @var string the protocol to use for the socket connection
61
+ */
62
+ private $_protocol;
63
+
64
+
65
+ /**
66
+ * @var resource holds the socket resource
67
+ */
68
+ private $_socket;
69
+
70
+ /**
71
+ * @var bool whether or not to wait for a response
72
+ */
73
+ private $_async;
74
+
75
+
76
+ /**
77
+ * Creates a new SocketConsumer and assigns properties from the $options array
78
+ * @param array $options
79
+ */
80
+ public function __construct($options = array()) {
81
+ parent::__construct($options);
82
+
83
+
84
+ $this->_host = $options['host'];
85
+ $this->_endpoint = $options['endpoint'];
86
+ $this->_connect_timeout = array_key_exists('connect_timeout', $options) ? $options['connect_timeout'] : 5;
87
+ $this->_async = array_key_exists('async', $options) && $options['async'] === false ? false : true;
88
+
89
+ if (array_key_exists('use_ssl', $options) && $options['use_ssl'] == true) {
90
+ $this->_protocol = "ssl";
91
+ $this->_port = 443;
92
+ } else {
93
+ $this->_protocol = "tcp";
94
+ $this->_port = 80;
95
+ }
96
+ }
97
+
98
+
99
+ /**
100
+ * Write using a persistent socket connection.
101
+ * @param array $batch
102
+ * @return bool
103
+ */
104
+ public function persist($batch) {
105
+
106
+ $socket = $this->_getSocket();
107
+ if (!is_resource($socket)) {
108
+ return false;
109
+ }
110
+
111
+ $data = "data=".$this->_encode($batch);
112
+
113
+ $body = "";
114
+ $body.= "POST ".$this->_endpoint." HTTP/1.1\r\n";
115
+ $body.= "Host: " . $this->_host . "\r\n";
116
+ $body.= "Content-Type: application/x-www-form-urlencoded\r\n";
117
+ $body.= "Accept: application/json\r\n";
118
+ $body.= "Content-length: " . strlen($data) . "\r\n";
119
+ $body.= "\r\n";
120
+ $body.= $data;
121
+
122
+ return $this->_write($socket, $body);
123
+ }
124
+
125
+
126
+ /**
127
+ * Return cached socket if open or create a new persistent socket
128
+ * @return bool|resource
129
+ */
130
+ private function _getSocket() {
131
+ if(is_resource($this->_socket)) {
132
+
133
+ if ($this->_debug()) {
134
+ $this->_log("Using existing socket");
135
+ }
136
+
137
+ return $this->_socket;
138
+ } else {
139
+
140
+ if ($this->_debug()) {
141
+ $this->_log("Creating new socket at ".time());
142
+ }
143
+
144
+ return $this->_createSocket();
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Attempt to open a new socket connection, cache it, and return the resource
150
+ * @param bool $retry
151
+ * @return bool|resource
152
+ */
153
+ private function _createSocket($retry = true) {
154
+ try {
155
+ $socket = pfsockopen($this->_protocol . "://" . $this->_host, $this->_port, $err_no, $err_msg, $this->_connect_timeout);
156
+
157
+ if ($this->_debug()) {
158
+ $this->_log("Opening socket connection to " . $this->_protocol . "://" . $this->_host . ":" . $this->_port);
159
+ }
160
+
161
+ if ($err_no != 0) {
162
+ $this->_handleError($err_no, $err_msg);
163
+ return $retry == true ? $this->_createSocket(false) : false;
164
+ } else {
165
+ // cache the socket
166
+ $this->_socket = $socket;
167
+ return $socket;
168
+ }
169
+
170
+ } catch (Exception $e) {
171
+ $this->_handleError($e->getCode(), $e->getMessage());
172
+ return $retry == true ? $this->_createSocket(false) : false;
173
+ }
174
+ }
175
+
176
+ /**
177
+ * Attempt to close and dereference a socket resource
178
+ */
179
+ private function _destroySocket() {
180
+ $socket = $this->_socket;
181
+ $this->_socket = null;
182
+ fclose($socket);
183
+ }
184
+
185
+
186
+ /**
187
+ * Write $data through the given $socket
188
+ * @param $socket
189
+ * @param $data
190
+ * @param bool $retry
191
+ * @return bool
192
+ */
193
+ private function _write($socket, $data, $retry = true) {
194
+
195
+ $bytes_sent = 0;
196
+ $bytes_total = strlen($data);
197
+ $socket_closed = false;
198
+ $success = true;
199
+ $max_bytes_per_write = 8192;
200
+
201
+ // if we have no data to write just return true
202
+ if ($bytes_total == 0) {
203
+ return true;
204
+ }
205
+
206
+ // try to write the data
207
+ while (!$socket_closed && $bytes_sent < $bytes_total) {
208
+
209
+ try {
210
+ $bytes = fwrite($socket, $data, $max_bytes_per_write);
211
+
212
+ if ($this->_debug()) {
213
+ $this->_log("Socket wrote ".$bytes." bytes");
214
+ }
215
+
216
+ // if we actually wrote data, then remove the written portion from $data left to write
217
+ if ($bytes > 0) {
218
+ $data = substr($data, $max_bytes_per_write);
219
+ }
220
+
221
+ } catch (Exception $e) {
222
+ $this->_handleError($e->getCode(), $e->getMessage());
223
+ $socket_closed = true;
224
+ }
225
+
226
+ if (isset($bytes) && $bytes) {
227
+ $bytes_sent += $bytes;
228
+ } else {
229
+ $socket_closed = true;
230
+ }
231
+ }
232
+
233
+ // create a new socket if the current one is closed and retry the message
234
+ if ($socket_closed) {
235
+
236
+ $this->_destroySocket();
237
+
238
+ if ($retry) {
239
+ if ($this->_debug()) {
240
+ $this->_log("Retrying socket write...");
241
+ }
242
+ $socket = $this->_getSocket();
243
+ if ($socket) return $this->_write($socket, $data, false);
244
+ }
245
+
246
+ return false;
247
+ }
248
+
249
+
250
+ // only wait for the response in debug mode or if we explicitly want to be synchronous
251
+ if ($this->_debug() || !$this->_async) {
252
+ $res = $this->handleResponse(fread($socket, 2048));
253
+ if ($res["status"] != "200") {
254
+ $this->_handleError($res["status"], $res["body"]);
255
+ $success = false;
256
+ }
257
+ }
258
+
259
+ return $success;
260
+ }
261
+
262
+
263
+ /**
264
+ * Parse the response from a socket write (only used for debugging)
265
+ * @param $response
266
+ * @return array
267
+ */
268
+ private function handleResponse($response) {
269
+
270
+ $lines = explode("\n", $response);
271
+
272
+ // extract headers
273
+ $headers = array();
274
+ foreach($lines as $line) {
275
+ $kvsplit = explode(":", $line);
276
+ if (count($kvsplit) == 2) {
277
+ $header = $kvsplit[0];
278
+ $value = $kvsplit[1];
279
+ $headers[$header] = trim($value);
280
+ }
281
+
282
+ }
283
+
284
+ // extract status
285
+ $line_one_exploded = explode(" ", $lines[0]);
286
+ $status = $line_one_exploded[1];
287
+
288
+ // extract body
289
+ $body = $lines[count($lines) - 1];
290
+
291
+ // if the connection has been closed lets kill the socket
292
+ if ($headers['Connection'] == "close") {
293
+ $this->_destroySocket();
294
+ if ($this->_debug()) {
295
+ $this->_log("Server told us connection closed so lets destroy the socket so it'll reconnect on next call");
296
+ }
297
+ }
298
+
299
+ $ret = array(
300
+ "status" => $status,
301
+ "body" => $body,
302
+ );
303
+
304
+ return $ret;
305
+ }
306
+
307
+
308
+ }
src/SupsysticTables/Promo/Model/classes/lib/Mixpanel.php ADDED
@@ -0,0 +1,302 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(dirname(__FILE__) . "/Base/MixpanelBase.php");
4
+ require_once(dirname(__FILE__) . "/Producers/MixpanelPeople.php");
5
+ require_once(dirname(__FILE__) . "/Producers/MixpanelEvents.php");
6
+
7
+ /**
8
+ * This is the main class for the Mixpanel PHP Library which provides all of the methods you need to track events and
9
+ * create/update profiles.
10
+ *
11
+ * Architecture
12
+ * -------------
13
+ *
14
+ * This library is built such that all messages are buffered in an in-memory "queue"
15
+ * The queue will be automatically flushed at the end of every request. Alternatively, you can call "flush()" manually
16
+ * at any time. Flushed messages will be passed to a Consumer's "persist" method. The library comes with a handful of
17
+ * Consumers. The "CurlConsumer" is used by default which will send the messages to Mixpanel using forked cURL processes.
18
+ * You can implement your own custom Consumer to customize how a message is sent to Mixpanel. This can be useful when
19
+ * you want to put messages onto a distributed queue (such as ActiveMQ or Kestrel) instead of writing to Mixpanel in
20
+ * the user thread.
21
+ *
22
+ * Options
23
+ * -------------
24
+ *
25
+ * <table width="100%" cellpadding="5">
26
+ * <tr>
27
+ * <th>Option</th>
28
+ * <th>Description</th>
29
+ * <th>Default</th>
30
+ * </tr>
31
+ * <tr>
32
+ * <td>max_queue_size</td>
33
+ * <td>The maximum number of items to buffer in memory before flushing</td>
34
+ * <td>1000</td>
35
+ * </tr>
36
+ * <tr>
37
+ * <td>debug</td>
38
+ * <td>Enable/disable debug mode</td>
39
+ * <td>false</td>
40
+ * </tr>
41
+ * <tr>
42
+ * <td>consumer</td>
43
+ * <td>The consumer to use for writing messages</td>
44
+ * <td>curl</td>
45
+ * </tr>
46
+ * <tr>
47
+ * <td>consumers</td>
48
+ * <td>An array of custom consumers in the format array(consumer_key => class_name)</td>
49
+ * <td>null</td>
50
+ * </tr>
51
+ * <tr>
52
+ * <td>host</td>
53
+ * <td>The host name for api calls (used by some consumers)</td>
54
+ * <td>api.mixpanel.com</td>
55
+ * </tr>
56
+ * <tr>
57
+ * <td>events_endpoint</td>
58
+ * <td>The endpoint for tracking events (relative to the host)</td>
59
+ * <td>/events</td>
60
+ * </tr>
61
+ * <tr>
62
+ * <td>people_endpoint</td>
63
+ * <td>The endpoint for making people updates (relative to the host)</td>
64
+ * <td>/engage</td>
65
+ * </tr>
66
+ * <tr>
67
+ * <td>use_ssl</td>
68
+ * <td>Tell the consumer whether or not to use ssl (when available)</td>
69
+ * <td>true</td>
70
+ * </tr>
71
+ * <tr>
72
+ * <td>error_callback</td>
73
+ * <td>The name of a function to be called on consumption failures</td>
74
+ * <td>null</td>
75
+ * </tr>
76
+ * <tr>
77
+ * <td>connect_timeout</td>
78
+ * <td>In both the SocketConsumer and CurlConsumer, this is used for the connection timeout (i.e. How long it has take to actually make a connection).
79
+ * <td>5</td>
80
+ * </tr>
81
+ * <tr>
82
+ * <td>timeout</td>
83
+ * <td>In the CurlConsumer (non-forked), it is used to determine how long the cURL call has to execute.
84
+ * <td>30</td>
85
+ * </tr>
86
+ * </table>
87
+ *
88
+ * Example: Tracking an Event
89
+ * -------------
90
+ *
91
+ * $mp = Mixpanel::getInstance("MY_TOKEN");
92
+ *
93
+ * $mp->track("My Event");
94
+ *
95
+ * Example: Setting Profile Properties
96
+ * -------------
97
+ *
98
+ * $mp = Mixpanel::getInstance("MY_TOKEN", array("use_ssl" => false));
99
+ *
100
+ * $mp->people->set(12345, array(
101
+ * '$first_name' => "John",
102
+ * '$last_name' => "Doe",
103
+ * '$email' => "john.doe@example.com",
104
+ * '$phone' => "5555555555",
105
+ * 'Favorite Color' => "red"
106
+ * ));
107
+ *
108
+ */
109
+ class Mixpanel extends Base_MixpanelBase {
110
+
111
+
112
+ /**
113
+ * An instance of the MixpanelPeople class (used to create/update profiles)
114
+ * @var MixpanelPeople
115
+ */
116
+ public $people;
117
+
118
+
119
+ /**
120
+ * An instance of the MixpanelEvents class
121
+ * @var Producers_MixpanelEvents
122
+ */
123
+ private $_events;
124
+
125
+
126
+ /**
127
+ * An instance of the Mixpanel class (for singleton use)
128
+ * @var Mixpanel
129
+ */
130
+ private static $_instance;
131
+
132
+
133
+ /**
134
+ * Instantiates a new Mixpanel instance.
135
+ * @param $token
136
+ * @param array $options
137
+ */
138
+ public function __construct($token, $options = array()) {
139
+ parent::__construct($options);
140
+ $this->people = new Producers_MixpanelPeople($token, $options);
141
+ $this->_events = new Producers_MixpanelEvents($token, $options);
142
+ }
143
+
144
+
145
+ /**
146
+ * Returns a singleton instance of Mixpanel
147
+ * @param $token
148
+ * @param array $options
149
+ * @return Mixpanel
150
+ */
151
+ public static function getInstance($token, $options = array()) {
152
+ if(!isset(self::$_instance)) {
153
+ self::$_instance = new Mixpanel($token, $options);
154
+ }
155
+ return self::$_instance;
156
+ }
157
+
158
+
159
+ /**
160
+ * Add an array representing a message to be sent to Mixpanel to the in-memory queue.
161
+ * @param array $message
162
+ */
163
+ public function enqueue($message = array()) {
164
+ $this->_events->enqueue($message);
165
+ }
166
+
167
+
168
+ /**
169
+ * Add an array representing a list of messages to be sent to Mixpanel to a queue.
170
+ * @param array $messages
171
+ */
172
+ public function enqueueAll($messages = array()) {
173
+ $this->_events->enqueueAll($messages);
174
+ }
175
+
176
+
177
+ /**
178
+ * Flush the events queue
179
+ * @param int $desired_batch_size
180
+ */
181
+ public function flush($desired_batch_size = 50) {
182
+ $this->_events->flush($desired_batch_size);
183
+ }
184
+
185
+
186
+ /**
187
+ * Empty the events queue
188
+ */
189
+ public function reset() {
190
+ $this->_events->reset();
191
+ }
192
+
193
+
194
+ /**
195
+ * Identify the user you want to associate to tracked events
196
+ * @param string|int $user_id
197
+ */
198
+ public function identify($user_id) {
199
+ $this->_events->identify($user_id);
200
+ }
201
+
202
+ /**
203
+ * Track an event defined by $event associated with metadata defined by $properties
204
+ * @param string $event
205
+ * @param array $properties
206
+ */
207
+ public function track($event, $properties = array()) {
208
+ $this->_events->track($event, $properties);
209
+ }
210
+
211
+
212
+ /**
213
+ * Register a property to be sent with every event.
214
+ *
215
+ * If the property has already been registered, it will be
216
+ * overwritten. NOTE: Registered properties are only persisted for the life of the Mixpanel class instance.
217
+ * @param string $property
218
+ * @param mixed $value
219
+ */
220
+ public function register($property, $value) {
221
+ $this->_events->register($property, $value);
222
+ }
223
+
224
+
225
+ /**
226
+ * Register multiple properties to be sent with every event.
227
+ *
228
+ * If any of the properties have already been registered,
229
+ * they will be overwritten. NOTE: Registered properties are only persisted for the life of the Mixpanel class
230
+ * instance.
231
+ * @param array $props_and_vals
232
+ */
233
+ public function registerAll($props_and_vals = array()) {
234
+ $this->_events->registerAll($props_and_vals);
235
+ }
236
+
237
+
238
+ /**
239
+ * Register a property to be sent with every event.
240
+ *
241
+ * If the property has already been registered, it will NOT be
242
+ * overwritten. NOTE: Registered properties are only persisted for the life of the Mixpanel class instance.
243
+ * @param $property
244
+ * @param $value
245
+ */
246
+ public function registerOnce($property, $value) {
247
+ $this->_events->registerOnce($property, $value);
248
+ }
249
+
250
+
251
+ /**
252
+ * Register multiple properties to be sent with every event.
253
+ *
254
+ * If any of the properties have already been registered,
255
+ * they will NOT be overwritten. NOTE: Registered properties are only persisted for the life of the Mixpanel class
256
+ * instance.
257
+ * @param array $props_and_vals
258
+ */
259
+ public function registerAllOnce($props_and_vals = array()) {
260
+ $this->_events->registerAllOnce($props_and_vals);
261
+ }
262
+
263
+
264
+ /**
265
+ * Un-register an property to be sent with every event.
266
+ * @param string $property
267
+ */
268
+ public function unregister($property) {
269
+ $this->_events->unregister($property);
270
+ }
271
+
272
+
273
+ /**
274
+ * Un-register a list of properties to be sent with every event.
275
+ * @param array $properties
276
+ */
277
+ public function unregisterAll($properties) {
278
+ $this->_events->unregisterAll($properties);
279
+ }
280
+
281
+
282
+ /**
283
+ * Get a property that is set to be sent with every event
284
+ * @param string $property
285
+ * @return mixed
286
+ */
287
+ public function getProperty($property)
288
+ {
289
+ return $this->_events->getProperty($property);
290
+ }
291
+
292
+
293
+ /**
294
+ * Alias an existing id with a different unique id. This is helpful when you want to associate a generated id
295
+ * (such as a session id) to a user id or username.
296
+ * @param string|int $original_id
297
+ * @param string|int $new_id
298
+ */
299
+ public function createAlias($original_id, $new_id) {
300
+ $this->_events->createAlias($original_id, $new_id);
301
+ }
302
+ }
src/SupsysticTables/Promo/Model/classes/lib/Producers/MixpanelBaseProducer.php ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/../Base/MixpanelBase.php");
3
+ require_once(dirname(__FILE__) . "/../ConsumerStrategies/FileConsumer.php");
4
+ require_once(dirname(__FILE__) . "/../ConsumerStrategies/CurlConsumer.php");
5
+ require_once(dirname(__FILE__) . "/../ConsumerStrategies/SocketConsumer.php");
6
+
7
+ if (!function_exists('json_encode')) {
8
+ throw new Exception('The JSON PHP extension is required.');
9
+ }
10
+
11
+ /**
12
+ * Provides some base methods for use by a message Producer
13
+ */
14
+ abstract class Producers_MixpanelBaseProducer extends Base_MixpanelBase {
15
+
16
+
17
+ /**
18
+ * @var string a token associated to a Mixpanel project
19
+ */
20
+ protected $_token;
21
+
22
+
23
+ /**
24
+ * @var array a queue to hold messages in memory before flushing in batches
25
+ */
26
+ private $_queue = array();
27
+
28
+
29
+ /**
30
+ * @var ConsumerStrategies_AbstractConsumer the consumer to use when flushing messages
31
+ */
32
+ private $_consumer = null;
33
+
34
+
35
+ /**
36
+ * @var array The list of available consumers
37
+ */
38
+ private $_consumers = array(
39
+ "file" => "ConsumerStrategies_FileConsumer",
40
+ "curl" => "ConsumerStrategies_CurlConsumer",
41
+ "socket" => "ConsumerStrategies_SocketConsumer"
42
+ );
43
+
44
+
45
+ /**
46
+ * If the queue reaches this size we'll auto-flush to prevent out of memory errors
47
+ * @var int
48
+ */
49
+ protected $_max_queue_size = 1000;
50
+
51
+
52
+ /**
53
+ * Creates a new MixpanelBaseProducer, assings Mixpanel project token, registers custom Consumers, and instantiates
54
+ * the desired consumer
55
+ * @param $token
56
+ * @param array $options
57
+ */
58
+ public function __construct($token, $options = array()) {
59
+
60
+ parent::__construct($options);
61
+
62
+ // register any customer consumers
63
+ if (array_key_exists("consumers", $options)) {
64
+ $this->_consumers = array_merge($this->_consumers, $options['consumers']);
65
+ }
66
+
67
+ // set max queue size
68
+ if (array_key_exists("max_queue_size", $options)) {
69
+ $this->_max_queue_size = $options['max_queue_size'];
70
+ }
71
+
72
+ // associate token
73
+ $this->_token = $token;
74
+
75
+ if ($this->_debug()) {
76
+ $this->_log("Using token: ".$this->_token);
77
+ }
78
+
79
+ // instantiate the chosen consumer
80
+ $this->_consumer = $this->_getConsumer();
81
+
82
+ }
83
+
84
+
85
+ /**
86
+ * Flush the queue when we destruct the client with retries
87
+ */
88
+ public function __destruct() {
89
+ $attempts = 0;
90
+ $max_attempts = 10;
91
+ $success = false;
92
+ while (!$success && $attempts < $max_attempts) {
93
+ if ($this->_debug()) {
94
+ $this->_log("destruct flush attempt #".($attempts+1));
95
+ }
96
+ $success = $this->flush();
97
+ $attempts++;
98
+ }
99
+ }
100
+
101
+
102
+ /**
103
+ * Iterate the queue and write in batches using the instantiated Consumer Strategy
104
+ * @param int $desired_batch_size
105
+ * @return bool whether or not the flush was successful
106
+ */
107
+ public function flush($desired_batch_size = 50) {
108
+ $queue_size = count($this->_queue);
109
+ $succeeded = true;
110
+ if ($this->_debug()) {
111
+ $this->_log("Flush called - queue size: ".$queue_size);
112
+ }
113
+
114
+ while($queue_size > 0 && $succeeded) {
115
+ $batch_size = min(array($queue_size, $desired_batch_size, $this->_options['max_batch_size']));
116
+ $batch = array_splice($this->_queue, 0, $batch_size);
117
+ $succeeded = $this->_persist($batch);
118
+
119
+ if (!$succeeded) {
120
+ if ($this->_debug()) {
121
+ $this->_log("Batch consumption failed!");
122
+ }
123
+ $this->_queue = array_merge($batch, $this->_queue);
124
+
125
+ if ($this->_debug()) {
126
+ $this->_log("added batch back to queue, queue size is now $queue_size");
127
+ }
128
+ }
129
+
130
+ $queue_size = count($this->_queue);
131
+
132
+ if ($this->_debug()) {
133
+ $this->_log("Batch of $batch_size consumed, queue size is now $queue_size");
134
+ }
135
+ }
136
+ return $succeeded;
137
+ }
138
+
139
+
140
+ /**
141
+ * Empties the queue without persisting any of the messages
142
+ */
143
+ public function reset() {
144
+ $this->_queue = array();
145
+ }
146
+
147
+
148
+ /**
149
+ * Returns the in-memory queue
150
+ * @return array
151
+ */
152
+ public function getQueue() {
153
+ return $this->_queue;
154
+ }
155
+
156
+ /**
157
+ * Returns the current Mixpanel project token
158
+ * @return string
159
+ */
160
+ public function getToken() {
161
+ return $this->_token;
162
+ }
163
+
164
+
165
+ /**
166
+ * Given a strategy type, return a new PersistenceStrategy object
167
+ * @return ConsumerStrategies_AbstractConsumer
168
+ */
169
+ protected function _getConsumer() {
170
+ $key = $this->_options['consumer'];
171
+ $Strategy = $this->_consumers[$key];
172
+ if ($this->_debug()) {
173
+ $this->_log("Using consumer: " . $key . " -> " . $Strategy);
174
+ }
175
+ $this->_options['endpoint'] = $this->_getEndpoint();
176
+
177
+ return new $Strategy($this->_options);
178
+ }
179
+
180
+
181
+ /**
182
+ * Add an array representing a message to be sent to Mixpanel to a queue.
183
+ * @param array $message
184
+ */
185
+ public function enqueue($message = array()) {
186
+ array_push($this->_queue, $message);
187
+
188
+ // force a flush if we've reached our threshold
189
+ if (count($this->_queue) > $this->_max_queue_size) {
190
+ $this->flush();
191
+ }
192
+
193
+ if ($this->_debug()) {
194
+ $this->_log("Queued message: ".json_encode($message));
195
+ }
196
+ }
197
+
198
+
199
+ /**
200
+ * Add an array representing a list of messages to be sent to Mixpanel to a queue.
201
+ * @param array $messages
202
+ */
203
+ public function enqueueAll($messages = array()) {
204
+ foreach($messages as $message) {
205
+ $this->enqueue($message);
206
+ }
207
+
208
+ }
209
+
210
+
211
+ /**
212
+ * Given an array of messages, persist it with the instantiated Persistence Strategy
213
+ * @param $message
214
+ * @return mixed
215
+ */
216
+ protected function _persist($message) {
217
+ return $this->_consumer->persist($message);
218
+ }
219
+
220
+
221
+
222
+
223
+ /**
224
+ * Return the endpoint that should be used by a consumer that consumes messages produced by this producer.
225
+ * @return string
226
+ */
227
+ abstract function _getEndpoint();
228
+
229
+ }
src/SupsysticTables/Promo/Model/classes/lib/Producers/MixpanelEvents.php ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/MixpanelBaseProducer.php");
3
+ require_once(dirname(__FILE__) . "/MixpanelPeople.php");
4
+ require_once(dirname(__FILE__) . "/../ConsumerStrategies/CurlConsumer.php");
5
+
6
+ /**
7
+ * Provides an API to track events on Mixpanel
8
+ */
9
+ class Producers_MixpanelEvents extends Producers_MixpanelBaseProducer {
10
+
11
+ /**
12
+ * An array of properties to attach to every tracked event
13
+ * @var array
14
+ */
15
+ private $_super_properties = array("mp_lib" => "php");
16
+
17
+
18
+ /**
19
+ * Track an event defined by $event associated with metadata defined by $properties
20
+ * @param string $event
21
+ * @param array $properties
22
+ */
23
+ public function track($event, $properties = array()) {
24
+
25
+ // if no token is passed in, use current token
26
+ if (!array_key_exists("token", $properties)) $properties['token'] = $this->_token;
27
+
28
+ // if no time is passed in, use the current time
29
+ if (!array_key_exists('time', $properties)) $properties['time'] = time();
30
+
31
+ $params['event'] = $event;
32
+ $params['properties'] = array_merge($this->_super_properties, $properties);
33
+
34
+ $this->enqueue($params);
35
+ }
36
+
37
+
38
+ /**
39
+ * Register a property to be sent with every event. If the property has already been registered, it will be
40
+ * overwritten.
41
+ * @param string $property
42
+ * @param mixed $value
43
+ */
44
+ public function register($property, $value) {
45
+ $this->_super_properties[$property] = $value;
46
+ }
47
+
48
+
49
+ /**
50
+ * Register multiple properties to be sent with every event. If any of the properties have already been registered,
51
+ * they will be overwritten.
52
+ * @param array $props_and_vals
53
+ */
54
+ public function registerAll($props_and_vals = array()) {
55
+ foreach($props_and_vals as $property => $value) {
56
+ $this->register($property, $value);
57
+ }
58
+ }
59
+
60
+
61
+ /**
62
+ * Register a property to be sent with every event. If the property has already been registered, it will NOT be
63
+ * overwritten.
64
+ * @param $property
65
+ * @param $value
66
+ */
67
+ public function registerOnce($property, $value) {
68
+ if (!isset($this->_super_properties[$property])) {
69
+ $this->register($property, $value);
70
+ }
71
+ }
72
+
73
+
74
+ /**
75
+ * Register multiple properties to be sent with every event. If any of the properties have already been registered,
76
+ * they will NOT be overwritten.
77
+ * @param array $props_and_vals
78
+ */
79
+ public function registerAllOnce($props_and_vals = array()) {
80
+ foreach($props_and_vals as $property => $value) {
81
+ if (!isset($this->_super_properties[$property])) {
82
+ $this->register($property, $value);
83
+ }
84
+ }
85
+ }
86
+
87
+
88
+ /**
89
+ * Un-register an property to be sent with every event.
90
+ * @param string $property
91
+ */
92
+ public function unregister($property) {
93
+ unset($this->_super_properties[$property]);
94
+ }
95
+
96
+
97
+ /**
98
+ * Un-register a list of properties to be sent with every event.
99
+ * @param array $properties
100
+ */
101
+ public function unregisterAll($properties) {
102
+ foreach($properties as $property) {
103
+ $this->unregister($property);
104
+ }
105
+ }
106
+
107
+
108
+ /**
109
+ * Get a property that is set to be sent with every event
110
+ * @param string $property
111
+ * @return mixed
112
+ */
113
+ public function getProperty($property) {
114
+ return $this->_super_properties[$property];
115
+ }
116
+
117
+
118
+ /**
119
+ * Identify the user you want to associate to tracked events
120
+ * @param string|int $user_id
121
+ */
122
+ public function identify($user_id) {
123
+ $this->register("distinct_id", $user_id);
124
+ }
125
+
126
+
127
+ /**
128
+ * Alias an existing id with a different unique id. This is helpful when you want to associate a generated id to
129
+ * a username or e-mail address.
130
+ *
131
+ * Because aliasing can be extremely vulnerable to race conditions and ordering issues, we'll make a synchronous
132
+ * call directly to Mixpanel when this method is called. If it fails we'll throw an Exception as subsequent
133
+ * events are likely to be incorrectly tracked.
134
+ * @param string|int $original_id
135
+ * @param string|int $new_id
136
+ * @return array $msg
137
+ * @throws Exception
138
+ */
139
+ public function createAlias($original_id, $new_id) {
140
+ $msg = array(
141
+ "event" => '$create_alias',
142
+ "properties" => array("distinct_id" => $original_id, "alias" => $new_id, "token" => $this->_token)
143
+ );
144
+
145
+ $options = array_merge($this->_options, array("endpoint" => $this->_getEndpoint(), "fork" => false));
146
+ $curlConsumer = new ConsumerStrategies_CurlConsumer($options);
147
+ $success = $curlConsumer->persist(array($msg));
148
+ if (!$success) {
149
+ error_log("Creating Mixpanel Alias (original id: $original_id, new id: $new_id) failed");
150
+ throw new Exception("Tried to create an alias but the call was not successful");
151
+ } else {
152
+ return $msg;
153
+ }
154
+ }
155
+
156
+
157
+ /**
158
+ * Returns the "events" endpoint
159
+ * @return string
160
+ */
161
+ function _getEndpoint() {
162
+ return $this->_options['events_endpoint'];
163
+ }
164
+ }
src/SupsysticTables/Promo/Model/classes/lib/Producers/MixpanelPeople.php ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/MixpanelBaseProducer.php");
3
+
4
+ /**
5
+ * Provides an API to create/update profiles on Mixpanel
6
+ */
7
+ class Producers_MixpanelPeople extends Producers_MixpanelBaseProducer {
8
+
9
+ /**
10
+ * Internal method to prepare a message given the message data
11
+ * @param $distinct_id
12
+ * @param $operation
13
+ * @param $value
14
+ * @param null $ip
15
+ * @return array
16
+ */
17
+ private function _constructPayload($distinct_id, $operation, $value, $ip = null, $ignore_time = false) {
18
+ $payload = array(
19
+ '$token' => $this->_token,
20
+ '$distinct_id' => $distinct_id,
21
+ $operation => $value
22
+ );
23
+ if ($ip !== null) $payload['$ip'] = $ip;
24
+ if ($ignore_time === true) $payload['$ignore_time'] = true;
25
+ return $payload;
26
+ }
27
+
28
+ /**
29
+ * Set properties on a user record. If the profile does not exist, it creates it with these properties.
30
+ * If it does exist, it sets the properties to these values, overwriting existing values.
31
+ * @param string|int $distinct_id the distinct_id or alias of a user
32
+ * @param array $props associative array of properties to set on the profile
33
+ * @param string|null $ip the ip address of the client (used for geo-location)
34
+ * @param boolean $ignore_time If the $ignore_time property is true, Mixpanel will not automatically update the "Last Seen" property of the profile. Otherwise, Mixpanel will add a "Last Seen" property associated with the current time
35
+ */
36
+ public function set($distinct_id, $props, $ip = null, $ignore_time = false) {
37
+ $payload = $this->_constructPayload($distinct_id, '$set', $props, $ip, $ignore_time);
38
+ $this->enqueue($payload);
39
+ }
40
+
41
+ /**
42
+ * Set properties on a user record. If the profile does not exist, it creates it with these properties.
43
+ * If it does exist, it sets the properties to these values but WILL NOT overwrite existing values.
44
+ * @param string|int $distinct_id the distinct_id or alias of a user
45
+ * @param array $props associative array of properties to set on the profile
46
+ * @param string|null $ip the ip address of the client (used for geo-location)
47
+ * @param boolean $ignore_time If the $ignore_time property is true, Mixpanel will not automatically update the "Last Seen" property of the profile. Otherwise, Mixpanel will add a "Last Seen" property associated with the current time
48
+ */
49
+ public function setOnce($distinct_id, $props, $ip = null, $ignore_time = false) {
50
+ $payload = $this->_constructPayload($distinct_id, '$set_once', $props, $ip, $ignore_time);
51
+ $this->enqueue($payload);
52
+ }
53
+
54
+ /**
55
+ * Unset properties on a user record. If the profile does not exist, it creates it with no properties.
56
+ * If it does exist, it unsets these properties. NOTE: In other libraries we use 'unset' which is
57
+ * a reserved word in PHP.
58
+ * @param string|int $distinct_id the distinct_id or alias of a user
59
+ * @param array $props associative array of properties to unset on the profile
60
+ * @param string|null $ip the ip address of the client (used for geo-location)
61
+ * @param boolean $ignore_time If the $ignore_time property is true, Mixpanel will not automatically update the "Last Seen" property of the profile. Otherwise, Mixpanel will add a "Last Seen" property associated with the current time
62
+ */
63
+ public function remove($distinct_id, $props, $ip = null, $ignore_time = false) {
64
+ $payload = $this->_constructPayload($distinct_id, '$unset', $props, $ip, $ignore_time);
65
+ $this->enqueue($payload);
66
+ }
67
+
68
+ /**
69
+ * Increments the value of a property on a user record. If the profile does not exist, it creates it and sets the
70
+ * property to the increment value.
71
+ * @param string|int $distinct_id the distinct_id or alias of a user
72
+ * @param $prop string the property to increment
73
+ * @param int $val the amount to increment the property by
74
+ * @param string|null $ip the ip address of the client (used for geo-location)
75
+ * @param boolean $ignore_time If the $ignore_time property is true, Mixpanel will not automatically update the "Last Seen" property of the profile. Otherwise, Mixpanel will add a "Last Seen" property associated with the current time
76
+ */
77
+ public function increment($distinct_id, $prop, $val, $ip = null, $ignore_time = false) {
78
+ $payload = $this->_constructPayload($distinct_id, '$add', array("$prop" => $val), $ip, $ignore_time);
79
+ $this->enqueue($payload);
80
+ }
81
+
82
+ /**
83
+ * Adds $val to a list located at $prop. If the property does not exist, it will be created. If $val is a string
84
+ * and the list is empty or does not exist, a new list with one value will be created.
85
+ * @param string|int $distinct_id the distinct_id or alias of a user
86
+ * @param string $prop the property that holds the list
87
+ * @param string|array $val items to add to the list
88
+ * @param string|null $ip the ip address of the client (used for geo-location)
89
+ * @param boolean $ignore_time If the $ignore_time property is true, Mixpanel will not automatically update the "Last Seen" property of the profile. Otherwise, Mixpanel will add a "Last Seen" property associated with the current time
90
+ */
91
+ public function append($distinct_id, $prop, $val, $ip = null, $ignore_time = false) {
92
+ $operation = gettype($val) == "array" ? '$union' : '$append';
93
+ $payload = $this->_constructPayload($distinct_id, $operation, array("$prop" => $val), $ip, $ignore_time);
94
+ $this->enqueue($payload);
95
+ }
96
+
97
+ /**
98
+ * Adds a transaction to the user's profile for revenue tracking
99
+ * @param string|int $distinct_id the distinct_id or alias of a user
100
+ * @param string $amount the transaction amount e.g. "20.50"
101
+ * @param null $timestamp the timestamp of when the transaction occurred (default to current timestamp)
102
+ * @param string|null $ip the ip address of the client (used for geo-location)
103
+ * @param boolean $ignore_time If the $ignore_time property is true, Mixpanel will not automatically update the "Last Seen" property of the profile. Otherwise, Mixpanel will add a "Last Seen" property associated with the current time
104
+ */
105
+ public function trackCharge($distinct_id, $amount, $timestamp = null, $ip = null, $ignore_time = false) {
106
+ $timestamp = $timestamp == null ? time() : $timestamp;
107
+ $date_iso = date("c", $timestamp);
108
+ $transaction = array(
109
+ '$time' => $date_iso,
110
+ '$amount' => $amount
111
+ );
112
+ $val = array('$transactions' => $transaction);
113
+ $payload = $this->_constructPayload($distinct_id, '$append', $val, $ip, $ignore_time);
114
+ $this->enqueue($payload);
115
+ }
116
+
117
+ /**
118
+ * Clear all transactions stored on a user's profile
119
+ * @param string|int $distinct_id the distinct_id or alias of a user
120
+ * @param string|null $ip the ip address of the client (used for geo-location)
121
+ * @param boolean $ignore_time If the $ignore_time property is true, Mixpanel will not automatically update the "Last Seen" property of the profile. Otherwise, Mixpanel will add a "Last Seen" property associated with the current time
122
+ */
123
+ public function clearCharges($distinct_id, $ip = null, $ignore_time = false) {
124
+ $payload = $this->_constructPayload($distinct_id, '$set', array('$transactions' => array()), $ip, $ignore_time);
125
+ $this->enqueue($payload);
126
+ }
127
+
128
+ /**
129
+ * Delete this profile from Mixpanel
130
+ * @param string|int $distinct_id the distinct_id or alias of a user
131
+ * @param string|null $ip the ip address of the client (used for geo-location)
132
+ * @param boolean $ignore_time If the $ignore_time property is true, Mixpanel will not automatically update the "Last Seen" property of the profile. Otherwise, Mixpanel will add a "Last Seen" property associated with the current time
133
+ */
134
+ public function deleteUser($distinct_id, $ip = null, $ignore_time = false) {
135
+ $payload = $this->_constructPayload($distinct_id, '$delete', "", $ip, $ignore_time);
136
+ $this->enqueue($payload);
137
+ }
138
+
139
+ /**
140
+ * Returns the "engage" endpoint
141
+ * @return string
142
+ */
143
+ function _getEndpoint() {
144
+ return $this->_options['people_endpoint'];
145
+ }
146
+
147
+ }
src/SupsysticTables/Promo/Module.php CHANGED
@@ -17,6 +17,27 @@ class SupsysticTables_Promo_Module extends SupsysticTables_Core_BaseModule
17
  if(is_admin()) {
18
  add_action('admin_init', array($this, 'loadAdminPromoAssets'));
19
  add_action('wp_ajax_supsystic-tables-tutorial-close', array($this, 'endTutorial'));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  }
21
  }
22
 
@@ -164,4 +185,89 @@ class SupsysticTables_Promo_Module extends SupsysticTables_Core_BaseModule
164
  public function endTutorial() {
165
  update_user_meta(get_current_user_id(), 'supsystic-tables-tutorial_was_showed', 1);
166
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  }
17
  if(is_admin()) {
18
  add_action('admin_init', array($this, 'loadAdminPromoAssets'));
19
  add_action('wp_ajax_supsystic-tables-tutorial-close', array($this, 'endTutorial'));
20
+
21
+ $dispatcher = $this->getEnvironment()->getDispatcher();
22
+ $dispatcher->on('messages', array($this, 'renderDiscountMsg'));
23
+
24
+ $this->_checkFirstRun();
25
+ add_action('admin_footer', array($this, 'checkPluginDeactivation'));
26
+ }
27
+ }
28
+
29
+ private function _setUsed() {
30
+ update_option($this->config('db_prefix'). 'plug_was_used', 1);
31
+ }
32
+
33
+ private function _isUsed() {
34
+ return (int) get_option($this->config('db_prefix'). 'plug_was_used');
35
+ }
36
+
37
+ private function _checkFirstRun() {
38
+ if(!$this->_isUsed()) { // First time plugin run
39
+ $this->getController()->getModel('promo')->firstRun();
40
+ $this->_setUsed();
41
  }
42
  }
43
 
185
  public function endTutorial() {
186
  update_user_meta(get_current_user_id(), 'supsystic-tables-tutorial_was_showed', 1);
187
  }
188
+
189
+ public function renderDiscountMsg()
190
+ {
191
+ $environment = $this->getEnvironment();
192
+ if($environment->isPro() && $environment->isModule('license') && $environment->getModule('license')->isActive()) {
193
+ $proPluginsList = array(
194
+ 'ultimate-maps-by-supsystic-pro', 'newsletters-by-supsystic-pro', 'contact-form-by-supsystic-pro', 'live-chat-pro',
195
+ 'digital-publications-supsystic-pro', 'coming-soon-supsystic-pro', 'price-table-supsystic-pro', 'tables-generator-pro',
196
+ 'social-share-pro', 'popup-by-supsystic-pro', 'supsystic_slider_pro', 'supsystic-gallery-pro', 'google-maps-easy-pro',
197
+ 'backup-supsystic-pro',
198
+ );
199
+ $activePluginsList = get_option('active_plugins', array());
200
+ $activeProPluginsCount = 0;
201
+ foreach($activePluginsList as $actPl) {
202
+ foreach($proPluginsList as $proPl) {
203
+ if(strpos($actPl, $proPl) !== false) {
204
+ $activeProPluginsCount++;
205
+ }
206
+ }
207
+ }
208
+ if($activeProPluginsCount === 1) {
209
+ $twig = $this->getEnvironment()->getTwig();
210
+ $twig->display('@promo/discountMessage.twig', array(
211
+ 'bundlePageLink' => '//supsystic.com/all-plugins/',
212
+ 'buyLink' => $this->getDiscountBuyUrl(),
213
+ ));
214
+ }
215
+ }
216
+ }
217
+
218
+ public function getDiscountBuyUrl() {
219
+ $environment = $this->getEnvironment();
220
+ $pluginCode = $environment->getConfig()->get('plugin_product_code');
221
+ $license = $environment->getModule('license')->getHelper()->getCredentials();
222
+ $license['key'] = md5($license['key']);
223
+ $license = urlencode(base64_encode(implode('|', $license)));
224
+ return 'http://supsystic.com/?mod=manager&pl=lms&action=extend&plugin_code='. $pluginCode. '&lic='. $license;
225
+ }
226
+
227
+ public function checkPluginDeactivation() {
228
+ if(function_exists('get_current_screen')) {
229
+ $screen = get_current_screen();
230
+ if($screen && isset($screen->base) && $screen->base == 'plugins') {
231
+ $twig = $this->getEnvironment()->getTwig();
232
+ $twig->display('@promo/pluginDeactivation.twig', array(
233
+ 'pluginName' => $this->getConfig()->get('plugin_title_name'),
234
+ ));
235
+ $modulePath = untrailingslashit(plugin_dir_url(__FILE__));
236
+ wp_enqueue_script('jquery-ui-dialog');
237
+ wp_enqueue_script(
238
+ $this->config('db_prefix'). 'plug-deactivation',
239
+ $modulePath . '/assets/js/admin.plugins.js',
240
+ array('jquery-ui-dialog')
241
+ );
242
+ // And you will ask - "So, why we actyally have OOP, MVC and other patterns here -
243
+ // if only one possibility to acomplish your goal - is to make such dump codes?"
244
+ // And I will answer - "I don't know" ........
245
+ $pluginPath = $this->getEnvironment()->getPluginPath();
246
+ $pluginDirName = basename($pluginPath);
247
+ $pluginUrl = plugin_dir_url($pluginPath). $pluginDirName. '/';
248
+
249
+ wp_enqueue_script('jquery-ui-dialog');
250
+
251
+ /*$ui->createStyle('tables-ui-styles')
252
+ ->setHookName($hookName)
253
+ ->setLocalSource('css/supsystic-ui.css')*/
254
+
255
+ wp_enqueue_style('tables-ui-styles', $pluginUrl. '/app/assets/css/supsystic-ui.css');
256
+ //wp_enqueue_style('supsystic-jquery-ui', $pluginUrl. '/app/assets/css/jquery-ui.min.css');
257
+ //wp_enqueue_style('supsystic-jquery-ui.theme', $pluginUrl. '/app/assets/css/jquery-ui.theme.min.css');
258
+ //wp_enqueue_style('supsystic-jquery-ui.structure', $pluginUrl. '/app/assets/css/jquery-ui.structure.min.css');
259
+ wp_enqueue_style('jquery-ui','//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/themes/smoothness/jquery-ui.css');
260
+ wp_enqueue_style('supsystic-font-awesome', '//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css');
261
+
262
+ wp_localize_script($this->config('db_prefix'). 'plug-deactivation', 'dtsPluginsData', array(
263
+ 'plugName' => $pluginDirName. '/index.php',
264
+ ));
265
+
266
+ /*framePtw::_()->getModule('templates')->loadCoreJs();
267
+ framePtw::_()->getModule('templates')->loadCoreCss();
268
+ framePtw::_()->getModule('templates')->loadJqueryUi();
269
+ */
270
+ }
271
+ }
272
+ }
273
  }
src/SupsysticTables/Promo/assets/js/admin.plugins.js ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function(){
2
+ // yeah, I know - that there are core.js, but I will not load 2k rows file - only for those 2 things for now
3
+ function createSpinner(elem) {
4
+ elem = typeof(elem) != 'undefined' ? elem : false;
5
+
6
+ if(elem) {
7
+ var icon = elem.attr('disabled', true).find('.fa');
8
+
9
+ if(icon) {
10
+ icon.data('icon', icon.attr('class'));
11
+ icon.attr('class', 'fa fa-spinner fa-spin');
12
+ }
13
+ } else {
14
+ return $('<i/>', { class: 'fa fa-spinner fa-spin' });
15
+ }
16
+ }
17
+ function deleteSpinner(elem) {
18
+ var icon = elem.attr('disabled', false).find('.fa');
19
+
20
+ if(icon) {
21
+ icon.attr('class', icon.data('icon'));
22
+ icon.data('icon', '');
23
+ }
24
+ }
25
+ if(typeof(g_dtsAnimationSpeed) == 'undefined') {
26
+ g_dtsAnimationSpeed = 300;
27
+ }
28
+ var $deactivateLnk = jQuery('#the-list tr[data-plugin="'+ dtsPluginsData.plugName+ '"] .row-actions .deactivate a');
29
+ if($deactivateLnk && $deactivateLnk.length > 0) {
30
+ var $deactivateForm = jQuery('#dtsDeactivateForm');
31
+ var $deactivateWnd = jQuery('#dtsDeactivateWnd').dialog({
32
+ modal: true
33
+ , autoOpen: false
34
+ , width: 500
35
+ , height: 390
36
+ , buttons: {
37
+ 'Submit & Deactivate': function() {
38
+ $deactivateForm.submit();
39
+ }
40
+ }
41
+ });
42
+ var $wndButtonset = $deactivateWnd.parents('.ui-dialog:first')
43
+ .find('.ui-dialog-buttonpane .ui-dialog-buttonset')
44
+ , $deactivateDlgBtn = $deactivateWnd.find('.dtsDeactivateSkipDataBtn')
45
+ , deactivateUrl = $deactivateLnk.attr('href');
46
+ $deactivateDlgBtn.attr('href', deactivateUrl);
47
+ $wndButtonset.append( $deactivateDlgBtn );
48
+ $deactivateLnk.click(function(){
49
+ $deactivateWnd.dialog('open');
50
+ return false;
51
+ });
52
+
53
+ $deactivateForm.submit(function(){
54
+ if(typeof(ajaxurl) == 'undefined') {
55
+ window.location.href = deactivateUrl;
56
+ return false;
57
+ }
58
+ var $btn = $wndButtonset.find('button:first');
59
+ $btn.width( $btn.width() ); // Ha:)
60
+ createSpinner($btn);
61
+ // TODO: Re-make this to new framework workflow
62
+ jQuery.post(ajaxurl,
63
+ {
64
+ action: 'supsystic-tables',
65
+ route: {
66
+ module: 'promo',
67
+ action: 'saveDeactivateData'
68
+ },
69
+ deactivate_reason: $deactivateForm.find('[name="deactivate_reason"]').val(),
70
+ better_plugin: $deactivateForm.find('[name="better_plugin"]').val(),
71
+ other: $deactivateForm.find('[name="other"]').val(),
72
+ })
73
+ .always(function (res) {
74
+ deleteSpinner($btn);
75
+ window.location.href = deactivateUrl
76
+ });
77
+ return false;
78
+
79
+ });
80
+ $deactivateForm.find('[name="deactivate_reason"]').change(function(){
81
+ jQuery('.dtsDeactivateDescShell').slideUp( g_dtsAnimationSpeed );
82
+ if(jQuery(this).prop('checked')) {
83
+ var $descShell = jQuery(this).parents('.dtsDeactivateReasonShell:first').find('.dtsDeactivateDescShell');
84
+ if($descShell && $descShell.size()) {
85
+ $descShell.slideDown( g_dtsAnimationSpeed );
86
+ }
87
+ }
88
+ });
89
+ }
90
+ });
src/SupsysticTables/Promo/views/discountMessage.twig ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <style>
2
+ .supsystic-container .bundleMessageShell {
3
+ background-color: #ffffff;
4
+ padding: 10px 10px 0 10px;
5
+ margin-bottom: -20px;
6
+ }
7
+ .supsystic-container .bundleMessage {
8
+ border: 3px solid #52bac5;
9
+ text-align: center;
10
+ padding: 10px;
11
+ vertical-align: middle;
12
+ }
13
+ .supsystic-container .bundleMessage .text {
14
+ font-size: 21px;
15
+ line-height: 28px;
16
+ vertical-align: middle;
17
+ }
18
+ .supsystic-container .bundleMessage .text a {
19
+ color: #52bac5;
20
+ }
21
+ .supsystic-container .bundleMessage .button {
22
+ height: 40px !important;
23
+ line-height: 40px !important;
24
+ font-size: 17px !important;
25
+ background-color: #52bac5 !important;
26
+ border: none!important;
27
+ color: #fff !important;
28
+ padding: 0 26px!important;
29
+ margin-left: 20px;
30
+ vertical-align: middle;
31
+ }
32
+ </style>
33
+ <div class="bundleMessageShell">
34
+ <div class="bundleMessage">
35
+ <span class="text">{{ environment.translate('Upgrade to bundle and get an access to <a href="%s" target="_blank">all 14 plugins</a> more than 80%% off!') |format(bundlePageLink)|raw }}</span>
36
+ <a href="{{ buyLink }}" class="button" target="_blank">{{ environment.translate('Buy Now') }}</a>
37
+ </div>
38
+ </div>
src/SupsysticTables/Promo/views/pluginDeactivation.twig ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <style type="text/css">
2
+ .dtsDeactivateDescShell {
3
+ display: none;
4
+ margin-left: 25px;
5
+ margin-top: 5px;
6
+ }
7
+ .dtsDeactivateReasonShell {
8
+ display: block;
9
+ margin-bottom: 10px;
10
+ }
11
+ #dtsDeactivateWnd input[type="text"],
12
+ #dtsDeactivateWnd textarea {
13
+ width: 100%;
14
+ }
15
+ #dtsDeactivateWnd h4 {
16
+ line-height: 1.53em;
17
+ }
18
+ #dtsDeactivateWnd + .ui-dialog-buttonpane .ui-dialog-buttonset {
19
+ float: none;
20
+ }
21
+ .dtsDeactivateSkipDataBtn {
22
+ float: right;
23
+ margin-top: 7px;
24
+ text-decoration: none;
25
+ color: #777 !important;
26
+ }
27
+
28
+ .dtsDeactivateReasonShell input[type="radio"]:checked::before {
29
+ width: 6px !important;
30
+ }
31
+ .ui-widget-content .dtsDeactivateReasonShell input[type="radio"] {
32
+ width: 16px;
33
+ height: 16px;
34
+ }
35
+ </style>
36
+ <div id="dtsDeactivateWnd" style="display: none;" title="{{ environment.translate('Your Feedback') }}">
37
+ <h4>{{ environment.translate('If you have a moment, please share why you are deactivating %s')|format(pluginName) }}</h4>
38
+ <form id="dtsDeactivateForm">
39
+ <label class="dtsDeactivateReasonShell">
40
+ <input type="radio" name="deactivate_reason" value="not_working" />
41
+ {{ environment.translate("Couldn\'t get the plugin to work") }}
42
+ <div class="dtsDeactivateDescShell">
43
+ {{ environment.translate('If you have a question, <a href="%s" target="_blank">contact us</a> and will do our best to help you')|format('https://supsystic.com/contact-us/')|raw }}
44
+ </div>
45
+ </label>
46
+ <label class="dtsDeactivateReasonShell">
47
+ <input type="radio" name="deactivate_reason" value="found_better" />
48
+ {{ environment.translate('I found a better plugin') }}
49
+ <div class="dtsDeactivateDescShell">
50
+ <input type="text" name="better_plugin" placeholder="{{ environment.translate("If it\'s possible, specify plugin name") }}">
51
+ </div>
52
+ </label>
53
+ <label class="dtsDeactivateReasonShell">
54
+ <input type="radio" name="deactivate_reason" value="not_need" />
55
+ {{ environment.translate('I no longer need the plugin') }}
56
+ </label>
57
+ <label class="dtsDeactivateReasonShell">
58
+ <input type="radio" name="deactivate_reason" value="temporary" />
59
+ {{ environment.translate("It\'s a temporary deactivation") }}
60
+ </label>
61
+ <label class="dtsDeactivateReasonShell">
62
+ <input type="radio" name="deactivate_reason" value="other" />
63
+ {{ environment.translate('Other') }}
64
+ <div class="dtsDeactivateDescShell">
65
+ <input type="text" name="other" placeholder="{{ environment.translate('What is the reason?') }}">
66
+ </div>
67
+ </label>
68
+ </form>
69
+ <a href="" class="dtsDeactivateSkipDataBtn">{{ environment.translate('Skip & Deactivate') }}</a>
70
+ </div>
src/SupsysticTables/Tables/Controller.php CHANGED
@@ -223,7 +223,7 @@ class SupsysticTables_Tables_Controller extends SupsysticTables_Core_BaseControl
223
  $footer = (int)$request->post->get('footer');
224
  $table = $tables->getById($id);
225
 
226
- if($this->getEnvironment()->isWooPro() && isset($table->woo_settings) && $table->woo_settings['woocommerce']['enable'] === 'on'){
227
  $rows = $this->getEnvironment()->getModule('woocommerce')->getController()->getRowsByPart($id, array(), $start, $length, $searchAll['value']);
228
  }else{
229
  $rows = $tables->getRowsByPart($id, ($searchAll['value'] == '' ? false : $searchAll['value']), $searchCols, $orderCol, $orderAsc, $start, $length, $header, $footer, $searchParams, $table);
@@ -381,7 +381,7 @@ class SupsysticTables_Tables_Controller extends SupsysticTables_Core_BaseControl
381
  )
382
  );
383
  }
384
-
385
  return $this->ajaxSuccess();
386
  }
387
 
@@ -421,8 +421,21 @@ class SupsysticTables_Tables_Controller extends SupsysticTables_Core_BaseControl
421
  $tables = $this->getEnvironment()->getModule('tables');
422
  $id = $request->post->get('id');
423
  $tables->setIniLimits();
424
-
425
- return $this->ajaxSuccess(array('table' => $tables->render((int)$id)));
 
 
 
 
 
 
 
 
 
 
 
 
 
426
  }
427
 
428
  /**
223
  $footer = (int)$request->post->get('footer');
224
  $table = $tables->getById($id);
225
 
226
+ if($this->getEnvironment()->isWooPro() && isset($table->woo_settings) && isset($table->woo_settings['woocommerce']['enable']) && $table->woo_settings['woocommerce']['enable'] === 'on'){
227
  $rows = $this->getEnvironment()->getModule('woocommerce')->getController()->getRowsByPart($id, array(), $start, $length, $searchAll['value']);
228
  }else{
229
  $rows = $tables->getRowsByPart($id, ($searchAll['value'] == '' ? false : $searchAll['value']), $searchCols, $orderCol, $orderAsc, $start, $length, $header, $footer, $searchParams, $table);
381
  )
382
  );
383
  }
384
+ $this->cleanCache($id);
385
  return $this->ajaxSuccess();
386
  }
387
 
421
  $tables = $this->getEnvironment()->getModule('tables');
422
  $id = $request->post->get('id');
423
  $tables->setIniLimits();
424
+ $data = $request->post->get('settings');
425
+ $settings = false;
426
+ if($data && !empty($data)) {
427
+ if(get_magic_quotes_gpc()) {
428
+ $data = stripslashes($data);
429
+ }
430
+ parse_str($data, $settings);
431
+ }
432
+ $preview = $request->post->get('preview');
433
+
434
+ $tables->isPreview = ($preview && $preview == 1);
435
+ if($tables->isPreview) {
436
+ $this->cleanCache($id);
437
+ }
438
+ return $this->ajaxSuccess(array('table' => $tables->render((int)$id, $settings)));
439
  }
440
 
441
  /**
src/SupsysticTables/Tables/Module.php CHANGED
@@ -28,6 +28,8 @@ class SupsysticTables_Tables_Module extends SupsysticTables_Core_BaseModule
28
  private $_tablesObj = array();
29
  private $_tablesStyles = array();
30
 
 
 
31
  /**
32
  * {@inheritdoc}
33
  */
@@ -56,7 +58,7 @@ class SupsysticTables_Tables_Module extends SupsysticTables_Core_BaseModule
56
  add_action('shutdown', array($this, 'onShutdown'));
57
  $dispatcher = $this->getEnvironment()->getDispatcher();
58
  $dispatcher->on('after_tables_loaded', array($this, 'onAfterLoaded'));
59
- $this->renderTableHistorySection();
60
 
61
  add_filter('jetpack_lazy_images_blacklisted_classes', array($this, 'excludeFromLazyLoad'), 999, 1);
62
  }
@@ -118,15 +120,43 @@ class SupsysticTables_Tables_Module extends SupsysticTables_Core_BaseModule
118
  public function addDataTableStyles($tableViewId) {
119
  $tableObj = is_object($tableViewId) ? $tableViewId : $this->_tablesObj[$tableViewId];
120
  array_push($this->_tablesStyles, $tableObj->view_id);
 
 
121
 
122
- if(!empty($tableObj->meta) && !empty($tableObj->meta)) {
123
  $styles = $tableObj->meta['css'];
124
  $styles = trim(preg_replace('/\/\*.*\*\//Us', '', $styles));
125
-
126
- if(!empty($styles)) {
127
- return $this->getTwig()->render('@tables/styles.twig', array('tableObj' => $tableObj));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  }
129
  }
 
 
 
 
 
 
 
 
 
 
130
  return '';
131
  }
132
 
@@ -210,7 +240,7 @@ class SupsysticTables_Tables_Module extends SupsysticTables_Core_BaseModule
210
  * @param int $id
211
  * @return string
212
  */
213
- public function render($id)
214
  {
215
  if($this->disallowIndexing($id)) {
216
  return;
@@ -238,6 +268,15 @@ class SupsysticTables_Tables_Module extends SupsysticTables_Core_BaseModule
238
  if (!$table) {
239
  return sprintf($environment->translate('The table with ID %d not exists.'), $id);
240
  }
 
 
 
 
 
 
 
 
 
241
  $table->isSSP = (!$this->isSingleCell
242
  && !$this->isTablePart
243
  && isset($table->settings['features']['paging'])
@@ -245,7 +284,6 @@ class SupsysticTables_Tables_Module extends SupsysticTables_Core_BaseModule
245
  && isset($table->settings['serverSideProcessing'])
246
  && $table->settings['serverSideProcessing'] == 'on'
247
  );
248
- $table->isDB = ($environment->isPro() && !$this->isSingleCell && !$this->isTablePart && isset($table->settings['source']) && isset($table->settings['source']['database']) && $table->settings['source']['database'] == 'on');
249
 
250
  if(!isset($table->isPageRows)) {
251
  $table->isPageRows = false;
@@ -253,7 +291,8 @@ class SupsysticTables_Tables_Module extends SupsysticTables_Core_BaseModule
253
  $this->checkSpreadsheet = $this->checkSpreadsheet && !$table->isPageRows
254
  && $environment->isPro()
255
  && isset($table->settings['features']['import']['google']['automatically_update'])
256
- && isset($table->settings['features']['import']['google']['link']);
 
257
 
258
  if (!$table->isSSP
259
  && !isset($table->settings['disableCache'])
@@ -356,6 +395,9 @@ class SupsysticTables_Tables_Module extends SupsysticTables_Core_BaseModule
356
  }
357
  }
358
  }
 
 
 
359
  foreach($table->rows as $key => $row) {
360
  if(isset($row['cells']) && !empty($row['cells'])) {
361
  foreach($row['cells'] as $index => $cell) {
@@ -396,7 +438,26 @@ class SupsysticTables_Tables_Module extends SupsysticTables_Core_BaseModule
396
  $this->tableSearch = '';
397
  }
398
 
399
- $renderData = $twig->render($this->getShortcodeTemplate(), array('table' => $table, 'is_feed' => is_feed()));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
400
  $renderData = preg_replace('/\s+/', ' ', trim($renderData));
401
 
402
  if(!$table->isSSP && !in_array($table->view_id, $this->_tablesStyles)) {
@@ -412,6 +473,10 @@ class SupsysticTables_Tables_Module extends SupsysticTables_Core_BaseModule
412
  return $renderData;
413
  }
414
 
 
 
 
 
415
  public function getMirrorFooter($table) {
416
  $footer = array();
417
 
@@ -903,7 +968,7 @@ class SupsysticTables_Tables_Module extends SupsysticTables_Core_BaseModule
903
 
904
  $ui->add(
905
  $ui->createStyle('supsystic-tables-datatables-responsive-css')
906
- ->setHookName($frontendHookName)
907
  ->setSource($coreModulePath . '/assets/css/lib/responsive.dataTables.min.css')
908
  ->setVersion('2.0.2')
909
  ->setCachingAllowed(true)
@@ -936,7 +1001,7 @@ class SupsysticTables_Tables_Module extends SupsysticTables_Core_BaseModule
936
 
937
  $ui->add(
938
  $ui->createScript('supsystic-tables-datatables-responsive-js')
939
- ->setHookName($frontendHookName)
940
  ->setSource($coreModulePath . '/assets/js/lib/dataTables.responsive.min.js')
941
  ->setVersion('2.0.2')
942
  ->setCachingAllowed(true)
@@ -1327,7 +1392,7 @@ class SupsysticTables_Tables_Module extends SupsysticTables_Core_BaseModule
1327
  /**
1328
  * Runs the callbacks after the table editor tabs rendered.
1329
  */
1330
- private function renderTableHistorySection()
1331
  {
1332
  $dispatcher = $this->getEnvironment()->getDispatcher();
1333
 
@@ -1336,17 +1401,18 @@ class SupsysticTables_Tables_Module extends SupsysticTables_Core_BaseModule
1336
  }
1337
 
1338
  /**
1339
- * Renders the "TableHistory" tab.
1340
  * @param \stdClass $table Current table
1341
  */
1342
  public function afterTabsRendered()
1343
  {
1344
  $twig = $this->getEnvironment()->getTwig();
1345
  $twig->display('@tables/partials/historyTab.twig', array());
 
1346
  }
1347
 
1348
  /**
1349
- * Renders the "TableHistory" tab content.
1350
  * @param \stdClass $table Current table
1351
  */
1352
  public function afterTabsContentRendered($table)
@@ -1358,7 +1424,12 @@ class SupsysticTables_Tables_Module extends SupsysticTables_Core_BaseModule
1358
  $dispatcher->apply('table_history_tabs_content_template', array('@tables/partials/historyTabContent.twig')),
1359
  $dispatcher->apply('table_history_tabs_content_data', array(array( 'table' => $table )))
1360
  );
 
 
 
 
1361
  }
 
1362
  public function getShortcodesList()
1363
  {
1364
  $environment = $this->getEnvironment();
28
  private $_tablesObj = array();
29
  private $_tablesStyles = array();
30
 
31
+ public $isPreview = false;
32
+
33
  /**
34
  * {@inheritdoc}
35
  */
58
  add_action('shutdown', array($this, 'onShutdown'));
59
  $dispatcher = $this->getEnvironment()->getDispatcher();
60
  $dispatcher->on('after_tables_loaded', array($this, 'onAfterLoaded'));
61
+ $this->renderTableProSections();
62
 
63
  add_filter('jetpack_lazy_images_blacklisted_classes', array($this, 'excludeFromLazyLoad'), 999, 1);
64
  }
120
  public function addDataTableStyles($tableViewId) {
121
  $tableObj = is_object($tableViewId) ? $tableViewId : $this->_tablesObj[$tableViewId];
122
  array_push($this->_tablesStyles, $tableObj->view_id);
123
+ $styles = '';
124
+ $customStyles = '';
125
 
126
+ if(!empty($tableObj->meta) && !empty($tableObj->meta) && isset($tableObj->meta['css'])) {
127
  $styles = $tableObj->meta['css'];
128
  $styles = trim(preg_replace('/\/\*.*\*\//Us', '', $styles));
129
+ }
130
+ if(isset($tableObj->settings['styles']) && isset($tableObj->settings['styles']['useCustomStyles'])) {
131
+ $standardFontsList = $this->getStandardFontsList();
132
+ $allFontsList = $this->getFontsList();
133
+
134
+ if(isset($tableObj->settings['styles']['headerFontFamily'])) {
135
+ $family = $tableObj->settings['styles']['headerFontFamily'];
136
+ if(in_array($family, $allFontsList) && !in_array($family, $standardFontsList)) {
137
+ $customStyles = '@import url("//fonts.googleapis.com/css?family='.str_replace(' ', '+', $family).'");';
138
+ }
139
+ }
140
+ if(isset($tableObj->settings['styles']['cellFontFamily'])) {
141
+ $family = $tableObj->settings['styles']['cellFontFamily'];
142
+ if(in_array($family, $allFontsList) && !in_array($family, $standardFontsList)) {
143
+ $customStyles .= '@import url("//fonts.googleapis.com/css?family='.str_replace(' ', '+', $family).'");';
144
+ }
145
+ }
146
+ if(!$this->isPreview) {
147
+ $customStyles .= str_replace('supsystic-table-{id}', 'supsystic-table-'.$tableObj->id, $tableObj->settings['styles']['customCss']);
148
  }
149
  }
150
+
151
+ if(!empty($styles) || !empty($customStyles)) {
152
+ return $this->getTwig()->render('@tables/styles.twig',
153
+ array(
154
+ 'viewId' => $tableObj->view_id,
155
+ 'styles' => empty($styles) ? '' : $tableObj->meta['css'],
156
+ 'customStyles' => $customStyles
157
+ )
158
+ );
159
+ }
160
  return '';
161
  }
162
 
240
  * @param int $id
241
  * @return string
242
  */
243
+ public function render($id, $settings = false)
244
  {
245
  if($this->disallowIndexing($id)) {
246
  return;
268
  if (!$table) {
269
  return sprintf($environment->translate('The table with ID %d not exists.'), $id);
270
  }
271
+ $table->isDB = ($environment->isPro() && !$this->isSingleCell && !$this->isTablePart && isset($table->settings['source']) && isset($table->settings['source']['database']) && $table->settings['source']['database'] == 'on');
272
+
273
+ if($settings) {
274
+ if($table->isDB) {
275
+ $settings['source'] = $table->settings['source'];
276
+ }
277
+ $settings['disableCache'] = 'on';
278
+ $table->settings = $settings;
279
+ }
280
  $table->isSSP = (!$this->isSingleCell
281
  && !$this->isTablePart
282
  && isset($table->settings['features']['paging'])
284
  && isset($table->settings['serverSideProcessing'])
285
  && $table->settings['serverSideProcessing'] == 'on'
286
  );
 
287
 
288
  if(!isset($table->isPageRows)) {
289
  $table->isPageRows = false;
291
  $this->checkSpreadsheet = $this->checkSpreadsheet && !$table->isPageRows
292
  && $environment->isPro()
293
  && isset($table->settings['features']['import']['google']['automatically_update'])
294
+ && isset($table->settings['features']['import']['google']['link'])
295
+ && !empty($table->settings['features']['import']['google']['link']);
296
 
297
  if (!$table->isSSP
298
  && !isset($table->settings['disableCache'])
395
  }
396
  }
397
  }
398
+ if(!empty($table->meta['mergedCells'])) {
399
+ unset($table->settings['features']['ordering']);
400
+ }
401
  foreach($table->rows as $key => $row) {
402
  if(isset($row['cells']) && !empty($row['cells'])) {
403
  foreach($row['cells'] as $index => $cell) {
438
  $this->tableSearch = '';
439
  }
440
 
441
+ $show_edit_link = '';
442
+ if( is_user_logged_in() ) {
443
+ $user = wp_get_current_user();
444
+ $roles = is_array($user->roles) ? $user->roles : array($user->roles);
445
+ $pluginSettings = get_option($this->getController()->getConfig()->get('db_prefix') . 'settings', 'access_roles');
446
+ if (!empty($roles) && !empty($pluginSettings)) {
447
+ foreach ($roles as $role) {
448
+ if (in_array($role, $pluginSettings)) {
449
+ $show_edit_link = $this->_getTblLink($id);
450
+ break;
451
+ }
452
+ }
453
+ }
454
+
455
+ if (current_user_can('manage_options')) {
456
+ $show_edit_link = $this->_getTblLink($id);
457
+ }
458
+ }
459
+
460
+ $renderData = $twig->render($this->getShortcodeTemplate(), array('table' => $table, 'is_feed' => is_feed(), 'show_edit_link' => $show_edit_link));
461
  $renderData = preg_replace('/\s+/', ' ', trim($renderData));
462
 
463
  if(!$table->isSSP && !in_array($table->view_id, $this->_tablesStyles)) {
473
  return $renderData;
474
  }
475
 
476
+ private function _getTblLink($id) {
477
+ return "<a href=".$this->getController()->generateUrl('tables', 'view', array( 'id' => $id ) ).">". $this->getEnvironment()->translate('Edit'). " <i class='fa fa-fw fa-pencil'></i></a>";
478
+ }
479
+
480
  public function getMirrorFooter($table) {
481
  $footer = array();
482
 
968
 
969
  $ui->add(
970
  $ui->createStyle('supsystic-tables-datatables-responsive-css')
971
+ ->setHookName($dynamicHookName)
972
  ->setSource($coreModulePath . '/assets/css/lib/responsive.dataTables.min.css')
973
  ->setVersion('2.0.2')
974
  ->setCachingAllowed(true)
1001
 
1002
  $ui->add(
1003
  $ui->createScript('supsystic-tables-datatables-responsive-js')
1004
+ ->setHookName($dynamicHookName)
1005
  ->setSource($coreModulePath . '/assets/js/lib/dataTables.responsive.min.js')
1006
  ->setVersion('2.0.2')
1007
  ->setCachingAllowed(true)
1392
  /**
1393
  * Runs the callbacks after the table editor tabs rendered.
1394
  */
1395
+ private function renderTableProSections()
1396
  {
1397
  $dispatcher = $this->getEnvironment()->getDispatcher();
1398
 
1401
  }
1402
 
1403
  /**
1404
+ * Renders the "TableHistory" and "Source" tab.
1405
  * @param \stdClass $table Current table
1406
  */
1407
  public function afterTabsRendered()
1408
  {
1409
  $twig = $this->getEnvironment()->getTwig();
1410
  $twig->display('@tables/partials/historyTab.twig', array());
1411
+ $twig->display('@tables/partials/sourceTab.twig', array());
1412
  }
1413
 
1414
  /**
1415
+ * Renders the "TableHistory" and "Source" tabs content.
1416
  * @param \stdClass $table Current table
1417
  */
1418
  public function afterTabsContentRendered($table)
1424
  $dispatcher->apply('table_history_tabs_content_template', array('@tables/partials/historyTabContent.twig')),
1425
  $dispatcher->apply('table_history_tabs_content_data', array(array( 'table' => $table )))
1426
  );
1427
+ $twig->display(
1428
+ $dispatcher->apply('table_source_tabs_content_template', array('@tables/partials/sourceTabContent.twig')),
1429
+ $dispatcher->apply('table_source_tabs_content_data', array(array( 'table' => $table )))
1430
+ );
1431
  }
1432
+
1433
  public function getShortcodesList()
1434
  {
1435
  $environment = $this->getEnvironment();
src/SupsysticTables/Tables/assets/css/tables.shortcode.css CHANGED
@@ -225,6 +225,11 @@ table.oneColumnWithLabels tr:not(.haveMergedCell) td:after {
225
  padding: 4px;
226
  }
227
 
 
 
 
 
 
228
  /* For search by hidden cells and for invisible cells */
229
  .supsystic-tables-wrap table.supsystic-table tr .hiddenCell, .supsystic-tables-wrap table.supsystic-table tr .invisibleCell {
230
  display: none !important;
@@ -269,4 +274,11 @@ table.dataTable input.search-column {
269
  .dataTables_wrapper table td,
270
  .dataTables_wrapper table th {
271
  word-break: unset!important;
 
 
 
 
 
 
 
272
  }
225
  padding: 4px;
226
  }
227
 
228
+ /* For of applying unneeded scroll to fixed columns */
229
+ .supsystic-tables-wrap .DTFC_LeftWrapper .supsystic-table, .supsystic-tables-wrap .DTFC_RightWrapper .supsystic-table {
230
+ border-right: none;
231
+ }
232
+
233
  /* For search by hidden cells and for invisible cells */
234
  .supsystic-tables-wrap table.supsystic-table tr .hiddenCell, .supsystic-tables-wrap table.supsystic-table tr .invisibleCell {
235
  display: none !important;
274
  .dataTables_wrapper table td,
275
  .dataTables_wrapper table th {
276
  word-break: unset!important;
277
+ }
278
+ .supsystic-tables-wrap table.supsystic-table.stripe, .supsystic-tables-wrap table.supsystic-table.hover td {
279
+ background-color: inherit;
280
+ }
281
+ /*Disable Edit Link that was placed wrong in plugin before*/
282
+ .supsystic-tables-wrap > a {
283
+ display: none;
284
  }
src/SupsysticTables/Tables/assets/css/tables.view.css CHANGED
@@ -84,7 +84,8 @@
84
  top: -100%;
85
  z-index: -1;
86
  margin: 0;
87
- margin-top: 20px;
 
88
  }
89
  .tables-view .row-tab.active {
90
  opacity: 1;
@@ -193,10 +194,12 @@
193
  -moz-box-shadow: none;
194
  box-shadow: none;
195
  }
196
- .tables-view #settings input, .tables-view #settings select, .history-settings input, .history-settings select {
197
- width: 100% !important;
 
198
  }
199
- .tables-view #settings textarea {
 
200
  width: 100%;
201
  min-height: 100px;
202
  }
@@ -207,31 +210,123 @@
207
  .tables-view .tabs-settings {
208
  text-align: center;
209
  }
210
- .tables-view .row-settings-tabs {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
  clear: both;
212
  display: block;
213
- padding: 10px;
214
  }
215
- .tables-view .row-settings-tab {
216
  padding-bottom: 20px;
217
  }
218
- .tables-view .title-block {
219
- line-height: 40px;
220
- padding: 0 10px !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  .tables-view .title-place {
223
  line-height: 20px;
224
- padding: 0 15px;
225
  }
226
  .tables-view .title-place h3 {
227
  font-size: 16px;
228
  }
229
- .tables-view .title-block h3 {
230
- margin: 0;
231
- }
232
  .setting-wrapper {
233
- min-height: 30px;
234
- margin: 0 0 10px 0
 
 
 
 
 
 
 
235
  }
236
  .setting-item {
237
  min-height: 33px;
@@ -260,7 +355,8 @@
260
  margin-right: 8px;
261
  }
262
  .sub-label {
263
- line-height: 33px;
 
264
  }
265
  .sub-label, .sub-input, .tables-view #settings .sub-input {
266
  float: left;
@@ -282,13 +378,13 @@
282
  float: none !important;
283
  }
284
  /* supsystic-ui settings */
285
- .tables-view .row-settings-tab .icheckbox_minimal, .tables-view .row-settings-tab .iradio_minimal {
286
  float: left;
287
  }
288
  #row-tab-woocommerce .icheckbox_minimal{
289
  float: left;
290
  }
291
- .tables-view .row-settings-tab .icheckbox_minimal {
292
  margin-top: 8px;
293
  }
294
 
@@ -381,6 +477,36 @@
381
  height: 100%;
382
  border: 1px solid;
383
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
384
 
385
  @media (max-width: 810px) {
386
  .wp-core-ui .button {
@@ -473,3 +599,75 @@
473
  color: #000;
474
  text-decoration: underline;
475
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  top: -100%;
85
  z-index: -1;
86
  margin: 0;
87
+ margin-top: 20px;
88
+ max-width: 100%;
89
  }
90
  .tables-view .row-tab.active {
91
  opacity: 1;
194
  -moz-box-shadow: none;
195
  box-shadow: none;
196
  }
197
+ .tables-view #settings input, .tables-view #settings select,
198
+ .tables-view .tabs-content input, .tabs-content select {
199
+ width: 100%;/* !important;*/
200
  }
201
+ .tables-view #settings textarea,
202
+ .tables-view .tabs-content textarea {
203
  width: 100%;
204
  min-height: 100px;
205
  }
210
  .tables-view .tabs-settings {
211
  text-align: center;
212
  }
213
+ /* settings panel */
214
+ .tables-view .settings-section {
215
+ width: 280px;
216
+ float: left;
217
+ }
218
+ .tables-view .preview-section {
219
+ min-width: 250px;
220
+ padding-left: 20px;
221
+ overflow: hidden;
222
+ }
223
+ @media (max-width: 782px) {
224
+ .tables-view .settings-section {
225
+ width: 100%;
226
+ }
227
+ .tables-view .preview-section {
228
+ width: 100%;
229
+ padding-left: 0;
230
+ padding-top: 10px;
231
+ }
232
+ }
233
+ .tables-view .preview-section .dataTables_processing {
234
+ z-index: 100;
235
+ top: 10px;
236
+ }
237
+ .tables-view .settings-wrap {
238
+ padding-left: 10px;
239
+ padding-right: 10px;
240
+ }
241
+ .tables-view .settings-wrap {
242
+ border: #ccc solid 1px;
243
+ }
244
+ .tables-view #preview-container {
245
+ overflow-y: auto;
246
+ }
247
+ #table-preview {
248
+ margin-left: auto;
249
+ margin-right: auto;
250
+ position: relative;
251
+ }
252
+ .tables-view .settings-wrap .row-settings-block .icheckbox_minimal {
253
+ margin-top: 3px;
254
+ }
255
+ .tables-view .settings-blocks {
256
  clear: both;
257
  display: block;
258
+ font-size: 14px;
259
  }
260
+ .tables-view .row-settings-block {
261
  padding-bottom: 20px;
262
  }
263
+ .tables-view .settings-block-title {
264
+ line-height: 20px;
265
+ border-bottom: #23282d 3px double;
266
+ margin-top: 2px;
267
+ margin-bottom: 10px;
268
+ }
269
+ .tables-view .settings-block-title h3 {
270
+ font-size: 16px;
271
+ margin: 5px 0;
272
+ }
273
+ .tables-view .setting-title {
274
+ line-height: 20px;
275
+ }
276
+ .tables-view .setting-title h3 {
277
+ font-size: 15px;
278
+ margin: 15px 0;
279
+ }
280
+ .setting-label, .setting-check, .setting-input {
281
+ min-height: 28px;
282
+ }
283
+ .setting-label {
284
+ float: left;
285
+ }
286
+ .setting-label {
287
+ width: 90%;
288
+ }
289
+ .setting-input {
290
+ width: 100%;
291
+ padding-right: 5px;
292
+ }
293
+ .setting-input, .setting-check {
294
+ float: right;
295
  }
296
+ .setting-label .fa-question.supsystic-tooltip {
297
+ float: none;
298
+ }
299
+ .setting-suboption {
300
+ padding-left: 15px;
301
+ }
302
+ .tables-view .settings-section input[type=text] {
303
+ height: 28px;
304
+ }
305
+ /* end settings panel */
306
+
307
+ .tables-view .preview-styling {
308
+ text-align: center;
309
+ }
310
+
311
+
312
+
313
  .tables-view .title-place {
314
  line-height: 20px;
315
+ /*padding: 0 15px;*/
316
  }
317
  .tables-view .title-place h3 {
318
  font-size: 16px;
319
  }
 
 
 
320
  .setting-wrapper {
321
+ min-height: 28px;
322
+ margin: 0 0 5px 0
323
+ }
324
+ .setting-wrapper:after {
325
+ clear: both;
326
+ }
327
+ .setting-wrapper:before, .setting-wrapper:after {
328
+ content: " ";
329
+ display: table;
330
  }
331
  .setting-item {
332
  min-height: 33px;
355
  margin-right: 8px;
356
  }
357
  .sub-label {
358
+ margin-top: 2px;
359
+ line-height: 28px;
360
  }
361
  .sub-label, .sub-input, .tables-view #settings .sub-input {
362
  float: left;
378
  float: none !important;
379
  }
380
  /* supsystic-ui settings */
381
+ .tables-view .row-settings-block .icheckbox_minimal, .tables-view .row-settings-block .iradio_minimal {
382
  float: left;
383
  }
384
  #row-tab-woocommerce .icheckbox_minimal{
385
  float: left;
386
  }
387
+ .tables-view .row-settings-block .icheckbox_minimal {
388
  margin-top: 8px;
389
  }
390
 
477
  height: 100%;
478
  border: 1px solid;
479
  }
480
+ .color-settings-wrapper {
481
+ display: flex;
482
+ text-align: right;
483
+ }
484
+ .color-picker-wrapper {
485
+ display: inline-block;
486
+ width: 28px;
487
+ height: 28px;
488
+ border: 1px solid;
489
+ }
490
+ .color-picker-preview {
491
+ display: inline-block;
492
+ width: 100%;
493
+ height: 100%;
494
+ }
495
+ .color-input {
496
+ width: 80px !important;
497
+ }
498
+ .input-small {
499
+ width: 40px !important;
500
+ }
501
+ .inner-label {
502
+ padding-left: 10px;
503
+ padding-right: 5px;
504
+ line-height: 28px;
505
+ }
506
+ .right-label {
507
+ padding-left: 5px;
508
+ line-height: 28px;
509
+ }
510
 
511
  @media (max-width: 810px) {
512
  .wp-core-ui .button {
599
  color: #000;
600
  text-decoration: underline;
601
  }
602
+ .preview-styling .stb-wraper-anchor-nav-links {
603
+ text-align: center;
604
+ }
605
+ .setting-wrapper-inline {
606
+ display:table;
607
+ width:100%;
608
+ }
609
+ .setting-wrapper-inline .setting-label {
610
+ display:table-cell;
611
+ width: auto;
612
+ float: none;
613
+ vertical-align:middle;
614
+ padding-right:4px;
615
+ white-space:nowrap;
616
+ }
617
+ .setting-wrapper-inline .setting-input {
618
+ display:inline-block;
619
+ width:inherit;
620
+ float:left;
621
+ }
622
+ .setting-wrapper-inline .setting-input input,
623
+ .setting-wrapper-inline .setting-input select {
624
+ width:100%;
625
+ }
626
+ .setting-input {
627
+ text-align:right;
628
+ }
629
+ .setting-input-inline {
630
+ display:table-cell;
631
+ width: auto;
632
+ float: none;
633
+ vertical-align:middle;
634
+ padding-right:4px;
635
+ white-space:nowrap;
636
+ }
637
+ .setting-input-inline .sub-label span {
638
+ padding: 0 5px 0 0px;
639
+ }
640
+ .setting-input-inline .iradio_minimal {
641
+ margin: 0px;
642
+ }
643
+ .setting-input-inline-wrapper {
644
+ display:table;
645
+ width:100%;
646
+ }
647
+ .setting-input-inline input {
648
+ width: 100%;
649
+ max-width: 90px;
650
+ }
651
+ .setting-input-divider {
652
+ display:block;
653
+ position:relative;
654
+ margin:10px 0px;
655
+ }
656
+ #editor-set-currency-format {
657
+ width:100px !important;
658
+ }
659
+ #editor-set-percent-format {
660
+ width:85px !important;
661
+ }
662
+ #editor-set-date-format {
663
+ width:123px !important;
664
+ }
665
+ #editor-set-time-duration-format {
666
+ width:90px !important;
667
+ }
668
+ #features-export-pdf-paper-size,
669
+ #autoIndex,
670
+ #styling-border,
671
+ #language-file {
672
+ width:96px !important;
673
+ }
src/SupsysticTables/Tables/assets/img/database.gif DELETED
Binary file
src/SupsysticTables/Tables/assets/img/history_table.gif DELETED
Binary file
src/SupsysticTables/Tables/assets/js/editor/tables.editor.js CHANGED
@@ -1,6 +1,7 @@
1
  var g_stbWindowHeight = 0;
2
  var g_stbPagination = false;
3
  var g_stbRowsPerPage = 1;
 
4
  (function ($, app, undefined) {
5
  $(document).ready(function() {
6
  g_stbWindowHeight = $(window).width() > 810 ? $(window).height() * 0.7 : $(window).height(); // 810px is mobile responsive width
@@ -25,7 +26,11 @@ var g_stbRowsPerPage = 1;
25
  fixedRowsTop: 0,
26
  fixedColumnsLeft: 0,
27
  comments: true,
28
- contextMenu: true,
 
 
 
 
29
  formulas: true,
30
  /*fillHandle: {
31
  autoInsertRow: false // Disable adding of new row during drag-down cell via right bottom corner
@@ -161,6 +166,7 @@ var g_stbRowsPerPage = 1;
161
  if(isForced) $(editor.table).find('a').attr('target', "_blank");
162
  });
163
  editor.addHook('beforeChange', function (changes, source) {
 
164
  $.each(changes, function (index, changeSet) {
165
  var row = changeSet[0],
166
  col = changeSet[1],
@@ -547,7 +553,7 @@ var g_stbRowsPerPage = 1;
547
  alert('Failed to load table data: ' + error);
548
  }).always(function (response) {
549
  $('#loadingProgress').remove();
550
- editor.render();
551
  $('#buttonSave').attr('disabled', false);
552
  g_stbDoSaving = false;
553
  });
@@ -705,10 +711,11 @@ var g_stbRowsPerPage = 1;
705
  }
706
  r++;
707
  }
708
- this.render();
709
  this.updateSettings({
710
  manualRowResize: true
711
  });
 
712
  }
713
  })();
714
 
@@ -768,6 +775,12 @@ var g_stbRowsPerPage = 1;
768
  }
769
  })();
770
 
 
 
 
 
 
 
771
  editor.getSourceDataPagination = (function () {
772
  return function (fromX, fromY, toX, toY) {
773
  this.copyInBuffer();
@@ -797,6 +810,16 @@ var g_stbRowsPerPage = 1;
797
  }
798
  })();
799
 
 
 
 
 
 
 
 
 
 
 
800
  Handsontable.dom.addEvent(window, 'hashchange', function (event) {
801
  if (g_stbPagination) {
802
  editor.setPageData();
1
  var g_stbWindowHeight = 0;
2
  var g_stbPagination = false;
3
  var g_stbRowsPerPage = 1;
4
+ var g_stbIsDataEdited = {'settings': false, 'source': false, 'history': false, 'woocommerce': false, 'data': false};
5
  (function ($, app, undefined) {
6
  $(document).ready(function() {
7
  g_stbWindowHeight = $(window).width() > 810 ? $(window).height() * 0.7 : $(window).height(); // 810px is mobile responsive width
26
  fixedRowsTop: 0,
27
  fixedColumnsLeft: 0,
28
  comments: true,
29
+ contextMenu: {
30
+ callback: function (key, selection, clickEvent) {
31
+ g_stbIsDataEdited['data'] = true;
32
+ }
33
+ },
34
  formulas: true,
35
  /*fillHandle: {
36
  autoInsertRow: false // Disable adding of new row during drag-down cell via right bottom corner
166
  if(isForced) $(editor.table).find('a').attr('target', "_blank");
167
  });
168
  editor.addHook('beforeChange', function (changes, source) {
169
+ g_stbIsDataEdited['data'] = true;
170
  $.each(changes, function (index, changeSet) {
171
  var row = changeSet[0],
172
  col = changeSet[1],
553
  alert('Failed to load table data: ' + error);
554
  }).always(function (response) {
555
  $('#loadingProgress').remove();
556
+ if(!g_stbPagination) editor.renderWithRecalc();
557
  $('#buttonSave').attr('disabled', false);
558
  g_stbDoSaving = false;
559
  });
711
  }
712
  r++;
713
  }
714
+
715
  this.updateSettings({
716
  manualRowResize: true
717
  });
718
+ this.renderWithRecalc();
719
  }
720
  })();
721
 
775
  }
776
  })();
777
 
778
+ editor.getCellValuePagination = (function () {
779
+ return function (row, col) {
780
+ return row >= this.pageStart && row <= this.pageStop ? this.getData()[row][col] : this.bufferData[row][col];
781
+ }
782
+ })();
783
+
784
  editor.getSourceDataPagination = (function () {
785
  return function (fromX, fromY, toX, toY) {
786
  this.copyInBuffer();
810
  }
811
  })();
812
 
813
+ editor.renderWithRecalc = (function () {
814
+ return function () {
815
+ var recalcLimit = 5;
816
+ do {
817
+ this.render();
818
+ recalcLimit--;
819
+ } while(this.plugin.matrix.needRecalc() && recalcLimit > 0);
820
+ }
821
+ })();
822
+
823
  Handsontable.dom.addEvent(window, 'hashchange', function (event) {
824
  if (g_stbPagination) {
825
  editor.setPageData();
src/SupsysticTables/Tables/assets/js/editor/tables.editor.toolbar.js CHANGED
@@ -763,6 +763,7 @@ var g_stbCellBgColorTimeoutSet = false,
763
  $button.unbind(event);
764
  $button.on(event, function (e) {
765
  e.preventDefault();
 
766
 
767
  if (/word-wrap-default|word-wrap-visible|word-wrap-hidden/.test(method)) {
768
  $('#toolbar-word-wrapping i')
763
  $button.unbind(event);
764
  $button.on(event, function (e) {
765
  e.preventDefault();
766
+ g_stbIsDataEdited['data'] = true;
767
 
768
  if (/word-wrap-default|word-wrap-visible|word-wrap-hidden/.test(method)) {
769
  $('#toolbar-word-wrapping i')
src/SupsysticTables/Tables/assets/js/tables.model.js CHANGED
@@ -1,6 +1,9 @@
1
  var g_stbDoSaving = true; //waiting for the end of downloads
2
  var g_stbDoPreview = false;
 
 
3
  var g_stbPreviewTimeoutSet = false;
 
4
  (function ($, app) {
5
 
6
  var TablesModel = (function () {
@@ -92,12 +95,11 @@ var g_stbPreviewTimeoutSet = false;
92
  return deferred.promise();
93
  };
94
 
95
- TablesModel.prototype.setRows = function (id, rows, byPart, preview) {
96
  if (isNaN(id = parseInt(id))) {
97
  throw new Error('Invalid table id.');
98
  }
99
  byPart = typeof(byPart) != 'undefined' ? byPart : false;
100
- preview= typeof(preview) != 'undefined' ? preview : false;
101
 
102
  if(byPart) {
103
  var self = this,
@@ -127,19 +129,18 @@ var g_stbPreviewTimeoutSet = false;
127
  });
128
  });
129
  ajaxPromise = ajaxPromise.then(function() {
130
- app.deleteSpinner($('#buttonSave'));
131
- g_stbDoSaving = false;
132
  });
133
- if(preview) {
134
- ajaxPromise = ajaxPromise.then(function() {
135
- self.getPreview(id, preview);
136
- });
137
- }
138
  } else {
139
  return this.request('updateRows', { id: id, rows: this._prepareData(rows) });
140
  }
141
  };
142
 
 
 
 
 
 
143
  TablesModel.prototype.getMeta = function (id) {
144
  if (isNaN(id = parseInt(id))) {
145
  throw new Error('Invalid table id.');
@@ -167,12 +168,16 @@ var g_stbPreviewTimeoutSet = false;
167
  return this.settingsRequest('getSettings',{});
168
  };
169
 
170
- TablesModel.prototype.setSettings = function (id, settings) {
171
  if (isNaN(id = parseInt(id))) {
172
  throw new Error('Invalid table id.');
173
  }
 
 
 
 
174
 
175
- return this.request('saveSettings', { id: id, settings: settings.serialize() });
176
  };
177
 
178
  TablesModel.prototype.setHistorySettings = function (id, settings) {
@@ -421,21 +426,25 @@ var g_stbPreviewTimeoutSet = false;
421
  }
422
  };
423
 
424
- TablesModel.prototype.saveTable = function(preview) {
425
- this._saveTable(preview);
426
  };
427
 
428
- TablesModel.prototype._saveTable = function(preview) {
 
 
429
  preview = typeof(preview) != 'undefined' ? preview : false;
 
430
  var self = this,
431
  editor = self.getEditor(),
432
  id = app.getParameterByName('id'),
433
  toolbar = app.Editor.Tb,
434
  svlFormatsClass = toolbar.getSvlFormatClass(),
435
  formatClasses = toolbar.getFormatClasses(),
436
- pagination = g_stbPagination;
 
437
 
438
- if (pagination) {
439
  editor.copyInBuffer();
440
  var bufferData = editor.bufferData,
441
  bufferMeta = editor.bufferMeta,
@@ -444,15 +453,37 @@ var g_stbPreviewTimeoutSet = false;
444
  countCols = editor.bufferCols;
445
  }
446
 
447
- if (preview !== false) {
448
- $(preview).html($('<i/>', { class: 'fa fa-spinner fa-spin' }).attr('style','font-size: 2em !important')).prepend('<label> Table generate in process.... </label>');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
449
  }
450
 
451
- if(!g_stbDoSaving) {
452
  g_stbDoSaving = true;
453
  app.createSpinner($('#buttonSave'));
454
 
455
- var formData = $('form#settings'),
 
456
  byPart = true,
457
  metaData = [],
458
  mergeData = [],
@@ -461,212 +492,239 @@ var g_stbPreviewTimeoutSet = false;
461
  rowCounter = 0,
462
  requiredAssets = {};
463
 
464
- // Put textareas data into the hidden fields before the saving of table settings
465
- formData.find('input[name="elements[descriptionText]"]').val( formData.find('#descriptionText').val() );
466
- formData.find('input[name="elements[signatureText]"]').val( formData.find('#signatureText').val() );
467
- formData.find('input[name="features[after_table_loaded_script]"]').val(this._b64EncodeUnicode(formData.find('#after-table-loaded-script-text').val()));
468
- formData.find('input[name="source[dbSQL]"]').val( formData.find('#source-db-sql').val() );
469
 
470
- if(preview) {
471
- var tableInstance = app.getTableInstanceById(id);
 
472
 
473
- if(tableInstance) {
474
- tableInstance.api().destroy();
475
- }
476
- }
477
 
478
- $.each((pagination ? bufferData : editor.getData()), function (x, row) {
479
- var currentRow = { cells: [] };
480
- rowCounter++;
481
-
482
- $.each(row, function (y, cell) {
483
- var meta = (pagination ? bufferMeta[x * countCols + y] : editor.getCellMeta(x, y)),
484
- metaClasses = meta.className;
485
-
486
- if (typeof(metaClasses) != 'undefined' && metaClasses.indexOf(svlFormatsClass) !== -1) {
487
- metaClasses = metaClasses.replace(svlFormatsClass, '').trim();
488
- var dataFormats = ('data-formats' in meta ? meta['data-formats'] : '');
489
- if (dataFormats.length > 0) {
490
- for (var c in formatClasses) {
491
- if (dataFormats.indexOf(c) !== -1) {
492
- metaClasses += ' ' + c;
493
  }
494
  }
495
  }
496
- }
497
- var cellHtml = (pagination ? bufferData[x][y] : $(editor.getCell(x, y))),
498
- classes = [],
499
- cellData = {
500
- y: rowCounter,
501
- data: cell,
502
- calculatedValue: null,
503
- hidden: false,
504
- hiddenCell: metaClasses && metaClasses.match('hiddenCell') !== null,
505
- invisibleCell: metaClasses && metaClasses.match('invisibleCell') !== null
506
- },
507
- mergeCell = (pagination ? editor.mergeGetInfo(x, y) : editor.mergeCells.mergedCellInfoCollection.getInfo(x, y));
508
-
509
- // set merged params
510
- if(mergeCell !== undefined) {
511
- cellData.hidden = true;
512
- }
513
- if(!pagination)
514
- {
515
- // set formatted value
516
- cellHtml = cellHtml.clone();
517
- cellHtml.find('.htAutocompleteArrow').remove();
518
- cellData.formattedValue = cellHtml.text();
519
- }
520
-
521
- if(meta.readOnly) {
522
- cellData.readOnly = true;
523
- }
524
- // selectable cell data source
525
- if(meta.source && meta.source.length) {
526
- meta.type = 'dropdown';
527
- cellData.source = meta.source;
528
- }
529
-
530
- // Set cell format
531
- cellData.type = meta.type ? meta.type : 'text';
532
- cellData.baseType = meta.baseType ? meta.baseType : 'text';
533
- cellData.formatType = meta.formatType ? meta.formatType : '';
534
-
535
- switch(cellData.formatType) {
536
- case 'currency':
537
- cellData.format = formData.find('[name="currencyFormat"]').val();
538
- break;
539
- case 'percent':
540
- cellData.format = formData.find('[name="percentFormat"]').val();
541
- break;
542
- case 'date':
543
- //one table can contain multiple date formats
544
- cellData.format = meta.format != 'undefined'
545
- ? meta.format
546
- : formData.find('[name="dateFormat"]').val();
547
 
548
- var date = moment(cellData.data, cellData.format);
 
 
 
 
 
 
 
549
 
550
- if (date.isValid()) {
551
- cellData.dateOrder = date.format('x');
552
- }
553
- break;
554
- default:
555
- cellData.format = meta.format;
556
- break;
557
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
558
 
559
- // Set calculated value for cells with formulas
560
- if (self.isFormula(cell)) {
561
- var value = self.getFormulaResult(cell, x, y);
562
 
563
- if (value !== undefined) {
564
- if (!isNaN(value) && value !== '0' && value !== 0 && value % 1 !== 0) { // round float
565
- var floatValue = parseFloat(value);
566
 
567
- if (floatValue.toString().indexOf('.') !== -1) {
568
- var afterPointSybolsLength = floatValue.toString().split('.')[1].length;
569
 
570
- if (afterPointSybolsLength > 4) {
571
- value = floatValue.toFixed(4);
 
572
  }
573
  }
 
 
 
 
574
  }
575
- cellData.calculatedValue = value;
576
  }
577
- }
578
 
579
- // Set classes for cell
580
- if (metaClasses !== undefined) {
581
- $.each(metaClasses.split(' '), function (index, element) {
582
- if (element.length) {
583
- if(toeInArray(element, ['datefield', 'tooltipCell', 'collapsibleCell']) != -1 && !requiredAssets[element]) {
584
- requiredAssets[element] = true;
 
 
585
  }
586
- classes.push($.trim(element));
587
- }
588
- });
589
- }
590
- cellData.meta = classes;
591
-
592
- // Set comments for cell
593
- if (typeof(meta.comment) != 'undefined') {
594
- cellData.comment = meta.comment;
595
- }
596
 
597
- // Set column width by cells of first table row
598
- if (x == 0) {
599
- columnsWidth.push(editor.getColWidth(y));
600
- }
601
- var diagramsExists = cell && cell.toString().match(/(\[\s*supsystic-table-diagram[^\]]*\])+?/gi);
602
-
603
- if(diagramsExists) {
604
- for(var i = 0; i < diagramsExists.length; i++) {
605
- var diagramId = /id=[\'|\"](\d+)[\'|\"]/gi.exec(diagramsExists[i]);
606
 
607
- if(diagramId && diagramId[1]) {
608
- requiredAssets.diagrams = requiredAssets.diagrams ? requiredAssets.diagrams : [];
609
- requiredAssets.diagrams.push(diagramId[1]);
 
 
 
 
 
 
 
 
 
 
 
610
  }
611
  }
612
- }
613
- currentRow.cells.push(cellData);
614
- });
615
 
616
- // Row height
617
- currentRow.height = (pagination ? bufferHeights[x] : editor.getRowHeight(x));
618
 
619
- rowsData.push(currentRow);
620
- });
621
- if(pagination) {
622
- mergeData = bufferMerge;
623
- } else {
624
- if(editor.mergeCells.mergedCellInfoCollection.length) {
625
- for(var i = 0; i < editor.mergeCells.mergedCellInfoCollection.length; i++) {
626
- mergeData.push(editor.mergeCells.mergedCellInfoCollection[i]);
 
627
  }
628
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
629
  }
630
- metaData = {
631
- requiredAssets: requiredAssets,
632
- mergedCells: mergeData,
633
- columnsWidth: columnsWidth,
634
- columnsFixedWidth: g_stbFixedColumnsWidth,
635
- columnsSortOrder: g_stbMultipleColumnsSorting,
636
- columnsDisableSorting: g_stbDisableColumnsSorting,
637
- css: this.getCssEditor().getValue()
638
- };
639
 
640
  // Request to save settings, meta and rows
641
  var ajaxPromise = new $.Deferred().resolve();
642
 
643
- ajaxPromise = ajaxPromise.then(
644
- function() {
645
- return self.setSettings(id, formData);
646
- }
647
- );
648
- ajaxPromise = ajaxPromise.then(
649
- function() {
650
- return self.setHistorySettings(id, $('form#history-settings'));
651
  }
652
- );
653
- ajaxPromise = ajaxPromise.then(
654
- function() {
655
- return self.setMeta(id, metaData);
 
 
 
 
 
 
 
656
  }
657
- );
658
- ajaxPromise = ajaxPromise.then(
659
- function() {
660
- return self.setRows(id, rowsData, byPart, preview);
 
 
 
 
 
 
 
 
661
  }
662
- );
663
- ajaxPromise = ajaxPromise.then(
664
- function() {
665
- if(SDT_DATA.isWooPro) {
666
- return self.setWooSettings(id, $('form#woocommerce-settings'));
 
 
667
  }
 
 
 
 
 
 
668
  }
669
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
670
  } else {
671
  if(preview && !g_stbPreviewTimeoutSet) {
672
  this.getPreview(id, preview);
@@ -684,26 +742,204 @@ var g_stbPreviewTimeoutSet = false;
684
  }, 50);
685
  } else {
686
  g_stbPreviewTimeoutSet = false;
687
- g_stbDoPreview = true;
688
- var container = preview instanceof $ ? preview : $(preview),
689
- table;
690
-
691
- if(container.length) {
692
-
693
- return this.render(app.getParameterByName('id')).done(function(response) {
694
- container.empty().append($(response.table));
695
- table = container.find('table');
696
- app.initializeTable(table, app.showTable, function(table) {
 
 
 
 
 
 
 
 
 
 
 
 
697
  self._afterTablePreview(table);
698
- g_stbDoPreview = false;
699
  if(app.initExportTable) {
700
  app.initExportTable();
701
  }
 
 
 
 
 
 
 
 
702
  });
703
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
704
  }
705
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
706
  };
 
 
 
 
 
 
 
 
 
 
 
 
707
 
708
  TablesModel.prototype.getPreviewHistoryTable = function (userId, preview, period) {
709
  var self = this,
@@ -723,12 +959,11 @@ var g_stbPreviewTimeoutSet = false;
723
  }
724
  };
725
 
726
- TablesModel.prototype.render = function (id) {
727
  if (isNaN(id = parseInt(id))) {
728
  throw new Error('Invalid table id.');
729
  }
730
-
731
- return this.request('render', { id: id });
732
  };
733
 
734
  TablesModel.prototype.renderFromHistory = function (userId, tableId, period) {
@@ -926,9 +1161,8 @@ var g_stbPreviewTimeoutSet = false;
926
  );
927
  break;
928
  case 'currency':
929
- var currencySymbolMatch = format.match(/^[^\d]?|[^\d]?$/),
930
- currencySymbol = currencySymbolMatch[0] || '$',
931
- formatWithoutCurrency = format.replace(currencySymbol, '');
932
 
933
  delimiters = (formatWithoutCurrency.match(/[^\d]/g) || [',', '.']).reverse();
934
  languageData.delimiters = {
1
  var g_stbDoSaving = true; //waiting for the end of downloads
2
  var g_stbDoPreview = false;
3
+ var g_stbNeedPreview = false;
4
+ var g_stbMobilePreview = false;
5
  var g_stbPreviewTimeoutSet = false;
6
+ //var g_stbPreviewTable = null;
7
  (function ($, app) {
8
 
9
  var TablesModel = (function () {
95
  return deferred.promise();
96
  };
97
 
98
+ TablesModel.prototype.setRows = function (id, rows, byPart) {
99
  if (isNaN(id = parseInt(id))) {
100
  throw new Error('Invalid table id.');
101
  }
102
  byPart = typeof(byPart) != 'undefined' ? byPart : false;
 
103
 
104
  if(byPart) {
105
  var self = this,
129
  });
130
  });
131
  ajaxPromise = ajaxPromise.then(function() {
132
+ self.endSave();
 
133
  });
 
 
 
 
 
134
  } else {
135
  return this.request('updateRows', { id: id, rows: this._prepareData(rows) });
136
  }
137
  };
138
 
139
+ TablesModel.prototype.endSave = function () {
140
+ app.deleteSpinner($('#buttonSave'));
141
+ g_stbDoSaving = false;
142
+ };
143
+
144
  TablesModel.prototype.getMeta = function (id) {
145
  if (isNaN(id = parseInt(id))) {
146
  throw new Error('Invalid table id.');
168
  return this.settingsRequest('getSettings',{});
169
  };
170
 
171
+ TablesModel.prototype.setSettings = function (id, settings, source) {
172
  if (isNaN(id = parseInt(id))) {
173
  throw new Error('Invalid table id.');
174
  }
175
+ var data = settings.serialize();
176
+ if(typeof(source) != 'undefined' && source.length) {
177
+ data += '&' + source.serialize();
178
+ }
179
 
180
+ return this.request('saveSettings', { id: id, settings: data });
181
  };
182
 
183
  TablesModel.prototype.setHistorySettings = function (id, settings) {
426
  }
427
  };
428
 
429
+ TablesModel.prototype.saveTable = function(preview, rerender) {
430
+ this._saveTable(preview, rerender);
431
  };
432
 
433
+ TablesModel.prototype._saveTable = function(preview, rerender) {
434
+ // rerender = 1 (needed render preview)
435
+ // rerender = 2 (needed settings save and render preview)
436
  preview = typeof(preview) != 'undefined' ? preview : false;
437
+ rerender = typeof(rerender) != 'undefined' ? rerender : false;
438
  var self = this,
439
  editor = self.getEditor(),
440
  id = app.getParameterByName('id'),
441
  toolbar = app.Editor.Tb,
442
  svlFormatsClass = toolbar.getSvlFormatClass(),
443
  formatClasses = toolbar.getFormatClasses(),
444
+ pagination = g_stbPagination,
445
+ lastSave = false;
446
 
447
+ if(pagination) {
448
  editor.copyInBuffer();
449
  var bufferData = editor.bufferData,
450
  bufferMeta = editor.bufferMeta,
453
  countCols = editor.bufferCols;
454
  }
455
 
456
+ if(preview !== false) {
457
+ if(g_stbDoPreview && rerender) {
458
+ g_stbNeedPreview = true;
459
+ return;
460
+ }
461
+ for(var key in g_stbIsDataEdited) {
462
+ if(g_stbIsDataEdited[key] && (rerender == 2 || key != 'settings')) {
463
+ lastSave = key;
464
+ }
465
+ }
466
+
467
+ var $preview = $(preview),
468
+ $table = $preview.find('.supsystic-tables-wrap');
469
+ if($table.length) {
470
+ if(lastSave == false && !rerender && !g_stbNeedPreview) return;
471
+ //g_stbPreviewTable = '';
472
+ $table.find('.dataTables_processing').css('display', 'block');
473
+ }
474
+ else {
475
+ $(preview).html($('<i/>', { class: 'fa fa-spinner fa-spin' }).attr('style','font-size: 2em !important')).prepend('<label> Table generate in process.... </label>');
476
+ }
477
+ } else {
478
+ g_stbNeedPreview = true;
479
  }
480
 
481
+ if(!g_stbDoSaving && (!preview || lastSave !== false)) {
482
  g_stbDoSaving = true;
483
  app.createSpinner($('#buttonSave'));
484
 
485
+ var formData = this.prepareSettingsForm($('form#settings'), id),
486
+ sourceData = $('form#source-settings'),
487
  byPart = true,
488
  metaData = [],
489
  mergeData = [],
492
  rowCounter = 0,
493
  requiredAssets = {};
494
 
495
+ if(!preview || g_stbIsDataEdited['data']) {
 
 
 
 
496
 
497
+ $.each((pagination ? bufferData : editor.getData()), function (x, row) {
498
+ var currentRow = { cells: [] };
499
+ rowCounter++;
500
 
501
+ $.each(row, function (y, cell) {
502
+ var meta = (pagination ? bufferMeta[x * countCols + y] : editor.getCellMeta(x, y)),
503
+ metaClasses = meta.className;
 
504
 
505
+ if (typeof(metaClasses) != 'undefined' && metaClasses.indexOf(svlFormatsClass) !== -1) {
506
+ metaClasses = metaClasses.replace(svlFormatsClass, '').trim();
507
+ var dataFormats = ('data-formats' in meta ? meta['data-formats'] : '');
508
+ if (dataFormats.length > 0) {
509
+ for (var c in formatClasses) {
510
+ if (dataFormats.indexOf(c) !== -1) {
511
+ metaClasses += ' ' + c;
512
+ }
 
 
 
 
 
 
 
513
  }
514
  }
515
  }
516
+ var cellHtml = (pagination ? bufferData[x][y] : $(editor.getCell(x, y))),
517
+ classes = [],
518
+ cellData = {
519
+ y: rowCounter,
520
+ data: cell,
521
+ calculatedValue: null,
522
+ hidden: false,
523
+ hiddenCell: metaClasses && metaClasses.match('hiddenCell') !== null,
524
+ invisibleCell: metaClasses && metaClasses.match('invisibleCell') !== null
525
+ },
526
+ mergeCell = (pagination ? editor.mergeGetInfo(x, y) : editor.mergeCells.mergedCellInfoCollection.getInfo(x, y));
527
+
528
+ // set merged params
529
+ if(mergeCell !== undefined) {
530
+ cellData.hidden = true;
531
+ }
532
+ if(!pagination)
533
+ {
534
+ // set formatted value
535
+ cellHtml = cellHtml.clone();
536
+ cellHtml.find('.htAutocompleteArrow').remove();
537
+ cellData.formattedValue = cellHtml.text().replace(/\\/g, '&#92;');
538
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
539
 
540
+ if(meta.readOnly) {
541
+ cellData.readOnly = true;
542
+ }
543
+ // selectable cell data source
544
+ if(meta.source && meta.source.length) {
545
+ meta.type = 'dropdown';
546
+ cellData.source = meta.source;
547
+ }
548
 
549
+ // Set cell format
550
+ cellData.type = meta.type ? meta.type : 'text';
551
+ cellData.baseType = meta.baseType ? meta.baseType : 'text';
552
+ cellData.formatType = meta.formatType ? meta.formatType : '';
553
+
554
+ switch(cellData.formatType) {
555
+ case 'currency':
556
+ cellData.format = formData.find('[name="currencyFormat"]').val();
557
+ break;
558
+ case 'percent':
559
+ cellData.format = formData.find('[name="percentFormat"]').val();
560
+ break;
561
+ case 'date':
562
+ //one table can contain multiple date formats
563
+ cellData.format = meta.format != 'undefined'
564
+ ? meta.format
565
+ : formData.find('[name="dateFormat"]').val();
566
+
567
+ var date = moment(cellData.data, cellData.format);
568
+
569
+ if (date.isValid()) {
570
+ cellData.dateOrder = date.format('x');
571
+ }
572
+ break;
573
+ default:
574
+ cellData.format = meta.format;
575
+ break;
576
+ }
577
 
578
+ // Set calculated value for cells with formulas
579
+ if (self.isFormula(cell)) {
580
+ var value = self.getFormulaResult(cell, x, y);
581
 
582
+ if (value !== undefined) {
583
+ if (!isNaN(value) && value !== '0' && value !== 0 && value % 1 !== 0) { // round float
584
+ var floatValue = parseFloat(value);
585
 
586
+ if (floatValue.toString().indexOf('.') !== -1) {
587
+ var afterPointSybolsLength = floatValue.toString().split('.')[1].length;
588
 
589
+ if (afterPointSybolsLength > 4) {
590
+ value = floatValue.toFixed(4);
591
+ }
592
  }
593
  }
594
+ cellData.calculatedValue = value;
595
+ if(typeof cell == 'string' && cell.toLowerCase().indexOf('=hyperlink') === 0) {
596
+ cellData.calculatedValue = app._hyperlinkUrl ? app._hyperlinkUrl : value;
597
+ }
598
  }
 
599
  }
 
600
 
601
+ // Set classes for cell
602
+ if (metaClasses !== undefined) {
603
+ $.each(metaClasses.split(' '), function (index, element) {
604
+ if (element.length) {
605
+ if(toeInArray(element, ['datefield', 'tooltipCell', 'collapsibleCell']) != -1 && !requiredAssets[element]) {
606
+ requiredAssets[element] = true;
607
+ }
608
+ classes.push($.trim(element));
609
  }
610
+ });
611
+ }
612
+ cellData.meta = classes;
 
 
 
 
 
 
 
613
 
614
+ // Set comments for cell
615
+ if (typeof(meta.comment) != 'undefined') {
616
+ cellData.comment = meta.comment;
617
+ }
 
 
 
 
 
618
 
619
+ // Set column width by cells of first table row
620
+ if (x == 0) {
621
+ columnsWidth.push(editor.getColWidth(y));
622
+ }
623
+ var diagramsExists = cell && cell.toString().match(/(\[\s*supsystic-table-diagram[^\]]*\])+?/gi);
624
+
625
+ if(diagramsExists) {
626
+ for(var i = 0; i < diagramsExists.length; i++) {
627
+ var diagramId = /id=[\'|\"](\d+)[\'|\"]/gi.exec(diagramsExists[i]);
628
+
629
+ if(diagramId && diagramId[1]) {
630
+ requiredAssets.diagrams = requiredAssets.diagrams ? requiredAssets.diagrams : [];
631
+ requiredAssets.diagrams.push(diagramId[1]);
632
+ }
633
  }
634
  }
635
+ currentRow.cells.push(cellData);
636
+ });
 
637
 
638
+ // Row height
639
+ currentRow.height = (pagination ? bufferHeights[x] : editor.getRowHeight(x));
640
 
641
+ rowsData.push(currentRow);
642
+ });
643
+ if(pagination) {
644
+ mergeData = bufferMerge;
645
+ } else {
646
+ if(editor.mergeCells.mergedCellInfoCollection.length) {
647
+ for(var i = 0; i < editor.mergeCells.mergedCellInfoCollection.length; i++) {
648
+ mergeData.push(editor.mergeCells.mergedCellInfoCollection[i]);
649
+ }
650
  }
651
  }
652
+ metaData = {
653
+ requiredAssets: requiredAssets,
654
+ mergedCells: mergeData,
655
+ columnsWidth: columnsWidth,
656
+ columnsFixedWidth: g_stbFixedColumnsWidth,
657
+ columnsSortOrder: g_stbMultipleColumnsSorting,
658
+ columnsDisableSorting: g_stbDisableColumnsSorting,
659
+ css: this.getCssEditor().getValue()
660
+ };
661
+ }
662
+
663
+ if(preview) {
664
+ self.getPreview(id, preview);
665
  }
 
 
 
 
 
 
 
 
 
666
 
667
  // Request to save settings, meta and rows
668
  var ajaxPromise = new $.Deferred().resolve();
669
 
670
+ if(!preview || g_stbIsDataEdited['settings'] || g_stbIsDataEdited['source']) {
671
+ if(sourceData.length) {
672
+ sourceData.find('input[name="source[dbSQL]"]').val(sourceData.find('#source-db-sql').val());
 
 
 
 
 
673
  }
674
+ ajaxPromise = ajaxPromise.then(
675
+ function() {
676
+ return self.setSettings(id, formData, sourceData);
677
+ }
678
+ );
679
+ g_stbIsDataEdited['settings'] = false;
680
+ g_stbIsDataEdited['source'] = false;
681
+ if(lastSave == 'settings' || lastSave == 'source') {
682
+ ajaxPromise = ajaxPromise.then(function() {
683
+ self.endSave();
684
+ });
685
  }
686
+ }
687
+ if(!preview || g_stbIsDataEdited['history']) {
688
+ ajaxPromise = ajaxPromise.then(
689
+ function() {
690
+ return self.setHistorySettings(id, $('form#history-settings'));
691
+ }
692
+ );
693
+ g_stbIsDataEdited['history'] = false;
694
+ if(lastSave == 'history') {
695
+ ajaxPromise = ajaxPromise.then(function() {
696
+ self.endSave();
697
+ });
698
  }
699
+ }
700
+ if(!preview || g_stbIsDataEdited['woocommerce']) {
701
+ ajaxPromise = ajaxPromise.then(
702
+ function() {
703
+ if(SDT_DATA.isWooPro) {
704
+ return self.setWooSettings(id, $('form#woocommerce-settings'));
705
+ }
706
  }
707
+ );
708
+ g_stbIsDataEdited['woocommerce'] = false;
709
+ if(lastSave == 'woocommerce') {
710
+ ajaxPromise = ajaxPromise.then(function() {
711
+ self.endSave();
712
+ });
713
  }
714
+ }
715
+ if(!preview || g_stbIsDataEdited['data']) {
716
+ ajaxPromise = ajaxPromise.then(
717
+ function() {
718
+ return self.setMeta(id, metaData);
719
+ }
720
+ );
721
+ ajaxPromise = ajaxPromise.then(
722
+ function() {
723
+ return self.setRows(id, rowsData, byPart, preview);
724
+ }
725
+ );
726
+ g_stbIsDataEdited['data'] = false;
727
+ }
728
  } else {
729
  if(preview && !g_stbPreviewTimeoutSet) {
730
  this.getPreview(id, preview);
742
  }, 50);
743
  } else {
744
  g_stbPreviewTimeoutSet = false;
745
+ if(!g_stbDoPreview) {
746
+ g_stbDoPreview = true;
747
+ g_stbNeedPreview = false;
748
+ var container = preview instanceof $ ? preview : $(preview),
749
+ table;
750
+
751
+ if(container.length) {
752
+ var settings = (g_stbIsDataEdited['settings'] ? this.prepareSettingsForm($('form#settings'), id).serialize() : '');
753
+
754
+ return this.render(app.getParameterByName('id'), settings).done(function(response) {
755
+ var tableInstance = app.getTableInstanceById(id);
756
+ if(tableInstance) {
757
+ tableInstance.api().destroy();
758
+ app.removeTableInstanceByViewId(tableInstance.data('view-id'));
759
+ }
760
+ //g_stbPreviewTable = response.table;
761
+ container.empty().append($(response.table));
762
+ table = container.find('table');
763
+ if(g_stbMobilePreview) {
764
+ app.setTableMobileWidth();
765
+ }
766
+ app.initTablesOnPage();
767
  self._afterTablePreview(table);
 
768
  if(app.initExportTable) {
769
  app.initExportTable();
770
  }
771
+ }).always(function() {
772
+ setTimeout(function(){
773
+ g_stbDoPreview = false;
774
+ if(g_stbNeedPreview) {
775
+ self.getPreview(id, preview);
776
+ }
777
+ }, 2000);
778
+
779
  });
780
+ }
781
+ }
782
+ }
783
+ };
784
+
785
+ TablesModel.prototype.reinitPreview = function (preview) {
786
+ var self = this,
787
+ tableId = app.getParameterByName('id'),
788
+ tableInstance = app.getTableInstanceById(tableId);
789
+ if(tableInstance) {
790
+ tableInstance.api().destroy();
791
+ app.removeTableInstanceByViewId(tableInstance.data('view-id'));
792
+ }
793
+ //previewContainer.empty().append($(g_stbPreviewTable));
794
+ table = preview.find('table');
795
+ if(table.length == 0) return;
796
+
797
+ app.setTableMobileWidth(g_stbMobilePreview);
798
+
799
+ app.initializeTable(table, app.showTable, function(table) {
800
+ self._afterTablePreview(table);
801
+ if(typeof tableInstance.fnAdjustColumnSizing == 'function' ) {
802
+ setTimeout(function(){
803
+ tableInstance.fnAdjustColumnSizing(false);
804
+ }, 350);
805
+ }
806
+ if(app.initExportTable) {
807
+ app.initExportTable();
808
+ }
809
+ });
810
+ }
811
+
812
+ TablesModel.prototype.getCssText = function(rule) {
813
+ var value = rule.cssText ? rule.cssText : rule.style.cssText;
814
+ if(typeof(value) == 'undefined' || value.length == 0 || value.indexOf('@import') >= 0) return '';
815
+ if(value.indexOf(rule.selectorText) == -1) {
816
+ value = rule.selectorText + '{' + value + '}';
817
+ }
818
+ return value;
819
+ }
820
+
821
+ TablesModel.prototype.prepareSettingsForm = function(formData, id) {
822
+ // Put textareas data into the hidden fields before the saving of table settings
823
+ formData.find('input[name="elements[descriptionText]"]').val( formData.find('#descriptionText').val() );
824
+ formData.find('input[name="elements[signatureText]"]').val( formData.find('#signatureText').val() );
825
+ formData.find('input[name="features[after_table_loaded_script]"]').val(this._b64EncodeUnicode(formData.find('#after-table-loaded-script-text').val()));
826
+
827
+ var customCss = '',
828
+ obj = document.getElementById('stb-preview-css'),
829
+ sheet = obj.sheet || obj.styleSheet;
830
+ if(!sheet.disabled) {
831
+ var rules = sheet.cssRules || sheet.rules;
832
+ if(rules) {
833
+ for(var r = 0; r < rules.length; r++) {
834
+ customCss += this.getCssText(rules[r]);
835
+ }
836
  }
837
  }
838
+ customCss = customCss.replace(new RegExp('supsystic-table-'+id, 'g'), 'supsystic-table-{id}');
839
+ formData.find('input[name="styles[customCss]"]').val(customCss);
840
+ return formData;
841
+ }
842
+
843
+ TablesModel.prototype.disablePreviewCss = function (mode) {
844
+ var obj = document.getElementById('stb-preview-css'),
845
+ sheet = obj.sheet || obj.styleSheet;
846
+ sheet.disabled = mode;
847
+ }
848
+
849
+ TablesModel.prototype.getFontFamily = function(family) {
850
+ if(g_stbStandartFontsList
851
+ && toeInArray(family, g_stbStandartFontsList) == -1
852
+ && g_stbAllFontsList
853
+ && toeInArray(family, g_stbAllFontsList) != -1
854
+ ) {
855
+ return '@import url("//fonts.googleapis.com/css?family=' + family.replace(/_/g, '+') + '"); ';
856
+ }
857
+ return '';
858
+ }
859
+
860
+ TablesModel.prototype.updatePreviewCss = function (selectors) {
861
+ var obj = document.getElementById('stb-preview-css'),
862
+ sheet = obj.sheet || obj.styleSheet,
863
+ rules = sheet.cssRules || sheet.rules;
864
+
865
+ for(var i = 0; i < selectors.length; i++) {
866
+ var selector = selectors[i].selector,
867
+ param = selectors[i].param,
868
+ value = selectors[i].value,
869
+ newRules = typeof(value) == 'string' && value.length ? param + ':' + (param == 'font-family' ? '"' + value + '"' : value) + ';' : '',
870
+ found = -1;
871
+
872
+ for(var r = 0; r < rules.length; r++) {
873
+ if(rules[r].selectorText == selector) {
874
+ found = r;
875
+ var curCss = this.getCssText(rules[r]),
876
+ curRules = curCss.substring(curCss.indexOf('{') + 1, curCss.lastIndexOf('}')).split(';');
877
+
878
+ for(var c = 0; c < curRules.length; c++) {
879
+ var rulePaar = curRules[c].split(':');
880
+ if(rulePaar.length == 2) {
881
+ if(rulePaar[0].trim() != param) {
882
+ newRules += curRules[c] + ';';
883
+ }
884
+ }
885
+ }
886
+ break;
887
+ }
888
+ }
889
+ if(found >= 0) {
890
+ sheet.deleteRule(found);
891
+ }
892
+ if(newRules.length) {
893
+ sheet.insertRule(selector + '{' + newRules + '}', rules.length);
894
+ if(param == 'font-family') {
895
+ if(g_stbStandartFontsList
896
+ && toeInArray(value, g_stbStandartFontsList) == -1
897
+ && g_stbAllFontsList
898
+ && toeInArray(value, g_stbAllFontsList) != -1
899
+ ) {
900
+ sheet.insertRule('@import url("//fonts.googleapis.com/css?family=' + value.replace(/ /g, '+') + '"); ', 0);
901
+ }
902
+ }
903
+ }
904
+ }
905
+ }
906
+
907
+ TablesModel.prototype.getLightenDarkenColor = function(col, amt) {
908
+ var usePound = false;
909
+ if(col[0] == "#") {
910
+ col = col.slice(1);
911
+ usePound = true;
912
+ }
913
+ var num = parseInt(col, 16),
914
+ r = (num >> 16) + amt,
915
+ b = ((num >> 8) & 0x00FF) + amt,
916
+ g = (num & 0x0000FF) + amt;
917
+ if(r > 255) r = 255;
918
+ else if(r < 0) r = 0;
919
+ if(b > 255) b = 255;
920
+ else if(b < 0) b = 0;
921
+ if(g > 255) g = 255;
922
+ else if(g < 0) g = 0;
923
+ //return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16);
924
+ var res = (g | (b << 8) | (r << 16)).toString(16);
925
+ return (usePound?"#":"") + '0'.repeat(6 - res.length) + res;
926
+ }
927
+
928
+ TablesModel.prototype.controlSettingsValues = function($element) {
929
+ this._controlSettingsValues($element);
930
  };
931
+ TablesModel.prototype._controlSettingsValues = function($element) {
932
+ var formData = $('form#settings');
933
+ if($element.is('#table-elements-description')) {
934
+ if(formData.find('#descriptionText').val().length) {
935
+ $element.removeAttr('data-preview-not-redraw');
936
+ }
937
+ } else if($element.is('#table-elements-signature')) {
938
+ if(formData.find('#signatureText').val().length) {
939
+ $element.removeAttr('data-preview-not-redraw');
940
+ }
941
+ }
942
+ }
943
 
944
  TablesModel.prototype.getPreviewHistoryTable = function (userId, preview, period) {
945
  var self = this,
959
  }
960
  };
961
 
962
+ TablesModel.prototype.render = function (id, settings) {
963
  if (isNaN(id = parseInt(id))) {
964
  throw new Error('Invalid table id.');
965
  }
966
+ return this.request('render', { id: id, settings: typeof(settings) == 'undefined' ? false : settings, preview: '1' });
 
967
  };
968
 
969
  TablesModel.prototype.renderFromHistory = function (userId, tableId, period) {
1161
  );
1162
  break;
1163
  case 'currency':
1164
+ var formatWithoutCurrency = format.match(/\d.?\d*.?\d*/)[0],
1165
+ currencySymbol = format.replace(formatWithoutCurrency,'') || '$';
 
1166
 
1167
  delimiters = (formatWithoutCurrency.match(/[^\d]/g) || [',', '.']).reverse();
1168
  languageData.delimiters = {
src/SupsysticTables/Tables/assets/js/tables.view.js CHANGED
@@ -22,7 +22,8 @@ var g_stbCopyPasteColsCount = [];
22
  $(document).ready(function () {
23
  var tablesModel = app.Models.Tables,
24
  editor = app.Editor.Hot,
25
- cssEditor = tablesModel.getCssEditor();
 
26
 
27
  // Initialize Main Tabs
28
  var $mainTabsContent = $('.row-tab'),
@@ -45,7 +46,7 @@ var g_stbCopyPasteColsCount = [];
45
  case '#row-tab-editor':
46
  editor.render();
47
  break;
48
- case '#row-tab-preview':
49
  tablesModel.saveTable('#table-preview');
50
  break;
51
  case '#row-tab-css':
@@ -58,6 +59,7 @@ var g_stbCopyPasteColsCount = [];
58
 
59
  // Initialize Sub Tabs
60
  var linksOyPositions = [],
 
61
  offsetTop2 = Math.floor($("#stb-anl-main").offset().top);
62
  linksOyPositions.push({
63
  'id': '#stb-anl-main',
@@ -72,20 +74,15 @@ var g_stbCopyPasteColsCount = [];
72
  'offset': Math.abs(Math.floor($("#stb-anl-appearance").offset().top) - offsetTop2 - 40),
73
  });
74
  linksOyPositions.push({
75
- 'id': '#stb-anl-language',
76
- 'offset': Math.abs(Math.floor($("#stb-anl-language").offset().top) - offsetTop2 - 40),
77
  });
78
- linksOyPositions.push({
79
- 'id': '#stb-anl-source',
80
- 'offset': Math.abs(Math.floor($("#stb-anl-source").offset().top) - offsetTop2 - 40),
81
- });
82
-
83
 
84
  $('.settings-wrap').slimScroll({'height': g_stbWindowHeight+'px'}).off('slimscrolling')
85
  .on('slimscrolling', null, { 'oy': linksOyPositions }, function(e, pos){
86
  if(e && e.data && e.data.oy) {
87
  var ind1 = 0,
88
- $activeItem = $('.stb-anchor-nav-links.active'),
89
  isFind = false;
90
  while(ind1 < (e.data.oy.length - 1) && !isFind) {
91
  if(e.data.oy[ind1].offset <= pos && e.data.oy[ind1+1].offset > pos) {
@@ -95,7 +92,7 @@ var g_stbCopyPasteColsCount = [];
95
  ind1++;
96
  }
97
  // if current position at last anchor
98
- if(isFind == false && ind1 == 4) {
99
  isFind = ind1;
100
  }
101
  //check curr active item
@@ -106,12 +103,12 @@ var g_stbCopyPasteColsCount = [];
106
  $activeItem.removeClass('active');
107
  }
108
  // add active class
109
- $('.stb-anchor-nav-links[href="' + e.data.oy[isFind].id + '"]').addClass('active');
110
  }
111
  }
112
  });
113
- $('.stb-anchor-nav-links').on('click', function(e1, funcParams) {
114
- e1.preventDefault();
115
  var $settingsWrap = $('.settings-wrap')
116
  , urlLink = $(this).attr('href')
117
  , $linkItem = $(urlLink)
@@ -129,11 +126,35 @@ var g_stbCopyPasteColsCount = [];
129
  }
130
  }
131
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
 
133
  // init anchor link
134
  setTimeout(function() {
135
  var slScrollTopPos = parseInt($('#slimScrollStartPos').val());
136
- $('.stb-anchor-nav-links[href="#stb-anl-main"]').trigger('click', {'offsetScTop':slScrollTopPos});
137
  }, 200);
138
 
139
  // Fix of conflict with handsontable library - it triggers error if user makes click on link without href attribute
@@ -147,16 +168,19 @@ var g_stbCopyPasteColsCount = [];
147
  // Configure CSS Editor
148
  cssEditor.setTheme("ace/theme/monokai");
149
  cssEditor.getSession().setMode("ace/mode/css");
 
 
 
150
 
151
  // Make editors responsive for window height
152
- $('#tableEditor, #css-editor').css({
153
  'max-height': g_stbWindowHeight,
154
  'min-height': g_stbWindowHeight,
155
  'height': g_stbWindowHeight
156
  });
157
-
158
  // If turn on chosen plugin for selects of all types - there is conflict with handsontable plugin happen
159
- $('#row-tab-settings select[multiple="multiple"]').chosen({width: '100%'});
160
 
161
  // Tooltips and Shortcode select
162
  $('[data-toggle="tooltip"]').tooltip();
@@ -708,6 +732,261 @@ var g_stbCopyPasteColsCount = [];
708
  }
709
  });
710
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
711
  // Pro Notifications and Dialog Windows
712
  var $proNotify = $('.pro-notify');
713
 
22
  $(document).ready(function () {
23
  var tablesModel = app.Models.Tables,
24
  editor = app.Editor.Hot,
25
+ cssEditor = tablesModel.getCssEditor()
26
+ previewContainer = $('#table-preview');
27
 
28
  // Initialize Main Tabs
29
  var $mainTabsContent = $('.row-tab'),
46
  case '#row-tab-editor':
47
  editor.render();
48
  break;
49
+ case '#row-tab-settings':
50
  tablesModel.saveTable('#table-preview');
51
  break;
52
  case '#row-tab-css':
59
 
60
  // Initialize Sub Tabs
61
  var linksOyPositions = [],
62
+ settingsSection = $('.settings-section');
63
  offsetTop2 = Math.floor($("#stb-anl-main").offset().top);
64
  linksOyPositions.push({
65
  'id': '#stb-anl-main',
74
  'offset': Math.abs(Math.floor($("#stb-anl-appearance").offset().top) - offsetTop2 - 40),
75
  });
76
  linksOyPositions.push({
77
+ 'id': '#stb-anl-text',
78
+ 'offset': Math.abs(Math.floor($("#stb-anl-text").offset().top) - offsetTop2 - 40),
79
  });
 
 
 
 
 
80
 
81
  $('.settings-wrap').slimScroll({'height': g_stbWindowHeight+'px'}).off('slimscrolling')
82
  .on('slimscrolling', null, { 'oy': linksOyPositions }, function(e, pos){
83
  if(e && e.data && e.data.oy) {
84
  var ind1 = 0,
85
+ $activeItem = settingsSection.find('.stb-anchor-nav-links.active'),
86
  isFind = false;
87
  while(ind1 < (e.data.oy.length - 1) && !isFind) {
88
  if(e.data.oy[ind1].offset <= pos && e.data.oy[ind1+1].offset > pos) {
92
  ind1++;
93
  }
94
  // if current position at last anchor
95
+ if(isFind == false && ind1 == 3) {
96
  isFind = ind1;
97
  }
98
  //check curr active item
103
  $activeItem.removeClass('active');
104
  }
105
  // add active class
106
+ settingsSection.find('.stb-anchor-nav-links[href="' + e.data.oy[isFind].id + '"]').addClass('active');
107
  }
108
  }
109
  });
110
+ settingsSection.find('.stb-anchor-nav-links').on('click', function(e, funcParams) {
111
+ e.preventDefault();
112
  var $settingsWrap = $('.settings-wrap')
113
  , urlLink = $(this).attr('href')
114
  , $linkItem = $(urlLink)
126
  }
127
  }
128
  });
129
+ $('.preview-section .stb-anchor-nav-links').on('click', function(e, funcParams) {
130
+ e.preventDefault();
131
+ var href = $(this).attr('href');
132
+
133
+ g_stbMobilePreview = false;
134
+ $('.preview-styling a').removeClass('active');
135
+ $(this).addClass('active');
136
+ switch(href) {
137
+ case '#stb-style-desktop':
138
+ previewContainer.css('max-width', 'none');
139
+ break;
140
+ case '#stb-style-tablet':
141
+ previewContainer.css('max-width', '768px');
142
+ g_stbMobilePreview = true;
143
+ break;
144
+ case '#stb-style-mobile':
145
+ previewContainer.css('max-width', '380px');
146
+ g_stbMobilePreview = true;
147
+ break;
148
+ default:
149
+ break;
150
+ }
151
+ tablesModel.reinitPreview(previewContainer);
152
+ });
153
 
154
  // init anchor link
155
  setTimeout(function() {
156
  var slScrollTopPos = parseInt($('#slimScrollStartPos').val());
157
+ $('.settings-section .stb-anchor-nav-links[href="#stb-anl-main"]').trigger('click', {'offsetScTop':slScrollTopPos});
158
  }, 200);
159
 
160
  // Fix of conflict with handsontable library - it triggers error if user makes click on link without href attribute
168
  // Configure CSS Editor
169
  cssEditor.setTheme("ace/theme/monokai");
170
  cssEditor.getSession().setMode("ace/mode/css");
171
+ cssEditor.getSession().on('change', function() {
172
+ g_stbIsDataEdited['data'] = true;
173
+ });
174
 
175
  // Make editors responsive for window height
176
+ $('#tableEditor, #css-editor, #preview-container').css({
177
  'max-height': g_stbWindowHeight,
178
  'min-height': g_stbWindowHeight,
179
  'height': g_stbWindowHeight
180
  });
181
+
182
  // If turn on chosen plugin for selects of all types - there is conflict with handsontable plugin happen
183
+ $('#row-tab-settings select[multiple="multiple"], #row-tab-source select[multiple="multiple"]').chosen({width: '100%'});
184
 
185
  // Tooltips and Shortcode select
186
  $('[data-toggle="tooltip"]').tooltip();
732
  }
733
  });
734
 
735
+ // Table Styling
736
+ var previewTableId = 'supsystic-table-' + app.getParameterByName('id'),
737
+ tableSelector = '#' + previewTableId,
738
+ wrapperSelector = tableSelector + '_wrapper';
739
+ $('.color-picker-wrapper').each(function() {
740
+ var $this = $(this),
741
+ colorArea = $this.find('.color-picker-preview'),
742
+ colorInput = $this.parent().find('input.color-input'),
743
+ curColor = colorInput.val(),
744
+ timeoutSet = false;
745
+
746
+ $this.ColorPicker({
747
+ color: curColor,
748
+ onShow: function (colpkr) {
749
+ $this.ColorPickerSetColor(colorInput.val());
750
+ $(colpkr).fadeIn(500);
751
+ return false;
752
+ },
753
+ onHide: function (colpkr) {
754
+ $(colpkr).fadeOut(500);
755
+ return false;
756
+ },
757
+ onChange: function (hsb, hex, rgb) {
758
+ var self = this;
759
+ curColor = hex;
760
+ if(!timeoutSet) {
761
+ setTimeout(function(){
762
+ timeoutSet = false;
763
+ $(self).find('.colorpicker_submit').trigger('click');
764
+ }, 500);
765
+ timeoutSet = true;
766
+ }
767
+ },
768
+ onSubmit: function(hsb, hex, rgb, el) {
769
+ colorArea.css('backgroundColor', '#' + curColor);
770
+ colorInput.val('#' + curColor).trigger('change');
771
+ }
772
+ });
773
+ });
774
+
775
+ formSettings.find('input[name="styles[externalBorderWidth]"]').on('change', function() {
776
+ var wBorder = $(this).val(),
777
+ cBorder = formSettings.find('input[name="styles[externalBorderColor]"]').val();
778
+ tablesModel.updatePreviewCss([{selector: tableSelector, param: 'border', value: wBorder.length && cBorder.length ? wBorder + 'px solid ' + cBorder + ' !important' : ''}]);
779
+ });
780
+ formSettings.find('input[name="styles[externalBorderColor]"]').on('change', function() {
781
+ var cBorder = $(this).val(),
782
+ wBorder = formSettings.find('input[name="styles[externalBorderWidth]"]').val(),
783
+ isFill = wBorder.length && cBorder.length;
784
+ tablesModel.updatePreviewCss([
785
+ {selector: tableSelector, param: 'border', value: isFill ? wBorder + 'px solid ' + cBorder + ' !important' : ''},
786
+ {selector: wrapperSelector + ' .dataTables_scroll', param: 'border', value: isFill ? wBorder + 'px solid ' + cBorder + ' !important' : ''},
787
+ {selector: wrapperSelector + ' .DTFC_ScrollWrapper', param: 'border', value: isFill ? wBorder + 'px solid ' + cBorder + ' !important' : ''},
788
+ {selector: wrapperSelector + ' .DTFC_ScrollWrapper .dataTables_scroll', param: 'border', value: isFill ? 'none !important' : ''},
789
+ {selector: wrapperSelector + ' .dataTables_scrollBody table', param: 'border', value: isFill ? 'none !important' : ''},
790
+ ]);
791
+ $(this).parent().find('.color-picker-preview').css('backgroundColor', cBorder);
792
+ });
793
+
794
+ formSettings.find('input[name="styles[headerBorderWidth]"]').on('change', function() {
795
+ var wBorder = $(this).val(),
796
+ cBorder = formSettings.find('input[name="styles[headerBorderColor]"]').val();
797
+ tablesModel.updatePreviewCss([{selector: wrapperSelector + ' th', param: 'border', value: wBorder.length && cBorder.length ? wBorder + 'px solid ' + cBorder + ' !important' : ''}]);
798
+ });
799
+ formSettings.find('input[name="styles[headerBorderColor]"]').on('change', function() {
800
+ var cBorder = $(this).val(),
801
+ wBorder = formSettings.find('input[name="styles[headerBorderWidth]"]').val(),
802
+ isFill = wBorder.length && cBorder.length;
803
+ tablesModel.updatePreviewCss([
804
+ {selector: wrapperSelector + ' th', param: 'border', value: isFill ? wBorder + 'px solid ' + cBorder + ' !important' : ''},
805
+ {selector: wrapperSelector + ' .dataTables_scrollBody th', param: 'border-bottom', value: isFill ? 'none !important' : ''},
806
+ {selector: wrapperSelector + ' .dataTables_scrollBody th', param: 'border-top', value: isFill ? 'none !important' : ''},
807
+ {selector: wrapperSelector + ' .DTFC_LeftBodyWrapper th', param: 'border-bottom', value: isFill ? 'none !important' : ''},
808
+ {selector: wrapperSelector + ' .DTFC_LeftBodyWrapper th', param: 'border-top', value: isFill ? 'none !important' : ''},
809
+ {selector: wrapperSelector + ' .DTFC_RightBodyWrapper th', param: 'border-bottom', value: isFill ? 'none !important' : ''},
810
+ {selector: wrapperSelector + ' .DTFC_RightBodyWrapper th', param: 'border-top', value: isFill ? 'none !important' : ''},
811
+ {selector: wrapperSelector + ' .child table', param: 'border-collapse', value: isFill ? 'collapse' : ''},
812
+ ]);
813
+ $(this).parent().find('.color-picker-preview').css('backgroundColor', cBorder);
814
+ });
815
+ formSettings.find('input[name="styles[rowBorderWidth]"]').on('change', function() {
816
+ var wBorder = $(this).val(),
817
+ cBorder = formSettings.find('input[name="styles[rowBorderColor]"]').val(),
818
+ isFill = wBorder.length && cBorder.length;
819
+ tablesModel.updatePreviewCss([
820
+ {selector: wrapperSelector + ' td', param: 'border-top', value: isFill ? wBorder + 'px solid ' + cBorder : ''},
821
+ {selector: wrapperSelector + ' tbody tr:first-child td', param: 'border-top', value: isFill ? 'none' : ''},
822
+ {selector: wrapperSelector + ' tbody tr:last-child td', param: 'border-bottom', value: isFill ? wBorder + 'px solid ' + cBorder : ''},
823
+ {selector: wrapperSelector + ' .child table', param: 'border-collapse', value: isFill ? 'collapse' : ''}
824
+ ]);
825
+ });
826
+ formSettings.find('input[name="styles[rowBorderColor]"]').on('change', function() {
827
+ var cBorder = $(this).val(),
828
+ wBorder = formSettings.find('input[name="styles[rowBorderWidth]"]').val(),
829
+ isFill = wBorder.length && cBorder.length;
830
+ tablesModel.updatePreviewCss([
831
+ {selector: wrapperSelector + ' td', param: 'border-top', value: isFill ? wBorder + 'px solid ' + cBorder : ''},
832
+ {selector: wrapperSelector + ' tbody tr:first-child td', param: 'border-top', value: isFill ? 'none' : ''},
833
+ {selector: wrapperSelector + ' tbody tr:last-child td', param: 'border-bottom', value: isFill ? wBorder + 'px solid ' + cBorder : ''}
834
+ ]);
835
+ $(this).parent().find('.color-picker-preview').css('backgroundColor', cBorder);
836
+ });
837
+ formSettings.find('input[name="styles[columnBorderWidth]"]').on('change', function() {
838
+ var wBorder = $(this).val(),
839
+ cBorder = formSettings.find('input[name="styles[columnBorderColor]"]').val(),
840
+ isFill = wBorder.length && cBorder.length;
841
+ tablesModel.updatePreviewCss([
842
+ {selector: wrapperSelector + ' td', param: 'border-left', value: isFill ? wBorder + 'px solid ' + cBorder : ''},
843
+ {selector: wrapperSelector + ' td', param: 'border-right', value: isFill ? wBorder + 'px solid ' + cBorder : ''},
844
+ {selector: wrapperSelector + ' .child table', param: 'border-collapse', value: isFill ? 'collapse' : ''}
845
+ ]);
846
+ });
847
+ formSettings.find('input[name="styles[columnBorderColor]"]').on('change', function() {
848
+ var cBorder = $(this).val(),
849
+ wBorder = formSettings.find('input[name="styles[columnBorderWidth]"]').val(),
850
+ isFill = wBorder.length && cBorder.length;
851
+ tablesModel.updatePreviewCss([
852
+ {selector: wrapperSelector + ' td', param: 'border-left', value: isFill ? wBorder + 'px solid ' + cBorder : ''},
853
+ {selector: wrapperSelector + ' td', param: 'border-right', value: isFill ? wBorder + 'px solid ' + cBorder : ''},
854
+ {selector: wrapperSelector + ' tbody tr:first-child td', param: 'border-top', value: isFill ? 'none' : ''}
855
+ ]);
856
+ $(this).parent().find('.color-picker-preview').css('backgroundColor', cBorder);
857
+ });
858
+
859
+ formSettings.find('input[name="styles[headerBackgroundColor]"]').on('change', function() {
860
+ var color = $(this).val();
861
+ tablesModel.updatePreviewCss([{selector: wrapperSelector + ' th', param: 'background-color', value: color + ' !important'}]);
862
+ $(this).parent().find('.color-picker-preview').css('backgroundColor', color);
863
+ });
864
+ formSettings.find('input[name="styles[headerFontColor]"]').on('change', function() {
865
+ var color = $(this).val();
866
+ tablesModel.updatePreviewCss([{selector: wrapperSelector + ' th', param: 'color', value: color}]);
867
+ $(this).parent().find('.color-picker-preview').css('backgroundColor', color);
868
+ });
869
+ formSettings.find('input[name="styles[headerFontSize]"]').on('change', function() {
870
+ var size = $(this).val();
871
+ tablesModel.updatePreviewCss([{selector: wrapperSelector + ' th', param: 'font-size', value: size.length ? size + 'px' : ''}]);
872
+ });
873
+ formSettings.find('input[name="styles[cellBackgroundColor]"]').on('change', function() {
874
+ var color = $(this).val(),
875
+ even = tablesModel.getLightenDarkenColor(color, -20),
876
+ hover = tablesModel.getLightenDarkenColor(color, -40);
877
+ tablesModel.updatePreviewCss([
878
+ {selector: wrapperSelector + ' tbody tr', param: 'background-color', value: color},
879
+ {selector: wrapperSelector + ' table.stripe tbody tr.even', param: 'background-color', value: even},
880
+ {selector: wrapperSelector + ' table.stripe.order-column tbody tr > .sorting_1', param: 'background-color', value: even},
881
+ {selector: wrapperSelector + ' table.hover tbody tr:hover', param: 'background-color', value: hover},
882
+ {selector: wrapperSelector + ' table.stripe.order-column tbody tr.even > .sorting_1', param: 'background-color', value: hover},
883
+ {selector: wrapperSelector + ' table.order-column tbody tr > .sorting_1', param: 'background-color', value: even},
884
+ {selector: wrapperSelector + ' table.hover.order-column tbody tr:hover > .sorting_1', param: 'background-color', value: tablesModel.getLightenDarkenColor(color, -60)},
885
+ {selector: wrapperSelector + ' tbody td', param: 'background-color', value: 'inherit'},
886
+ ]);
887
+ $(this).parent().find('.color-picker-preview').css('backgroundColor', color);
888
+ });
889
+ formSettings.find('input[name="styles[cellFontColor]"]').on('change', function() {
890
+ var color = $(this).val();
891
+ tablesModel.updatePreviewCss([{selector: wrapperSelector + ' td', param: 'color', value: color}]);
892
+ $(this).parent().find('.color-picker-preview').css('backgroundColor', color);
893
+ });
894
+ formSettings.find('input[name="styles[cellFontSize]"]').on('change', function() {
895
+ var size = $(this).val();
896
+ tablesModel.updatePreviewCss([{selector: wrapperSelector + ' td', param: 'font-size', value: size.length ? size + 'px' : ''}]);
897
+ });
898
+ var headerFonts = formSettings.find('select[name="styles[headerFontFamily]"]'),
899
+ cellFonts = formSettings.find('select[name="styles[cellFontFamily]"]');
900
+ $('#fontFamily option').each(function() {
901
+ var option = '<option value="' + $(this).val() + '">' + $(this).text() + '</option>';
902
+ headerFonts.append(option);
903
+ cellFonts.append(option);
904
+ });
905
+ headerFonts.val(headerFonts.data('value'));
906
+ cellFonts.val(cellFonts.data('value'));
907
+ headerFonts.on('change', function() {
908
+ var family = $(this).val();
909
+ tablesModel.updatePreviewCss([{selector: wrapperSelector + ' th', param: 'font-family', value: family == 'default' ? '' : family}]);
910
+ });
911
+ cellFonts.on('change', function() {
912
+ var family = $(this).val();
913
+ tablesModel.updatePreviewCss([{selector: wrapperSelector + ' td', param: 'font-family', value: family == 'default' ? '' : family}]);
914
+ });
915
+
916
+ var searchSelector = tableSelector + '_filter input, '+wrapperSelector+' .stbColumnsSearchWrapper input';
917
+ formSettings.find('input[name="styles[searchBackgroundColor]"]').on('change', function() {
918
+ var color = $(this).val();
919
+ tablesModel.updatePreviewCss([{selector: searchSelector, param: 'background-color', value: color.length ? color + ' !important' : ''}]);
920
+ $(this).parent().find('.color-picker-preview').css('backgroundColor', color);
921
+ });
922
+ formSettings.find('input[name="styles[searchFontColor]"]').on('change', function() {
923
+ var color = $(this).val();
924
+ tablesModel.updatePreviewCss([{selector: searchSelector, param: 'color', value: color.length ? color + ' !important' : ''}]);
925
+ $(this).parent().find('.color-picker-preview').css('backgroundColor', color);
926
+ });
927
+ formSettings.find('input[name="styles[searchBorderColor]"]').on('change', function() {
928
+ var color = $(this).val();
929
+ tablesModel.updatePreviewCss([{selector: searchSelector, param: 'border', value: color.length ? '1px solid ' + color + ' !important' : ''}]);
930
+ $(this).parent().find('.color-picker-preview').css('backgroundColor', color);
931
+ });
932
+ formSettings.find('input[name="styles[fixedLayout]"]').on('change ifChanged', function() {
933
+ var checked = $(this).is(':checked');
934
+ tablesModel.updatePreviewCss([
935
+ {selector: tableSelector, param: 'table-layout', value: checked ? 'fixed !important' : ''},
936
+ {selector: tableSelector, param: 'overflow-wrap', value: checked ? 'break-word' : ''},
937
+ {selector: wrapperSelector + ' .dataTables_scroll table', param: 'table-layout', value: checked ? 'fixed !important' : ''},
938
+ {selector: wrapperSelector + ' .dataTables_scroll table', param: 'overflow-wrap', value: checked ? 'break-word' : ''},
939
+ ]);
940
+ });
941
+ formSettings.find('select[name="styles[verticalAlignment]"]').on('change', function() {
942
+ tablesModel.updatePreviewCss([{selector: tableSelector + ' th, ' + tableSelector + ' td', param: 'vertical-align', value: $(this).val()}]);
943
+ });
944
+ formSettings.find('select[name="styles[horizontalAlignment]"]').on('change', function() {
945
+ tablesModel.updatePreviewCss([{selector: tableSelector + ' th, ' + tableSelector + ' td', param: 'text-align', value: $(this).val()}]);
946
+ });
947
+ formSettings.find('select[name="styles[paginationPosition]"]').on('change', function() {
948
+ var position = $(this).val();
949
+ tablesModel.updatePreviewCss([
950
+ {selector: wrapperSelector + ' .dataTables_paginate', param: 'text-align', value: position},
951
+ {selector: wrapperSelector + ' .dataTables_paginate', param: 'float', value: position.length ? 'none' : ''}
952
+ ]);
953
+ });
954
+ formSettings.find('input[name="styles[showSortHover]"]').on('change ifChanged', function() {
955
+ var checked = $(this).is(':checked');
956
+ tablesModel.updatePreviewCss([
957
+ {selector: wrapperSelector + ' table .sorting', param: 'background-image', value: checked ? 'none' : ''},
958
+ {selector: wrapperSelector + ' table th.sorting:hover', param: 'background-image', value: checked ? 'url("'+SDT_DATA.pluginsUrl.replace(SDT_DATA.siteUrl, '/')+'/data-tables-generator-by-supsystic/src/SupsysticTables/Core/assets/css/images/sort_both.png")' : ''}
959
+ ]);
960
+ });
961
+
962
+ $('#stb-preview-css').text(formSettings.find('input[name="styles[customCss]"]').val().replace(new RegExp('supsystic-table-{id}', 'g'), previewTableId));
963
+
964
+ formSettings.find('input[name="styles[useCustomStyles]"]').on('change ifChanged', function() {
965
+ if($(this).is(':checked')) {
966
+ $('.table-styles-options').show();
967
+ tablesModel.disablePreviewCss(false);
968
+ tablesModel.updatePreviewCss([{selector: wrapperSelector + ' table', param: 'border-collapse', value: 'collapse'}]);
969
+ formSettings.find('.table-styles-options input, .table-styles-options select').trigger('change');
970
+ } else {
971
+ $('.table-styles-options').hide();
972
+ tablesModel.disablePreviewCss(true);
973
+ }
974
+ });
975
+
976
+ formSettings.find('.setting-wrapper input, .setting-input select, textarea').on('change ifChanged', function(e) {
977
+ g_stbIsDataEdited['settings'] = true;
978
+ var $this = $(this);
979
+ tablesModel.controlSettingsValues($this);
980
+ if($this.attr('data-preview-not-redraw') == '1') {
981
+ return;
982
+ }
983
+
984
+ if($this.attr('data-need-data-save') == '1') {
985
+ g_stbIsDataEdited['data'] = true;
986
+ }
987
+ tablesModel.saveTable('#table-preview', $this.attr('data-need-settings-save') == '1' ? 2 : 1);
988
+ });
989
+
990
  // Pro Notifications and Dialog Windows
991
  var $proNotify = $('.pro-notify');
992
 
src/SupsysticTables/Tables/assets/libraries/ruleJS/handsontable.formula.js CHANGED
@@ -181,7 +181,8 @@
181
  });
182
 
183
  if (rerender) {
184
- instance.render();
 
185
  }
186
  }
187
  };
181
  });
182
 
183
  if (rerender) {
184
+ //instance.render();
185
+ instance.renderWithRecalc();
186
  }
187
  }
188
  };
src/SupsysticTables/Tables/assets/libraries/ruleJS/ruleJS.js CHANGED
@@ -139,6 +139,17 @@ var ruleJS = (function (root) {
139
  })[0];
140
  };
141
 
 
 
 
 
 
 
 
 
 
 
 
142
  /**
143
  * remove item from data array
144
  * @param {String} id
@@ -437,16 +448,20 @@ var ruleJS = (function (root) {
437
  }
438
  }
439
  }
 
440
  if (element.innerText) {
441
- element.innerText = renderedValue || error;
 
442
  } else {
443
- element.textContent = renderedValue || error;
 
444
  }
445
  /* */
446
  }
447
 
448
-
449
- element.value = value || error;
 
450
 
451
  return parsed;
452
  };
@@ -1301,7 +1316,7 @@ var ruleJS = (function (root) {
1301
  var cellId = instance.utils.translateCellCoords({row: element.row, col: element.col});
1302
 
1303
  // get value
1304
- value = item ? item.value : (isEditorPagination ? window.editor.bufferData[cellCoords.row][cellCoords.col] : fnCellValue(cellCoords.row, cellCoords.col));
1305
 
1306
  if (instance.utils.isNull(value)) {
1307
  value = 0;
@@ -1466,20 +1481,24 @@ var ruleJS = (function (root) {
1466
  error = null;
1467
 
1468
  try {
1469
-
1470
- parser.setObj(element);
1471
- result = parser.parse(formula);
1472
- var id;
1473
-
1474
  if (element instanceof HTMLElement) {
1475
  id = element.getAttribute('data-cell-id');
1476
  } else if (element && element.id) {
1477
  id = element.id;
1478
  }
1479
 
1480
- var deps = instance.matrix.getDependencies(id);
1481
 
1482
- if (deps.indexOf(id) !== -1) {
 
 
 
 
 
 
 
 
 
1483
  result = null;
1484
 
1485
  deps.forEach(function (id) {
@@ -1488,11 +1507,17 @@ var ruleJS = (function (root) {
1488
 
1489
  throw Error('REF');
1490
  }
1491
-
1492
  if(!error && result === 0) {
1493
  result = "0";
1494
  }
1495
 
 
 
 
 
 
 
1496
  } catch (ex) {
1497
  // Errors debugging
1498
  //console.log(ex);
@@ -1650,7 +1675,15 @@ var ruleJS = (function (root) {
1650
  instance.custom = {};
1651
 
1652
  if (rootElement) {
1653
- instance.matrix.scan();
 
 
 
 
 
 
 
 
1654
  helper.unescapeHTML(rootElement);
1655
  }
1656
  };
139
  })[0];
140
  };
141
 
142
+ this.needRecalc = function () {
143
+ var need = false;
144
+ jQuery.each(instance.matrix.data, function (i, item) {
145
+ if(item.needUpdate || item.error === '#NEED_UPDATE') {
146
+ need = true;
147
+ return false;
148
+ }
149
+ });
150
+ return need;
151
+ };
152
+
153
  /**
154
  * remove item from data array
155
  * @param {String} id
448
  }
449
  }
450
  }
451
+ var renderedResult = renderedValue || error;
452
  if (element.innerText) {
453
+ if(renderedResult != element.innerText) instance.isEdited = true;
454
+ element.innerText = renderedResult;
455
  } else {
456
+ if(renderedResult != element.textContent) instance.isEdited = true;
457
+ element.textContent = renderedResult;
458
  }
459
  /* */
460
  }
461
 
462
+ var parseResult = value || error;
463
+ if(parseResult != element.value) instance.isEdited = true;
464
+ element.value = parseResult;
465
 
466
  return parsed;
467
  };
1316
  var cellId = instance.utils.translateCellCoords({row: element.row, col: element.col});
1317
 
1318
  // get value
1319
+ value = item ? item.value : (isEditorPagination ? window.editor.getCellValuePagination(cellCoords.row, cellCoords.col) : fnCellValue(cellCoords.row, cellCoords.col));
1320
 
1321
  if (instance.utils.isNull(value)) {
1322
  value = 0;
1481
  error = null;
1482
 
1483
  try {
 
 
 
 
 
1484
  if (element instanceof HTMLElement) {
1485
  id = element.getAttribute('data-cell-id');
1486
  } else if (element && element.id) {
1487
  id = element.id;
1488
  }
1489
 
1490
+ var curItem = instance.matrix.getItem(id);
1491
 
1492
+ parser.setObj(element);
1493
+ result = parser.parse(formula);
1494
+ var id;
1495
+
1496
+
1497
+
1498
+ var deps = instance.matrix.getDependencies(id),
1499
+ isFrontend = (typeof instance.isFrontend != 'undefined' || instance.isFrontend);
1500
+
1501
+ if (!isFrontend && deps.indexOf(id) !== -1) {
1502
  result = null;
1503
 
1504
  deps.forEach(function (id) {
1507
 
1508
  throw Error('REF');
1509
  }
1510
+
1511
  if(!error && result === 0) {
1512
  result = "0";
1513
  }
1514
 
1515
+ if(!isFrontend && curItem && curItem.value != result) {
1516
+ deps.forEach(function (id) {
1517
+ instance.matrix.updateItem(id, {value: null, needUpdate: true});
1518
+ });
1519
+ }
1520
+
1521
  } catch (ex) {
1522
  // Errors debugging
1523
  //console.log(ex);
1675
  instance.custom = {};
1676
 
1677
  if (rootElement) {
1678
+ var recalcLimit = 5;
1679
+ instance.isFrontend = true;
1680
+ do {
1681
+ instance.isEdited = false;
1682
+ instance.matrix.scan();
1683
+ recalcLimit--;
1684
+ } while(instance.isEdited && recalcLimit > 0);
1685
+
1686
+ //instance.matrix.scan();
1687
  helper.unescapeHTML(rootElement);
1688
  }
1689
  };
src/SupsysticTables/Tables/assets/libraries/ruleJS/ruleJS.lib.full.js CHANGED
@@ -20836,6 +20836,7 @@ this.j$ = this.jStat = (function(Math, undefined) {
20836
  // Custom supsystic formulas
20837
  Formula.HYPERLINK = function(url, linkLabel) {
20838
  linkLabel = linkLabel ? linkLabel : url;
 
20839
 
20840
  var res = linkLabel,
20841
  protocols = ['http', 'https', 'mailto', 'aim:', 'ftp', 'gopher', 'telnet'],
20836
  // Custom supsystic formulas
20837
  Formula.HYPERLINK = function(url, linkLabel) {
20838
  linkLabel = linkLabel ? linkLabel : url;
20839
+ window.supsystic.Tables._hyperlinkUrl = url; // to collect correct calculate value during table saving
20840
 
20841
  var res = linkLabel,
20842
  protocols = ['http', 'https', 'mailto', 'aim:', 'ftp', 'gopher', 'telnet'],
src/SupsysticTables/Tables/views/partials/historyTabContent.twig CHANGED
@@ -15,7 +15,7 @@
15
  </div>
16
  <div class="col-xs-12">
17
  <a href="{{ url }}" target="_blank">
18
- <img style="max-width:800px;" src="{{ environment.getModule('tables').getLocationUrl() }}/assets/img/history_table.gif" alt="Tables History" title="Available in PRO version" style="width: 100%; height: auto;">
19
  </a>
20
  </div>
21
  {% endblock %}
15
  </div>
16
  <div class="col-xs-12">
17
  <a href="{{ url }}" target="_blank">
18
+ <img style="max-width:100%" src="{{ environment.getModule('core').getCdnUrl() }}_assets/tables/img/settings/history_table.gif" alt="Tables History" title="Available in PRO version" style="width: 100%; height: auto;">
19
  </a>
20
  </div>
21
  {% endblock %}
src/SupsysticTables/Tables/views/partials/sourceTab.twig ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <li>
2
+ <a href="#row-tab-source" class="button">
3
+ <i class="fa fa-database" aria-hidden="true"></i>
4
+ {{ environment.translate('Source') }}
5
+ </a>
6
+ </li>
src/SupsysticTables/Tables/views/partials/sourceTabContent.twig ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="row row-tab" id="row-tab-source">
2
+ {% block content %}
3
+ {% import '@ui/tooltip.twig' as tooltip %}
4
+ <div class="col-xs-12">
5
+ <h3 style="display:inline-block;">
6
+ {{ environment.translate('Source') }}&nbsp;
7
+ {{ tooltip.icon('Database Source Pro feature allows you display table and its fields data from any table of WP database or External databases on the front-end. <a target="_blank" href="https://supsystic.com/documentation/database-source/"></br>Read more</a>.' | raw, 'top', true) }}
8
+ </h3>
9
+ </br>
10
+ <a href="{{ build_pro_url({ 'utm_medium': 'table-source-database'}) }}" class="button button-hero" target="_blank">
11
+ {{ environment.translate('Get PRO') }}
12
+ </a>
13
+ </div>
14
+ <div class="col-xs-12">
15
+ <a target="_blank" href="{{ build_pro_url({ 'utm_medium': notify }) }}">
16
+ <img style="max-width:100%" src="{{ environment.getModule('core').getCdnUrl() }}_assets/tables/img/settings/database.gif" alt="Database Source" title="Available in PRO version" style="width: 100%; height: auto;">
17
+ </a>
18
+ </div>
19
+ {% endblock %}
20
+ </div>
src/SupsysticTables/Tables/views/shortcode.twig CHANGED
@@ -71,7 +71,11 @@
71
  and context.table.meta.columnsWidth[cellIndex] is not empty
72
  %}
73
  {#style="min-width: {{ context.table.meta.columnsWidth[cellIndex] }}%; width: {{ context.table.meta.columnsWidth[cellIndex] }}%;"#}
74
- style="min-width: {{ context.table.meta.columnsWidth[cellIndex] }}%; "
 
 
 
 
75
  {% else %}
76
  style="width: {{ cell.width }}px"
77
  {% endif %}
@@ -162,17 +166,20 @@
162
  visibility: hidden;
163
  {% endif %}
164
  "
165
- {% if tableWidth is defined and table.settings.tableWidthMobileType is defined %}
166
- {% if table.settings.tableWidthMobileType == 'auto' %}
167
- {% set tableWidthMobile = 'auto' %}
168
- {% elseif table.settings.tableWidthMobile is defined %}
169
- {% set tableWidthMobile = table.settings.tableWidthMobile ~ table.settings.tableWidthMobileType %}
 
 
 
 
170
  {% endif %}
171
- data-table-width-mobile="{{ tableWidthMobile }}"
172
  {% endif %}
173
  >
174
  {% block before_table %}{% endblock %}
175
- {% if table.woo_settings is defined and table.woo_settings.woocommerce.multiple_add_cart =='on' %}
176
  <div class="stAddMultyWrapper"><button class="button stAddMultyButton stHidden" data-table-id="{{ table.id }}"><span>{{ environment.translate('Add selected to cart') }}</span></button></div>
177
  {% endif %}
178
  {% block caption_fixed %}
@@ -237,6 +244,9 @@
237
  {% if 'paginationMenuLength' in settingsKeys %}
238
  data-pagination-length="{{ table.settings.paginationMenuLength | default('') }}"
239
  {% endif %}
 
 
 
240
  {% if 'alignByFirstTable' in settingsKeys and 'auto_width' not in table.settings.features | keys %}
241
  data-align-by-first-table="{{ table.settings.alignByFirstTable | default('') }}"
242
  {% endif %}
@@ -486,6 +496,9 @@
486
  {% endif %}
487
  {% endblock %}
488
  </table>
 
 
 
489
  <!-- /#supsystic-table-{{ table.id }}.supsystic-table -->
490
 
491
  {% block signature %}
71
  and context.table.meta.columnsWidth[cellIndex] is not empty
72
  %}
73
  {#style="min-width: {{ context.table.meta.columnsWidth[cellIndex] }}%; width: {{ context.table.meta.columnsWidth[cellIndex] }}%;"#}
74
+ {% if context.table.settings.responsiveMode == 2 %}
75
+ style="min-width: {{ context.table.meta.columnsWidth[cellIndex] }}%; width: {{ context.table.meta.columnsWidth[cellIndex] }}%;"
76
+ {% else %}
77
+ style="min-width: {{ context.table.meta.columnsWidth[cellIndex] }}%; "
78
+ {% endif %}
79
  {% else %}
80
  style="width: {{ cell.width }}px"
81
  {% endif %}
166
  visibility: hidden;
167
  {% endif %}
168
  "
169
+ {% if tableWidth is defined %}
170
+ data-table-width-fixed="{{ tableWidth }}"
171
+ {% if table.settings.tableWidthMobileType is defined %}
172
+ {% if table.settings.tableWidthMobileType == 'auto' %}
173
+ {% set tableWidthMobile = 'auto' %}
174
+ {% elseif table.settings.tableWidthMobile is defined %}
175
+ {% set tableWidthMobile = table.settings.tableWidthMobile ~ table.settings.tableWidthMobileType %}
176
+ {% endif %}
177
+ data-table-width-mobile="{{ tableWidthMobile }}"
178
  {% endif %}
 
179
  {% endif %}
180
  >
181
  {% block before_table %}{% endblock %}
182
+ {% if table.woo_settings is defined and table.woo_settings.woocommerce.enable == 'on' and table.woo_settings.woocommerce.multiple_add_cart =='on' %}
183
  <div class="stAddMultyWrapper"><button class="button stAddMultyButton stHidden" data-table-id="{{ table.id }}"><span>{{ environment.translate('Add selected to cart') }}</span></button></div>
184
  {% endif %}
185
  {% block caption_fixed %}
244
  {% if 'paginationMenuLength' in settingsKeys %}
245
  data-pagination-length="{{ table.settings.paginationMenuLength | default('') }}"
246
  {% endif %}
247
+ {% if 'scrollTopByPagination' in settingsKeys %}
248
+ data-pagination-scroll="{{ table.settings.scrollTopByPagination | default('') }}"
249
+ {% endif %}
250
  {% if 'alignByFirstTable' in settingsKeys and 'auto_width' not in table.settings.features | keys %}
251
  data-align-by-first-table="{{ table.settings.alignByFirstTable | default('') }}"
252
  {% endif %}
496
  {% endif %}
497
  {% endblock %}
498
  </table>
499
+ {% if show_edit_link %}
500
+ {{ show_edit_link | raw }}
501
+ {% endif %}
502
  <!-- /#supsystic-table-{{ table.id }}.supsystic-table -->
503
 
504
  {% block signature %}
src/SupsysticTables/Tables/views/styles.twig CHANGED
@@ -1 +1,4 @@
1
- <style type="text/css" id="supsystic-table-{{ tableObj.view_id }}-css">{{ tableObj.meta.css | raw }}</style>
 
 
 
1
+ <style type="text/css" id="supsystic-table-{{ viewId }}-css">
2
+ {{ customStyles|raw }}
3
+ {{ styles|raw }}
4
+ </style>
src/SupsysticTables/Tables/views/view.twig CHANGED
@@ -116,31 +116,17 @@
116
  </span>
117
  </li>
118
  <li>
119
- {% set settingClass = '' %}
120
- {% set editorClass = '' %}
121
- {% if attributes is defined and attributes.new == '1' %}
122
- {% set editorClass = 'current ' %}
123
- {% else %}
124
- {% set settingClass = 'current ' %}
125
- {% endif %}
126
-
127
- <a href="#row-tab-settings" class="{{ settingClass }}button">
128
  <i class="fa fa-fw fa-wrench"></i>
129
  {{ environment.translate('Settings') }}
130
  </a>
131
  </li>
132
  <li>
133
- <a href="#row-tab-editor" class="{{ editorClass }}button">
134
  <i class="fa fa-fw fa-th"></i>
135
  {{ environment.translate('Editor') }}
136
  </a>
137
  </li>
138
- <li>
139
- <a href="#row-tab-preview" class="button">
140
- <i class="fa fa-fw fa-eye"></i>
141
- {{ environment.translate('Preview') }}
142
- </a>
143
- </li>
144
  <li>
145
  <a href="#row-tab-css" class="button">
146
  <i class="fa fa-fw fa-code"></i>
@@ -154,202 +140,193 @@
154
  </div>
155
 
156
  <div class="row row-tab" id="row-tab-settings">
157
-
158
  <div class="stb-wraper-anchor-nav-links">
159
  <a href="#stb-anl-main" class="stb-anchor-nav-links">{{ translate('Main')}}</a>
160
  <a href="#stb-anl-features" class="stb-anchor-nav-links">{{ translate('Features')}}</a>
161
  <a href="#stb-anl-appearance" class="stb-anchor-nav-links">{{ translate('Appearance')}}</a>
162
- <a href="#stb-anl-language" class="stb-anchor-nav-links">{{ translate('Language and Text')}}</a>
163
- <a href="#stb-anl-source" class="stb-anchor-nav-links">{{ translate('Source')}}</a>
164
  </div>
165
  <div class="settings-wrap">
166
  <form id="settings">
167
- <section class="row-settings-tabs">
168
- <section class="row row-settings-tab" id="stb-anl-main">
169
- <div class="title-block col-xs-12">
170
- <h3>{{ environment.translate('Main Settings') }}</h3>
171
- </div>
172
- <div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
173
- <div class="title-place">
174
  <h3>{{ environment.translate('Table Elements') }}</h3>
175
  </div>
176
- <div class="setting-wrapper row">
177
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
178
  <label for="table-elements-caption">
179
  {{ environment.translate('Caption') }}
180
  {{ tooltip.icon('Check here if you want to show the name of the table above the table', 'top', true) }}
181
  </label>
182
  </div>
183
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
184
  <input type="checkbox" name="elements[caption]"
185
  {{ checkbox.checked(table.settings.elements.caption) }}
186
  id="table-elements-caption"/>
187
- <!-- /#table-elements-caption -->
188
  </div>
189
  </div>
190
- <div class="setting-wrapper row">
191
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
192
  <label for="table-elements-description">
193
  {{ environment.translate('Description') }}
194
  {{ tooltip.icon('You can add short description to the table between title and table', 'top', true) }}
195
  </label>
196
  </div>
197
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
198
  <input type="checkbox" name="elements[description]"
199
  {{ checkbox.checked(table.settings.elements.description) }}
200
- id="table-elements-description"
201
  data-target-toggle=".table-elements-description-options"/>
202
  <!-- /#table-elements-caption -->
203
  </div>
204
  </div>
205
- <div class="setting-wrapper row table-elements-description-options"
206
  {% if table.settings.elements.description is not defined %}
207
  style="display:none"
208
  {% endif %}
209
  >
210
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
211
  <label for="descriptionText">
212
  {{ environment.translate('Description Text') }}
213
  </label>
214
  </div>
215
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
216
  <textarea id="descriptionText">{{ table.settings.elements.descriptionText | default('') }}</textarea>
217
  <input type="hidden" name="elements[descriptionText]" value="{{ table.settings.elements.descriptionText | default('') }}" />
218
- <!-- /#table-elements-caption -->
219
  </div>
220
  </div>
221
- <div class="setting-wrapper row">
222
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
223
  <label for="table-elements-signature">
224
  {{ environment.translate('Signature') }}
225
  {{ tooltip.icon('You can add signature under table footer', 'top', true) }}
226
  </label>
227
  </div>
228
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
229
  <input type="checkbox" name="elements[signature]"
230
  {{ checkbox.checked(table.settings.elements.signature) }}
231
- id="table-elements-signature"
232
  data-target-toggle=".table-elements-signature-options"/>
233
- <!-- /#table-elements-caption -->
234
  </div>
235
  </div>
236
- <div class="setting-wrapper row table-elements-signature-options"
237
  {% if table.settings.elements.signature is not defined %}
238
  style="display:none"
239
  {% endif %}
240
  >
241
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
242
  <label for="signatureText">
243
  {{ environment.translate('Signature Text') }}
244
  </label>
245
  </div>
246
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
247
  <textarea id="signatureText">{{ table.settings.elements.signatureText | default('') }}</textarea>
248
  <input type="hidden" name="elements[signatureText]" value="{{ table.settings.elements.signatureText | default('') }}" />
249
- <!-- /#table-elements-caption -->
250
  </div>
251
  </div>
252
- <div class="setting-wrapper row">
253
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
254
  <label for="table-elements-head">
255
  {{ environment.translate('Header') }}
256
  {{ tooltip.icon('<img src="http://supsystic.com/_assets/tables/tooltip/Header.jpg"/>', 'top', true) }}
257
  </label>
258
  </div>
259
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
260
  <input type="checkbox" name="elements[head]"
261
  {{ checkbox.checked(table.settings.elements.head) }}
262
  id="table-elements-head"
263
  data-target-toggle=".table-elements-head-options"/>
264
- <!-- /#table-elements-head -->
265
  </div>
266
  </div>
267
- <div class="setting-wrapper row table-elements-head-options"
268
  {% if table.settings.elements.head is not defined %}
269
  style="display:none"
270
  {% endif %}
271
  >
272
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
273
  <label for="headerRowsCount">
274
  {{ environment.translate('Count of Header Rows') }}
275
  {{ tooltip.icon(environment.translate('Count of table rows, which will be moved to header.')) }}
276
  </label>
277
  </div>
278
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
279
  <input name="headerRowsCount" id="headerRowsCount" type="text" value="{{ table.settings.headerRowsCount | default(1) }}">
280
  </div>
281
  </div>
282
- <div class="setting-wrapper row">
283
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
284
  <label for="table-elements-foot">
285
  {{ environment.translate('Footer') }}
286
  {{ tooltip.icon('<img src="http://supsystic.com/_assets/tables/tooltip/footer.jpg"/>', 'top', true) }}
287
  </label>
288
  </div>
289
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
290
  <input type="checkbox" name="elements[foot]"
291
  {{ checkbox.checked(table.settings.elements.foot) }}
292
  id="table-elements-foot"
293
  data-target-toggle=".table-elements-foot-options"/>
294
- <!-- /#table-elements-foot -->
295
  </div>
296
  </div>
297
- <div class="setting-wrapper row table-elements-foot-options"
298
  {% if table.settings.elements.foot is not defined %}
299
  style="display:none"
300
  {% endif %}
301
  >
302
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
303
  <label for="customFooter">
304
  {{ environment.translate('Custom Footer') }}
305
  {{ tooltip.icon(environment.translate('If checked - footer will be created from the last table rows. Otherwise - footer will be created from header rows.')) }}
306
  </label>
307
  </div>
308
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
309
  <input type="checkbox" name="customFooter"
310
  {{ checkbox.checked(table.settings.customFooter) }}
311
  id="customFooter"
312
  data-target-toggle=".custom-footer-options"/>
313
  </div>
314
  </div>
315
- <div class="setting-wrapper row custom-footer-options"
316
  {% if table.settings.elements.foot is not defined or table.settings.customFooter is not defined %}
317
  style="display:none"
318
  {% endif %}
319
  >
320
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
321
  <label for="footerRowsCount">
322
  {{ environment.translate('Count of Footer Rows') }}
323
  {{ tooltip.icon(environment.translate('Count of table rows, which will be moved to footer.')) }}
324
  </label>
325
  </div>
326
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
327
  <input name="footerRowsCount" id="footerRowsCount" type="text" value="{{ table.settings.footerRowsCount | default(1) }}">
328
  </div>
329
  </div>
330
- <div class="setting-wrapper row">
331
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
332
  <label for="features-fixed-header">
333
  {{ environment.translate('Fixed Header') }}
334
  {{ tooltip.icon(environment.translate('Allows to fix the table\'s header during table scrolling. Important! Header option must be enabled for using this feature. Also you need to set Fixed Table Height to create a vertical scroll for your table. To see the work of this feature you should not use such Responsive Modes such as Standard and Automatic columns hiding.')) }}
335
  </label>
336
  </div>
337
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
338
  <input type="checkbox" name="fixedHeader"
339
  {{ checkbox.checked(table.settings.fixedHeader) }}
340
  id="features-fixed-header"
341
  class="features-fixed-header-footer"/>
342
- <!-- /#features-fixed-header -->
343
  </div>
344
  </div>
345
- <div class="setting-wrapper row">
346
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
347
  <label for="features-fixed-footer">
348
  {{ environment.translate('Fixed Footer') }}
349
  {{ tooltip.icon(environment.translate('Allows to fix the table\'s footer during table scrolling. Important! Footer option must be enabled for using this feature. Also you need to set Fixed Table Height to create a vertical scroll at the table. To see the work of this feature you should not use such Responsive Modes as Standard and Automatic columns hiding.')) }}
350
  </label>
351
  </div>
352
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
353
  <input type="checkbox" name="fixedFooter"
354
  {{ checkbox.checked(table.settings.fixedFooter) }}
355
  id="features-fixed-footer"
@@ -357,74 +334,73 @@
357
  <!-- /#features-fixed-footer -->
358
  </div>
359
  </div>
360
- <div class="setting-wrapper row features-fixed-height"
361
  {% if table.settings.fixedHeader is not defined and table.settings.fixedFooter is not defined %}
362
  style="display:none"
363
  {% endif %}
364
  >
365
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
366
  <label for="fixedHeight">
367
  {{ environment.translate('Fixed Table Height') }}
368
  {{ tooltip.icon(environment.translate('Fixed table height in px. This value must be less than the original table height to create a vertical scroll, otherwise you will not see that the fixed header / footer exists.')) }}
369
  </label>
370
  </div>
371
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
372
  <input name="fixedHeight" id="fixedHeight" type="text" value="{{ table.settings.fixedHeight | default(400) }}">
373
  </div>
374
  </div>
375
- <div class="setting-wrapper row">
376
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
377
  <label for="features-fixed-columns">
378
  {{ environment.translate('Fixed Columns') }}
379
  {{ tooltip.icon(environment.translate('Allows to fix columns during table scrolling. Important! The fixing of columns suggests that the table will have a horisontal scroll type of responsive mode, otherwise you will not see that the fixed columns exist. So this feature is a kind of responsive mode on its own and will not work with such Responsive Modes as Standard and Automatic columns hiding.')) }}
380
  </label>
381
  </div>
382
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
383
  <input type="checkbox" name="fixedColumns"
384
  {{ checkbox.checked(table.settings.fixedColumns) }}
385
  id="features-fixed-columns"
386
  data-target-toggle=".fixed-columns-options"/>
387
- <!-- /#features-fixed-columns -->
388
  </div>
389
  </div>
390
- <div class="setting-wrapper row fixed-columns-options"
391
  {% if table.settings.fixedColumns is not defined %}
392
  style="display:none"
393
  {% endif %}
394
  >
395
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
396
  <label for="fixedLeftColumnsCount">
397
  {{ environment.translate('Left Columns Count') }}
398
  {{ tooltip.icon(environment.translate('Number of column to fix by left side of the table.')) }}
399
  </label>
400
  </div>
401
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
402
  <input name="fixedLeftColumnsCount" id="fixedLeftColumnsCount" type="text" value="{{ table.settings.fixedLeftColumnsCount | default(1) }}">
403
  </div>
404
  </div>
405
- <div class="setting-wrapper row fixed-columns-options"
406
  {% if table.settings.fixedColumns is not defined %}
407
  style="display:none"
408
  {% endif %}
409
  >
410
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
411
  <label for="fixedRightColumnsCount">
412
  {{ environment.translate('Right Columns Count') }}
413
  {{ tooltip.icon(environment.translate('Number of column to fix by right side of the table.')) }}
414
  </label>
415
  </div>
416
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
417
  <input name="fixedRightColumnsCount" id="fixedRightColumnsCount" type="text" value="{{ table.settings.fixedRightColumnsCount | default(0) }}">
418
  </div>
419
  </div>
420
- <div class="setting-wrapper row">
421
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
422
  <label for="autoIndex">
423
  {{ environment.translate('Auto Index') }}
424
  {{ tooltip.icon('Add index (row number) to table.', 'top', true) }}
425
  </label>
426
  </div>
427
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
428
  <select name="autoIndex" id="autoIndex">
429
  {% for value, title in {'off': 'No index', 'first': 'Use first column', 'new':'Create new column'} %}
430
  <option value="{{ value }}"
@@ -437,68 +413,66 @@
437
  </select>
438
  </div>
439
  </div>
440
- </div>
441
- <div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
442
- <div class="title-place">
443
  <h3>{{ environment.translate('Options') }}</h3>
444
  </div>
445
- <div class="setting-wrapper row">
446
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
447
  <label for="disable-table-cache">
448
  {{ environment.translate('Disable Table Cache') }}
449
  {{ tooltip.icon(environment.translate("This feature is necessary for those cases, when table contains the shortcodes. By checking the box, you can make sure that they will be rendered correctly and won't be influenced by cache.")) }}
450
  </label>
451
  </div>
452
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
453
- <input type="checkbox" name="disableCache" id="disable-table-cache" {{ checkbox.checked(table.settings.disableCache) }} />
454
  </div>
455
  </div>
456
- <div class="title-place">
457
  <h3>{{ environment.translate('Data Formats') }}</h3>
458
  </div>
459
- <div class="setting-wrapper row">
460
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
461
  <label for="editor-use-comma-as-delimiter">
462
  {{ environment.translate('Use Comma as Delimiter') }}
463
  {{ tooltip.icon(environment.translate('Use comma as delimiter of integer and fractional parts of number for editable fields on frontend')) }}
464
  </label>
465
  </div>
466
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
467
  <input type="checkbox" name="useCommaAsDelimiter"
468
  {{ checkbox.checked(table.settings.useCommaAsDelimiter) }}
469
  id="editor-use-comma-as-delimiter" />
470
  </div>
471
  </div>
472
- <div class="setting-wrapper row">
473
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
474
  <label for="editor-use-number-format">
475
  {{ environment.translate('Number Formatting') }}
476
  {{ tooltip.icon(environment.translate('Set format of all numbers in the table')) }}
477
  </label>
478
  </div>
479
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
480
  <input type="checkbox" name="useNumberFormat"
481
  {{ checkbox.checked(table.settings.useNumberFormat) }}
482
  id="editor-use-number-format" />
483
  </div>
484
  </div>
485
- <div class="setting-wrapper row use-number-format-options"
486
  {% if table.settings.useNumberFormat is not defined %}
487
  style="display:none"
488
  {% endif %}
489
  >
490
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
491
  <label for="editor-set-number-format">
492
  {{ environment.translate('Number') }}
493
  {{ tooltip.icon(environment.translate('Set output format for numbers e.g. 1,000.00, 1.00')) }}
494
  </label>
495
  </div>
496
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
497
  <input name="numberFormat" id="editor-set-number-format" type="text" value="{{ table.settings.numberFormat | default('1,000.00') }}">
498
  </div>
499
  </div>
500
- <div class="setting-wrapper row">
501
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
502
  <label for="editor-set-currency-format">
503
  {{ environment.translate('Currency') }}
504
  {{ tooltip.icon(environment.translate('Set output format for currencies. Supports only 1 currency for 1 table. Besides here you can establish needed divider between integer and fractional parts and quantity of zeros at fractional part. For example:<br />
@@ -506,12 +480,12 @@
506
  € 1.00')) }}
507
  </label>
508
  </div>
509
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
510
- <input name="currencyFormat" id="editor-set-currency-format" type="text" value="{{ table.settings.currencyFormat | default('$1,000.00') }}">
511
  </div>
512
  </div>
513
- <div class="setting-wrapper row">
514
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
515
  <label for="editor-set-percent-format">
516
  {{ environment.translate('Percent') }}
517
  {{ tooltip.icon(environment.translate('Set output format for percent numbers. For example:<br />
@@ -519,12 +493,12 @@
519
  10%')) }}
520
  </label>
521
  </div>
522
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
523
- <input name="percentFormat" id="editor-set-percent-format" type="text" value="{{ table.settings.percentFormat | default('10.00%') }}">
524
  </div>
525
  </div>
526
- <div class="setting-wrapper row">
527
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
528
  <label for="editor-set-date-format">
529
  {{ environment.translate('Date') }}
530
  {{ tooltip.icon(environment.translate('Set output format for date. For example:<br />
@@ -532,12 +506,12 @@
532
  DD.MM.YY - 25.12.91')) }}
533
  </label>
534
  </div>
535
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
536
- <input name="dateFormat" id="editor-set-date-format" type="text" value="{{ table.settings.dateFormat | default('DD.MM.YYYY') }}">
537
  </div>
538
  </div>
539
- <div class="setting-wrapper row">
540
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
541
  <label for="editor-set-time-duration-format">
542
  {{ environment.translate('Time / Duration') }}
543
  {{ tooltip.icon(environment.translate('Set output format for time and duration. For example:<br />
@@ -549,34 +523,31 @@
549
  hh:mm:ss - 36:40:12')) }}
550
  </label>
551
  </div>
552
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
553
- <input name="timeDurationFormat" id="editor-set-time-duration-format" type="text" value="{{ table.settings.timeDurationFormat | default('HH:mm') }}">
554
  </div>
555
  </div>
556
- </div>
557
- <!-- /.form-table -->
558
  </section>
559
- <section class="row row-settings-tab" id="stb-anl-features">
560
- <div class="title-block col-xs-12">
561
- <h3>{{ environment.translate('Features') }}</h3>
562
  </div>
563
- <div class="col-md-6 col-sm-6 col-xs-12">
564
- <div class="title-place">
565
  <h3>{{ environment.translate('General') }}</h3>
566
  </div>
567
- <div class="setting-wrapper row">
568
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
569
  <label for="features-responsive-mode">
570
  {{ environment.translate('Responsive Mode') }}
571
  {{ tooltip.icon(
572
  environment.translate('Standard Responsive mode - in this mode if table content doesn\'t fit all columns become under each other with one cell per row') ~ '<br>' ~ '<br>' ~
573
  environment.translate('Automatic column hiding - in this mode table columns will collapse from right to left if content does not fit to parent container width') ~ '<br>' ~ '<br>' ~
574
- environment.translate('Horizontal scroll - in this mode scroll bar will be added if table overflows parent container width') ~ '<br>' ~
575
- environment.translate('Disable Responsivity - default table fluid layout') ~ '<br>'
576
  ) }}
577
  </label>
578
  </div>
579
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
580
  <select name="responsiveMode" id="features-responsive-mode">
581
  {% for value, name in {
582
  '0': environment.translate('Standard Responsive mode'),
@@ -595,44 +566,43 @@
595
  </select>
596
  </div>
597
  </div>
598
- <div class="setting-wrapper row">
599
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
600
  <label for="features-info">
601
  {{ environment.translate('Table Information') }}
602
  {{ tooltip.icon(environment.translate('Table information display field. %s') | format('<img src="http://supsystic.com/_assets/tables/tooltip/info.jpg"/>') | raw, 'top', true) }}
603
  </label>
604
  </div>
605
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
606
  <input type="checkbox" name="features[info]" {{ checkbox.checked(table.settings.features.info) }} id="features-info"/>
607
  </div>
608
  </div>
609
- <div class="setting-wrapper row">
610
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
611
  <label for="features-ordering">
612
  {{ environment.translate('Sorting') }}
613
- {{ tooltip.icon('<p style="width:227px; padding:5px margin:0">To allow dynamic sorting with arrows you must enable Header option.</p><img src="http://supsystic.com/_assets/tables/tooltip/Ordrering.jpg"/>', 'top', true) }}
614
  </label>
615
  </div>
616
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
617
  <input type="checkbox" name="features[ordering]"
618
  {{ checkbox.checked(table.settings.features.ordering) }}
619
  id="features-ordering"
620
  data-target-toggle=".sorting-options"/>
621
- <!-- /#features-ordering -->
622
  </div>
623
  </div>
624
- <div class="setting-wrapper row sorting-options"
625
  {% if table.settings.features.ordering is not defined %}
626
  style="display:none"
627
  {% endif %}
628
  >
629
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
630
  <label for="features-sorting-order">
631
  {{ environment.translate('Sorting Order') }}
632
  {{ tooltip.icon(environment.translate('Set sort order by default')) }}
633
  </label>
634
  </div>
635
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
636
  <select name="sortingOrder" id="features-sorting-order">
637
  <option value="asc">{{ environment.translate('Ascending') }}</option>
638
  <option value="desc"
@@ -643,65 +613,64 @@
643
  </select>
644
  </div>
645
  </div>
646
- <div class="setting-wrapper row sorting-options"
647
  {% if table.settings.features.ordering is not defined %}
648
  style="display:none"
649
  {% endif %}
650
  >
651
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
652
  <label for="sorting-order-column">
653
  {{ environment.translate('Sorting Column') }}
654
  {{ tooltip.icon(environment.translate('Number of column to apply sort order. Set no value to disable table sorting by default.')) }}
655
  </label>
656
  </div>
657
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
658
  <input name="sortingOrderColumn" id="sorting-order-column" type="text" value="{{ table.settings.sortingOrderColumn | default(1) }}">
659
  </div>
660
  </div>
661
- <div class="setting-wrapper row">
662
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
663
  <label for="features-pagination">
664
  {{ environment.translate('Pagination') }}
665
  {{ tooltip.icon('<img src="http://supsystic.com/_assets/tables/tooltip/Pagination.jpg"/>', 'top', true) }}
666
  </label>
667
  </div>
668
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
669
  <input data-toggle="collapse" type="checkbox" name="features[paging]"
670
  {{ checkbox.checked(table.settings.features.paging) }}
671
  id="features-pagination"
672
  data-target-toggle=".pagination-options"/>
673
- <!-- /#features-pagination -->
674
  </div>
675
  </div>
676
- <div class="setting-wrapper row pagination-options"
677
  {% if table.settings.features.paging is not defined %}
678
  style="display:none"
679
  {% endif %}
680
  >
681
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
682
  <label for="pagination-length">
683
  {{ environment.translate('Pagination List Content') }}
684
  {{ tooltip.icon('Here you can set the number of rows to display on one Pagination page. Establish several numbers separated by comma to let users choose it personally. First number will be displayed by default. Since that the number of Pagination Pages will be recounted also.', 'top', true) }}
685
  </label>
686
  </div>
687
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
688
  <input type="text"
689
  name="paginationMenuLength"
690
  value="{{ table.settings.paginationMenuLength | default('50,100,All') }}"
691
  id="pagination-length" />
692
  </div>
693
  </div>
694
- <div class="setting-wrapper row pagination-options"
695
  {% if table.settings.features.paging is not defined %}
696
  style="display:none"
697
  {% endif %}
698
  >
699
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
700
  <label for="pagination-size">
701
  {{ environment.translate('Pagination Size') }}
702
  </label>
703
  </div>
704
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
705
  <select name="paginationSize" id="pagination-size" >
706
  {% for value, name in {
707
  'pagination-large': environment.translate('Large'),
@@ -719,68 +688,85 @@
719
  </select>
720
  </div>
721
  </div>
722
- <div class="setting-wrapper row pagination-options"
723
  {% if table.settings.features.paging is not defined %}
724
  style="display:none"
725
  {% endif %}
726
  >
727
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
728
  <label for="pagination-server-processing">
729
  {{ environment.translate('Server-side Processing') }}
730
  {{ tooltip.icon(environment.translate('This option is recommended for a large tables that cannot be processed in conventional way. The table will be sequentially loaded by ajax on a per page basis, all filtering, ordering and search clauses is server-side implemented too.')) }}
731
  </label>
732
  </div>
733
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
734
- <input type="checkbox" name="serverSideProcessing" id="server-side-processing"
735
  {{ checkbox.checked(table.settings.serverSideProcessing) }}
736
  >
737
  </div>
738
  </div>
739
- <div class="setting-wrapper row">
740
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
741
  <label for="features-searching">
742
  {{ environment.translate('Searching') }}
743
  {{ tooltip.icon('<img src="http://supsystic.com/_assets/tables/tooltip/Searching.jpg"/>', 'top', true) }}
744
  </label>
745
  </div>
746
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
747
  <input type="checkbox" name="features[searching]"
748
  {{ checkbox.checked(table.settings.features.searching) }}
749
  id="features-searching"
750
  data-target-toggle=".searching-options"/>
751
  </div>
752
  </div>
753
- <div class="setting-wrapper row searching-options"
754
  {% if table.settings.features.searching is not defined %}
755
  style="display:none"
756
  {% endif %}
757
  >
758
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
759
  <label for="features-search-by-column">
760
  {{ environment.translate('Search by Columns') }}
761
  {{ tooltip.icon(environment.translate('Add search by table columns. Use a semicolon as separator for select any of the values.')) }}
762
  </label>
763
  </div>
764
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
765
  <input type="checkbox" name="searching[columnSearch]" id="features-search-by-column"
766
  {{ checkbox.checked(table.settings.searching.columnSearch) }}
767
  >
768
  </div>
769
  </div>
770
- <div class="setting-wrapper row searching-options"
771
  {% if table.settings.features.searching is not defined
772
  or (table.settings.features.searching is defined and table.settings.searching.columnSearch is not defined)
773
  %}
774
  style="display:none"
775
  {% endif %}
776
  >
777
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
778
  <label for="features-search-by-column-position">
779
  {{ environment.translate('Location of Search Fields') }}
780
  {{ tooltip.icon(environment.translate('Here you can choose where the column search fields will be: at the top or bottom of the table.')) }}
781
  </label>
782
  </div>
783
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
784
  <select name="searching[columnSearchPosition]" id="features-search-by-column-position" >
785
  {% for value, name in {
786
  'bottom': environment.translate('Bottom'),
@@ -797,185 +783,183 @@
797
  </select>
798
  </div>
799
  </div>
800
- <div class="setting-wrapper row searching-options"
801
  {% if table.settings.features.searching is not defined %}
802
  style="display:none"
803
  {% endif %}
804
  >
805
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
806
  <label for="features-search-by-hidden-fields">
807
  {{ environment.translate('Search by Hidden Fields') }}
808
  {{ tooltip.icon(environment.translate('Lets make search by fields, marked as hidden (see appropriate button on editor toolbar)')) }}
809
  </label>
810
  </div>
811
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
812
  <input type="checkbox" name="searching[searchByHiddenField]" id="features-search-by-hidden-fields"
813
  {{ checkbox.checked(table.settings.searching.searchByHiddenField) }}
814
  >
815
  </div>
816
  </div>
817
- <div class="setting-wrapper row searching-options"
818
  {% if table.settings.features.searching is not defined %}
819
  style="display:none"
820
  {% endif %}
821
  >
822
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
823
  <label for="features-searching-result-only">
824
  {{ environment.translate('Show Only Search Results') }}
825
  {{ tooltip.icon(environment.translate('Hide table by default and show only if search has a result.')) }}
826
  </label>
827
  </div>
828
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
829
  <input type="checkbox" name="searching[resultOnly]" id="features-searching-result-only"
830
  {{ checkbox.checked(table.settings.searching.resultOnly) }}
831
  >
832
  </div>
833
  </div>
834
- <div class="setting-wrapper row searching-options"
835
  {% if table.settings.features.searching is not defined
836
  or (table.settings.features.searching is defined and table.settings.searching.resultOnly is not defined)
837
  %}
838
  style="display:none"
839
  {% endif %}
840
  >
841
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
842
-
843
  <label for="features-searching-show-table">
844
  {{ environment.translate('Show Empty Table') }}
845
  {{ tooltip.icon(environment.translate('Table will not be hidden by default , but will be empty.')) }}
846
  </label>
847
  </div>
848
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
849
  <input type="checkbox" name="searching[showTable]" id="features-searching-show-table"
850
  {{ checkbox.checked(table.settings.searching.showTable) }}
851
  >
852
  </div>
853
  </div>
854
- <div class="setting-wrapper row searching-options"
855
  {% if table.settings.features.searching is not defined %}
856
  style="display:none"
857
  {% endif %}
858
  >
859
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
860
  <label for="features-searching-strict-matching">
861
  {{ environment.translate('Strict Matching') }}
862
  {{ tooltip.icon(environment.translate('Display only entries with matching characters in the beginning of words')) }}
863
  </label>
864
  </div>
865
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
866
  <input type="checkbox" name="searching[strictMatching]" id="features-searching-strict-matching"
867
  {{ checkbox.checked(table.settings.searching.strictMatching) }}
868
  >
869
  </div>
870
  </div>
871
- <div class="setting-wrapper row searching-options"
872
  {% if table.settings.features.searching is not defined %}
873
  style="display:none"
874
  {% endif %}
875
  >
876
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
877
  <label for="features-searching-strict-min-chars">
878
  {{ environment.translate('Minimum Count of Characters') }}
879
  {{ tooltip.icon(environment.translate('Set minimum count of characters to start search in Search field. Set 0 to make search in any case.')) }}
880
  </label>
881
  </div>
882
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
883
  <input type="text" name="searching[minChars]" id="features-searching-strict-min-chars"
884
  value="{{ table.settings.searching.minChars|default('0') }}" />
885
  </div>
886
  </div>
887
- <div class="setting-wrapper row">
888
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
889
  <label for="features-disallow-indexing">
890
  {{ environment.translate('Disallow Indexing') }}
891
  {{ tooltip.icon(environment.translate('Disable indexing table for search bots')) }}
892
  </label>
893
  </div>
894
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
895
  <input type="checkbox" name="disallowIndexing" id="features-disallow-indexing"
896
  {{ checkbox.checked(table.settings.disallowIndexing) }} />
897
  </div>
898
  </div>
899
- <div class="setting-wrapper row">
900
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
901
  <label for="enable-after-table-loaded-script">
902
  {{ environment.translate('Execute JS Script After Table Load') }}
903
  {{ tooltip.icon(environment.translate('Allows to execute custom javascript code after table is loaded.')) }}
904
  </label>
905
  </div>
906
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
907
  <input type="checkbox" name="features[enable_after_table_loaded_script]"
908
  id="enable-after-table-loaded-script"
909
  data-target-toggle=".after-table-loaded-script-options"
910
  {{ checkbox.checked(table.settings.features.enable_after_table_loaded_script) }} />
911
  </div>
912
  </div>
913
- <div class="setting-wrapper row after-table-loaded-script-options"
914
  {% if table.settings.features.enable_after_table_loaded_script is not defined %}
915
  style="display:none"
916
  {% endif %}
917
  >
918
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
919
  <label for="after-table-loaded-script-text">
920
  {{ environment.translate('JS Script Text') }}
921
  </label>
922
  </div>
923
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
924
- <textarea id="after-table-loaded-script-text" placeholder="{{ environment.translate('Paste script code here')}}" style="margin-top: 10px;">{{ table.settings.features.after_table_loaded_script | default('') }}</textarea>
925
  <input type="hidden" name="features[after_table_loaded_script]" value="{{ table.settings.features.after_table_loaded_script | default('') }}" />
926
  </div>
927
  </div>
928
- </div>
929
- <div class="col-md-6 col-sm-6 col-xs-12">
930
- <div class="title-place">
931
  <h3>{{ environment.translate('Frontend Fields') }}</h3>
932
  </div>
933
  {% if environment.isPro() == false %}
934
- <div class="setting-wrapper row">
935
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
936
  <label for="save-editable-fields-unavailable">
937
  {{ environment.translate('Save Frontend Fields') }}
938
  {{ tooltip.icon(environment.translate('Save table data entered through frontend fields. Refer to the first two buttons on the second row of the editor toolbar:<br />Add editable field<br />Add dropdown list')) }}
939
  <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'editable_fields_feature' }) }}">{{ environment.translate('PRO option') }}</a>
940
  </label>
941
  </div>
942
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
943
  <input type="checkbox" disabled="disabled" id="save-editable-fields-unavailable"/>
944
  </div>
945
  </div>
946
- <div class="setting-wrapper row">
947
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
948
  <label for="mark-last-edited-cell-unavailable">
949
  {{ environment.translate('Mark Last Edited Cell') }}
950
  {{ tooltip.icon(environment.translate('Adds a symbol ✓ to last edited cell.')) }}
951
  <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'mark_last_edited_cell' }) }}">{{ environment.translate('PRO option') }}</a>
952
  </label>
953
  </div>
954
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
955
  <input type="checkbox" disabled="disabled" id="mark-last-edited-cell-unavailable"/>
956
  </div>
957
  </div>
958
- <div class="setting-wrapper row">
959
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
960
  <label for="editable-fields-logged-in-unavailable">
961
  {{ environment.translate('Use for Logged In Users Only') }}
962
  {{ 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/')) }}
963
  <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'editable_fields_for_logged_in_only' }) }}">{{ environment.translate('PRO option') }}</a>
964
  </label>
965
  </div>
966
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
967
  <input type="checkbox" disabled="disabled" id="editable-fields-logged-in-unavailable"/>
968
  </div>
969
  </div>
970
- <div class="setting-wrapper row editable-fields-logged-in-options">
971
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
972
  <label for="editable-fields-roles-unavailable">
973
  {{ environment.translate('Use for Current Roles Only') }}
974
  {{ 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.')) }}
975
  <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'editable_fields_for_current_roles' }) }}">{{ environment.translate('PRO option') }}</a>
976
  </label>
977
  </div>
978
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
979
  <select name="useEditableFieldsForCurRoles[]" disabled="disabled" id="editable-fields-roles-unavailable" data-placeholder="{{ environment.translate('Select roles')}}">
980
  <option>{{ environment.translate('Select roles')}}</option>
981
  </select>
@@ -983,100 +967,96 @@
983
  </div>
984
  {% endif %}
985
  {% if environment.isPro() == false %}
986
- <div class="title-place">
987
  <h3>{{ environment.translate('Export / Import') }}</h3>
988
  </div>
989
- <div class="setting-wrapper row">
990
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
991
  <label for="features-export-unavailable">
992
  {{ environment.translate('Frontend Export') }}
993
  {{ tooltip.icon(environment.translate('Allows to export table in pdf, csv, xls formats from the front-end. Choose needed formats')) }}
994
  <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'export_feature' }) }}">{{ environment.translate('PRO option') }}</a>
995
  </label>
996
  </div>
997
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
998
  <select name="features[export][]" disabled="disabled" id="features-export-unavailable" data-placeholder="{{ environment.translate('Select Some Options')}}">
999
  <option>{{ environment.translate('Select Some Options')}}</option>
1000
  </select>
1001
  </div>
1002
  </div>
1003
- <div class="setting-wrapper row">
1004
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1005
  <label for="features-export-pdf-paper-size-unavailable">
1006
  {{ environment.translate('PDF Paper Size') }}
1007
  {{ tooltip.icon(environment.translate('Choose the paper size for PDF pages')) }}
1008
  </label>
1009
  <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'export_feature_pdf_paper_size' }) }}">{{ environment.translate('PRO option') }}</a>
1010
  </div>
1011
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1012
  <select name="pdfPaperSize" disabled="disabled" id="features-export-pdf-paper-size-unavailable" data-placeholder="{{ environment.translate('Automatic')}}">
1013
  <option>{{ environment.translate('Automatic')}}</option>
1014
  </select>
1015
  </div>
1016
  </div>
1017
- <div class="setting-wrapper row">
1018
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1019
  <label for="features-export-pdf-orientation-unavailable">
1020
  {{ environment.translate('PDF Page Orientation') }}
1021
  {{ tooltip.icon(environment.translate('Choose the orientation for PDF pages')) }}
1022
  </label>
1023
  <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'export_feature_pdf_orientation' }) }}">{{ environment.translate('PRO option') }}</a>
1024
  </div>
1025
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1026
  <select name="pdfOrientation" disabled="disabled" id="features-export-pdf-orientation-unavailable" data-placeholder="{{ environment.translate('Portrait')}}">
1027
  <option>{{ environment.translate('Portrait')}}</option>
1028
  </select>
1029
  </div>
1030
  </div>
1031
- <div class="setting-wrapper row">
1032
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1033
  <label for="features-export-pdf-export-fonts-unavailable">
1034
  {{ environment.translate('Export Fonts to PDF') }}
1035
  {{ tooltip.icon(environment.translate('Allows export to PDF file the fonts, which were set for table content via editor toolbar. Important! Custom fonts might not contain some specific characters (greek, cyrillic etc.), so after importing of fonts your PDF file might lost part of content.')) }}
1036
  </label>
1037
  <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'export_feature_pdf_export_fonts' }) }}">{{ environment.translate('PRO option') }}</a>
1038
  </div>
1039
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1040
  <input type="checkbox" name="pdfExportFonts" disabled="disabled" id="features-export-pdf-export-fonts-unavailable" />
1041
  </div>
1042
  </div>
1043
- <div class="setting-wrapper row">
1044
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1045
  <label for="features-export-select-logo-unavailable">
1046
  {{ environment.translate('Export Logo') }}
1047
  {{ tooltip.icon(environment.translate('Automticaly appends selected logo for output pdf or printing')) }}
1048
  </label>
1049
  <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'export_feature_select_logo' }) }}">{{ environment.translate('PRO option') }}</a>
1050
  </div>
1051
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1052
  <button class="button" disabled="disabled" id="features-export-select-logo-unavailable">{{ environment.translate('Select Logo') }}</button>
1053
  </div>
1054
  </div>
1055
- <div class="setting-wrapper row">
1056
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1057
  <label for="google-tables-automatically-update-unavailable">
1058
  {{ environment.translate('Autoimport from Google Sheet') }}
1059
  {{ 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/')) }}
1060
  </label>
1061
  <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'google_tables_automatically_update' }) }}">{{ environment.translate('PRO option') }}</a>
1062
  </div>
1063
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1064
- <input type="checkbox" disabled="disabled" name="features[google_tables_automatically_update]" id="google-tables-automatically-update-unavailable" />
1065
  </div>
1066
  </div>
1067
  {% endif %}
1068
  {{ environment.getDispatcher().dispatch('tables-view-features', [table]) }}
1069
- <!-- /.form-table -->
1070
- </div>
1071
  </section>
1072
- <section class="row row-settings-tab" id="stb-anl-appearance">
1073
- <div class="title-block col-xs-12">
1074
- <h3>{{ environment.translate('Appearance') }}</h3>
1075
  </div>
1076
- <div class="col-md-6 col-sm-6 col-xs-12">
1077
- <div class="title-place">&nbsp;</div>
1078
- <div class="setting-wrapper row">
1079
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1080
  <label for="features-auto-width">
1081
  {{ environment.translate('Auto Table Width') }}
1082
  {{ tooltip.icon(environment.translate('If checked - width of table columns will be calculated automatically for table width 100%.<br /><br />
@@ -1086,7 +1066,7 @@
1086
  option to "auto" and check "Compact Table" option.')) }}
1087
  </label>
1088
  </div>
1089
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1090
  <input type="checkbox" name="features[auto_width]"
1091
  {{ checkbox.checked(table.settings.features.auto_width) }}
1092
  id="features-auto-width"
@@ -1094,131 +1074,137 @@
1094
  <!-- /#features-auto-width -->
1095
  </div>
1096
  </div>
1097
- <div class="setting-wrapper row auto-width-options"
1098
  {% if table.settings.features.auto_width is defined %}
1099
  style="display:none"
1100
  {% endif %}
1101
  >
1102
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
1103
  <label for="fixed-table-width">
1104
  {{ environment.translate('Fixed Table Width') }}
1105
  {{ tooltip.icon(environment.translate('Set fixed table width in px or %. Choose &quot;disable&quot; to make table width adjust by table content.')) }}
1106
  </label>
1107
  </div>
1108
- <div class="setting-item sub-options col-md-6 col-sm-6 col-xs-12">
1109
- <input type="text" name="tableWidth" value="{{ table.settings.tableWidth | default('100') }}" id="fixed-table-width"
1110
- {% if table.settings.tableWidthType == 'auto' %}
1111
- style="display:none"
1112
- {% endif %}/>
1113
- {% set tableWidthTypeDefault = '%' %}
1114
- <label for="fixed-table-width-type-percent" class="sub-label">
1115
- <input type="radio" name="tableWidthType" id="fixed-table-width-type-percent" value="%" {{ checkbox.radio_checked(table.settings.tableWidthType|default(tableWidthTypeDefault), '%') }} />
1116
- <span>%</span>
1117
- </label>
1118
- <label for="fixed-table-width-type-pixels" class="sub-label">
1119
- <input type="radio" name="tableWidthType" id="fixed-table-width-type-pixels" value="px" {{ checkbox.radio_checked(table.settings.tableWidthType|default(tableWidthTypeDefault), 'px') }} />
1120
- <span>px</span>
1121
- </label>
1122
- <label for="fixed-table-width-type-auto" class="sub-label">
1123
- <input type="radio" name="tableWidthType" id="fixed-table-width-type-auto" value="auto" {{ checkbox.radio_checked(table.settings.tableWidthType|default(tableWidthTypeDefault), 'auto') }} />
1124
- <span>{{ environment.translate('disable') }}</span>
1125
- </label>
1126
- </div>
 
 
 
 
1127
  </div>
1128
- <div class="setting-wrapper row auto-width-options"
1129
  {% if table.settings.features.auto_width is defined %}
1130
  style="display:none"
1131
  {% endif %}
1132
  >
1133
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
1134
  <label for="fixed-table-width-mobile">
1135
  {{ environment.translate('Fixed Table Width (mobile)') }}
1136
  {{ tooltip.icon(environment.translate('Set fixed table width in px or %. Choose &quot;disable&quot; to make table width adjust by table content.')) }}
1137
  </label>
1138
  </div>
1139
- <div class="setting-item sub-options col-md-6 col-sm-6 col-xs-12">
1140
- <input type="text" name="tableWidthMobile" value="{{ table.settings.tableWidthMobile | default('100') }}" id="fixed-table-width-mobile"
1141
- {% if table.settings.tableWidthMobileType == 'auto' %}
1142
- style="display:none"
1143
- {% endif %}/>
1144
- {% set tableWidthMobileTypeDefault = '%' %}
1145
- <label for="fixed-table-width-mobile-type-percent" class="sub-label">
1146
- <input type="radio" name="tableWidthMobileType" id="fixed-table-width-mobile-type-percent" value="%" {{ checkbox.radio_checked(table.settings.tableWidthMobileType|default(tableWidthMobileTypeDefault), '%') }} />
1147
- <span>%</span>
1148
- </label>
1149
- <label for="fixed-table-width-mobile-type-pixels" class="sub-label">
1150
- <input type="radio" name="tableWidthMobileType" id="fixed-table-width-mobile-type-pixels" value="px" {{ checkbox.radio_checked(table.settings.tableWidthMobileType|default(tableWidthMobileTypeDefault), 'px') }} />
1151
- <span>px</span>
1152
- </label>
1153
- <label for="fixed-table-width-mobile-type-auto" class="sub-label">
1154
- <input type="radio" name="tableWidthMobileType" id="fixed-table-width-mobile-type-auto" value="auto" {{ checkbox.radio_checked(table.settings.tableWidthMobileType|default(tableWidthMobileTypeDefault), 'auto') }} />
1155
- <span>{{ environment.translate('disable') }}</span>
1156
- </label>
1157
- </div>
1158
- </div>
1159
- <div class="setting-wrapper row">
1160
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1161
- <label for="styling-compact">
1162
- {{ environment.translate('Compact Table') }}
1163
- {{ tooltip.icon(environment.translate('Decrease the amount of whitespace in the table.')) }}
1164
- </label>
1165
- </div>
1166
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1167
- <input type="checkbox"
1168
- name="styling[compact]"
1169
- {{ checkbox.checked(attribute(table.settings.styling, 'compact')) }}
1170
- id="styling-compact"/>
1171
- <!-- /#styling-compact -->
1172
- </div>
1173
  </div>
1174
- <div class="setting-wrapper row auto-width-options"
1175
  {% if table.settings.features.auto_width is defined %}
1176
  style="display:none"
1177
  {% endif %}
1178
  >
1179
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
1180
  <label for="table-alignment-on-page">
1181
  {{ environment.translate('Align by First Table') }}
1182
  {{ tooltip.icon(environment.translate('If checked - this table will be resized by first supsystic table on page. Important! This option makes sense only if table is not on responsive mode or responsive mode is disabled. Also if the first table has different count of columns or different settings, their sizes may not be equal.')) }}
1183
  </label>
1184
  </div>
1185
- <div class="setting-item sub-options col-md-6 col-sm-6 col-xs-12">
1186
  <input type="checkbox" name="alignByFirstTable"
1187
  {{ checkbox.checked(table.settings.alignByFirstTable) }}
1188
  id="table-alignment-on-page"/>
1189
  </div>
1190
  </div>
1191
- <div class="setting-wrapper row">
1192
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1193
  <label for="styling-nowrap">
1194
  {{ environment.translate('Disable Wrapping') }}
1195
  {{ tooltip.icon(environment.translate('Disable wrapping of content in the table, so every word in the cells will be in one single line.')) }}
1196
  </label>
1197
  </div>
1198
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1199
  <input type="checkbox"
1200
  name="styling[nowrap]"
1201
  {{ checkbox.checked(attribute(table.settings.styling, 'nowrap')) }}
1202
  id="styling-nowrap"/>
1203
- <!-- /#styling-nowrap -->
1204
  </div>
1205
  </div>
1206
- <div class="setting-wrapper row">
1207
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1208
  <label for="paragraphMode">
1209
  {{ environment.translate('Paragraph Mode') }}
1210
  {{ tooltip.icon(environment.translate('This mode allows you to separate the content into paragraphs. To move to a new line in the cell - please press CTRL + Enter.')) }}
1211
  </label>
1212
  </div>
1213
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1214
  <input type="checkbox"
1215
  name="styling[paragraphMode]"
1216
  {{ checkbox.checked(attribute(table.settings.styling, 'paragraphMode')) }}
1217
  id="paragraphMode"/>
1218
  </div>
1219
  </div>
1220
- <div class="setting-wrapper row">
1221
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1222
  <label for="lightboxImg">
1223
  {{ environment.translate('Lightbox') }}
1224
  {{ tooltip.icon(environment.translate('Add Lightbox fo images . <a href="https://supsystic.com/documentation/lightbox-with-full-size-images/">https://supsystic.com/documentation/lightbox-with-full-size-images/</a>')) }}
@@ -1227,7 +1213,7 @@
1227
  {% endif %}
1228
  </label>
1229
  </div>
1230
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1231
  {% if environment.isPro() == false %}
1232
  <input type="checkbox" disabled="disabled" id="save-editable-fields-unavailable"/>
1233
  {% else %}
@@ -1238,31 +1224,28 @@
1238
  {% endif %}
1239
  </div>
1240
  </div>
1241
- <div class="setting-wrapper row">
1242
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1243
  <label for="lightboxImg">
1244
  {{ environment.translate('Merge cells align') }}
1245
  {{ tooltip.icon(environment.translate('Align columns which have include merge cells to left (in responcive mode)')) }}
1246
  </label>
1247
  </div>
1248
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1249
  <input type="checkbox"
1250
  name="styling[ColWithMergeCellsAlign]"
1251
  {{ checkbox.checked(attribute(table.settings.styling, 'ColWithMergeCellsAlign')) }}
1252
  id="ColWithMergeCellsAlign"/>
1253
  </div>
1254
  </div>
1255
- </div>
1256
- <div class="col-md-6 col-sm-6 col-xs-12">
1257
- <div class="title-place">&nbsp;</div>
1258
- <div class="setting-wrapper row">
1259
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1260
  <label for="styling-border">
1261
  {{ environment.translate('Borders') }}
1262
  {{ tooltip.icon(environment.translate('Cell - adds border around all four sides of each cell, Row - adds border only over and under each row. (i.e. only for the rows).')) }}
1263
  </label>
1264
  </div>
1265
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1266
  <select name="styling[border]"
1267
  id="styling-border">
1268
  {% for option in [
@@ -1273,75 +1256,70 @@
1273
  <option value="{{ option.value }}" {% if table.settings.styling.border == option.value %}selected="selected"{% endif %}>{{ option.name }}</option>
1274
  {% endfor %}
1275
  </select>
1276
- <!-- /#styling-border -->
1277
  </div>
1278
  </div>
1279
- <div class="setting-wrapper row">
1280
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1281
  <label for="styling-stripe">
1282
  {{ environment.translate('Row Striping') }}
1283
  {{ tooltip.icon(environment.translate('Add automatic highlight for table odd rows')) }}
1284
  </label>
1285
  </div>
1286
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1287
  <input type="checkbox"
1288
  name="styling[stripe]"
1289
  {{ checkbox.checked(attribute(table.settings.styling, 'stripe')) }}
1290
  id="styling-stripe"/>
1291
- <!-- /#styling-stripe -->
1292
  </div>
1293
  </div>
1294
- <div class="setting-wrapper row">
1295
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1296
  <label for="styling-hover">
1297
  {{ environment.translate('Highlighting by Mousehover') }}
1298
  {{ tooltip.icon(environment.translate('Row highlighting by mouse hover.')) }}
1299
  </label>
1300
  </div>
1301
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1302
  <input type="checkbox" name="styling[hover]"
1303
  {{ checkbox.checked(attribute(table.settings.styling, 'hover')) }}
1304
  id="styling-hover"/>
1305
- <!-- /#styling-hover -->
1306
  </div>
1307
  </div>
1308
- <div class="setting-wrapper row">
1309
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1310
  <label for="styling-order-column">
1311
  {{ environment.translate('Highlight the Order Column') }}
1312
  {{ tooltip.icon(environment.translate('If checked - the current sorted column will be highlighted')) }}
1313
  </label>
1314
  </div>
1315
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1316
  <input type="checkbox"
1317
  name="styling[order-column]"
1318
  {{ checkbox.checked(attribute(table.settings.styling, 'order-column')) }}
1319
  id="styling-order-column"/>
1320
- <!-- /#styling-order-column -->
1321
  </div>
1322
  </div>
1323
- <div class="setting-wrapper row">
1324
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1325
  <label for="hide-table-loader">
1326
  {{ environment.translate('Hide Table Loader') }}
1327
  {{ tooltip.icon(environment.translate('Enable / disable table loader icon before table will be completely loaded.')) }}
1328
  </label>
1329
  </div>
1330
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1331
  <input type="checkbox"
1332
  name="tableLoader[disable]"
1333
  {{ checkbox.checked(table.settings.tableLoader.disable) }}
1334
  id="hide-table-loader"
1335
  data-target-toggle=".hide-table-loader-options" />
1336
- <!-- /#styling-order-column -->
1337
  </div>
1338
  </div>
1339
- <div class="setting-wrapper row hide-table-loader-options"
1340
  {% if table.settings.tableLoader.disable is defined %}
1341
  style="display:none"
1342
  {% endif %}
1343
  >
1344
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
1345
  <label for="table-loaedr-icon">
1346
  {{ environment.translate('Table Loader Icon') }}
1347
  {{ tooltip.icon(environment.translate('Choose icon for loader')) }}
@@ -1350,7 +1328,7 @@
1350
  {% set tblLoaderIconItems = table.settings.tableLoader.iconItems | default('0') %}
1351
  {% set tblLoaderColor = table.settings.tableLoader.color | default('#000000') %}
1352
  </div>
1353
- <div class="setting-item sub-options col-md-6 col-sm-6 col-xs-12">
1354
  <button class="button selectTableLoaderIcon" id="table-loaedr-icon">{{ environment.translate('Choose Icon') }}</button>
1355
  <input type="hidden" name="tableLoader[iconName]" value="{{ tblLoaderIconName }}" />
1356
  <input type="hidden" name="tableLoader[iconItems]" value="{{ tblLoaderIconItems }}" />
@@ -1368,33 +1346,399 @@
1368
  </div>
1369
  </div>
1370
  </div>
1371
- <div class="setting-wrapper row hide-table-loader-options"
1372
  {% if table.settings.tableLoader.disable is defined %}
1373
  style="display:none"
1374
  {% endif %}
1375
  >
1376
- <div class="setting-item setting-options col-md-6 col-sm-6 col-xs-12">
1377
  <label for="tableLoaderColorContainer">
1378
  {{ environment.translate('Table Loader Color') }}
1379
  {{ tooltip.icon(environment.translate('Choose color for loader')) }}
1380
  </label>
1381
  </div>
1382
- <div class="setting-item sub-options col-md-6 col-sm-6 col-xs-12">
1383
  <div id="tableLoaderColorContainer" class="colorPickerShell">
1384
  <div class="tableLoaderColorArea colorPickerArea" style="background-color: {{ tblLoaderColor }};"></div>
1385
  <input type="hidden" name="tableLoader[color]" value="{{ tblLoaderColor }}" />
1386
  </div>
1387
  </div>
1388
  </div>
1389
- </div>
1390
- <!-- /.col-md-4 col-sm-6 col-xs-12 -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1391
  </section>
1392
- <section class="row row-settings-tab" id="stb-anl-language">
1393
- <div class="title-block col-xs-12">
1394
- <h3>{{ environment.translate('Language and Text') }}</h3>
1395
  </div>
1396
- <div class="col-md-6 col-sm-6 col-xs-12">
1397
- <div class="title-place">
1398
  <h3>{{ environment.translate('Overwrite Table Text') }}</h3>
1399
  </div>
1400
  {% set language_override = {
@@ -1436,8 +1780,8 @@
1436
  },
1437
  } %}
1438
  {% for key, data in language_override %}
1439
- <div class="setting-wrapper row">
1440
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1441
  <label for="language-{{ key }}">
1442
  {{ data.label }}
1443
  {% if data.info is not empty %}
@@ -1445,24 +1789,22 @@
1445
  {% endif %}
1446
  </label>
1447
  </div>
1448
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1449
  <input id="language-{{ key }}" type="text" name="language[{{ key }}]" value="{{ attribute(table.settings.language, key) }}" placeholder="{{ data.default }}">
1450
  </div>
1451
  </div>
1452
  {% endfor %}
1453
- </div>
1454
- <div class="col-md-6 col-sm-6 col-xs-12">
1455
- <div class="title-place">
1456
  <h3>{{ environment.translate('Language') }}</h3>
1457
  </div>
1458
- <div class="setting-wrapper row">
1459
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1460
  <label for="language-file">
1461
  {{ environment.translate('Table Language') }}
1462
  {{ tooltip.icon(environment.translate('Allows to choose language for the table\'s labels (pagination, search ets.). The dafault language is English.')) }}
1463
  </label>
1464
  </div>
1465
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1466
  <select name="language[file]" id="language-file">
1467
  {% for supportedLanguage in translations %}
1468
  <option value="{{ supportedLanguage }}" {% if table.settings.language.file == supportedLanguage %}selected="selected"{% endif %}>
@@ -1476,40 +1818,28 @@
1476
  </select>
1477
  </div>
1478
  </div>
1479
- </div>
1480
- </section>
1481
- <section class="row row-settings-tab" id="stb-anl-source">
1482
- <div class="title-block col-xs-12">
1483
- <h3>{{ environment.translate('Source') }}</h3>
1484
- </div>
1485
- {% if environment.isPro() == false %}
1486
- <div class="col-md-6 col-sm-6 col-xs-12">
1487
- <div class="title-place">
1488
- <h3>{{ environment.translate('Database') }}</h3>
1489
- </div>
1490
- <div class="setting-wrapper row">
1491
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1492
- <label for="table-source-database-unavailable">
1493
- {% set urlTables = environment.getModule('tables').getLocationUrl() %}
1494
- {{ environment.translate('Data from Database') }}
1495
- {{ tooltip.icon('Database Source Pro feature allows you display table and its fields data from any table of WP database or External databases on the front-end. <a target="_blank" href="https://supsystic.com/documentation/database-source/"></br>Read more</a>' | raw, 'top', true)}}
1496
- </label>
1497
- <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'table-source-database' }) }}">{{ environment.translate('PRO option') }}</a></br>
1498
- </div>
1499
- <div class="setting-item col-md-6 col-sm-6 col-xs-12">
1500
- <input type="checkbox" disabled="disabled" name="source[database]" id="table-source-database-unavailable" />
1501
- </div>
1502
- <div class="setting-item col-md-12 col-sm-12 col-xs-12">
1503
- <a target="_blank" href="{{build_pro_url({ 'utm_medium': notify })}}"><img style="max-width:800px" src="{{ environment.getModule('tables').getLocationUrl() }}/assets/img/database.gif"/></a>
1504
- </div>
1505
- </div>
1506
- </div>
1507
- {% endif %}
1508
- {{ environment.getDispatcher().dispatch('tables-view-source', [table]) }}
1509
  </section>
1510
  </section>
1511
  </form>
1512
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1513
  </div>
1514
 
1515
  <div class="row row-tab" id="row-tab-editor">
@@ -1829,15 +2159,6 @@
1829
  ></div>
1830
  <!-- /#tableEditor -->
1831
  </div>
1832
-
1833
- <div class="row row-tab" id="row-tab-preview">
1834
- <p class="description">
1835
- <i class="fa fa-fw fa-exclamation-circle"></i>
1836
- {{ environment.translate('Note that the table may look a little different depending on your theme style.') }}
1837
- </p>
1838
- <div id="table-preview"></div>
1839
- </div>
1840
-
1841
  <div class="row row-tab" id="row-tab-css">
1842
 
1843
 
116
  </span>
117
  </li>
118
  <li>
119
+ <a href="#row-tab-settings" class="button">
 
 
 
 
 
 
 
 
120
  <i class="fa fa-fw fa-wrench"></i>
121
  {{ environment.translate('Settings') }}
122
  </a>
123
  </li>
124
  <li>
125
+ <a href="#row-tab-editor" class="current button">
126
  <i class="fa fa-fw fa-th"></i>
127
  {{ environment.translate('Editor') }}
128
  </a>
129
  </li>
 
 
 
 
 
 
130
  <li>
131
  <a href="#row-tab-css" class="button">
132
  <i class="fa fa-fw fa-code"></i>
140
  </div>
141
 
142
  <div class="row row-tab" id="row-tab-settings">
143
+ <section class="settings-section">
144
  <div class="stb-wraper-anchor-nav-links">
145
  <a href="#stb-anl-main" class="stb-anchor-nav-links">{{ translate('Main')}}</a>
146
  <a href="#stb-anl-features" class="stb-anchor-nav-links">{{ translate('Features')}}</a>
147
  <a href="#stb-anl-appearance" class="stb-anchor-nav-links">{{ translate('Appearance')}}</a>
148
+ <a href="#stb-anl-text" class="stb-anchor-nav-links">{{ translate('Text')}}</a>
 
149
  </div>
150
  <div class="settings-wrap">
151
  <form id="settings">
152
+ <section class="settings-blocks">
153
+ <section class="row-settings-block" id="stb-anl-main">
154
+ <div class="settings-block-title">
155
+ <h3><i class="fa fa-fw fa-tachometer"></i> {{ environment.translate('Main Settings') }}</h3>
156
+ </div>
157
+ <div class="setting-title">
 
158
  <h3>{{ environment.translate('Table Elements') }}</h3>
159
  </div>
160
+ <div class="setting-wrapper">
161
+ <div class="setting-label">
162
  <label for="table-elements-caption">
163
  {{ environment.translate('Caption') }}
164
  {{ tooltip.icon('Check here if you want to show the name of the table above the table', 'top', true) }}
165
  </label>
166
  </div>
167
+ <div class="setting-check">
168
  <input type="checkbox" name="elements[caption]"
169
  {{ checkbox.checked(table.settings.elements.caption) }}
170
  id="table-elements-caption"/>
 
171
  </div>
172
  </div>
173
+ <div class="setting-wrapper">
174
+ <div class="setting-label">
175
  <label for="table-elements-description">
176
  {{ environment.translate('Description') }}
177
  {{ tooltip.icon('You can add short description to the table between title and table', 'top', true) }}
178
  </label>
179
  </div>
180
+ <div class="setting-check">
181
  <input type="checkbox" name="elements[description]"
182
  {{ checkbox.checked(table.settings.elements.description) }}
183
+ data-preview-not-redraw="1" id="table-elements-description"
184
  data-target-toggle=".table-elements-description-options"/>
185
  <!-- /#table-elements-caption -->
186
  </div>
187
  </div>
188
+ <div class="setting-wrapper table-elements-description-options setting-suboption"
189
  {% if table.settings.elements.description is not defined %}
190
  style="display:none"
191
  {% endif %}
192
  >
193
+ <div class="setting-label">
194
  <label for="descriptionText">
195
  {{ environment.translate('Description Text') }}
196
  </label>
197
  </div>
198
+ <div class="setting-input">
199
  <textarea id="descriptionText">{{ table.settings.elements.descriptionText | default('') }}</textarea>
200
  <input type="hidden" name="elements[descriptionText]" value="{{ table.settings.elements.descriptionText | default('') }}" />
 
201
  </div>
202
  </div>
203
+ <div class="setting-wrapper">
204
+ <div class="setting-label">
205
  <label for="table-elements-signature">
206
  {{ environment.translate('Signature') }}
207
  {{ tooltip.icon('You can add signature under table footer', 'top', true) }}
208
  </label>
209
  </div>
210
+ <div class="setting-check">
211
  <input type="checkbox" name="elements[signature]"
212
  {{ checkbox.checked(table.settings.elements.signature) }}
213
+ data-preview-not-redraw="1" id="table-elements-signature"
214
  data-target-toggle=".table-elements-signature-options"/>
 
215
  </div>
216
  </div>
217
+ <div class="setting-wrapper table-elements-signature-options setting-suboption"
218
  {% if table.settings.elements.signature is not defined %}
219
  style="display:none"
220
  {% endif %}
221
  >
222
+ <div class="setting-label">
223
  <label for="signatureText">
224
  {{ environment.translate('Signature Text') }}
225
  </label>
226
  </div>
227
+ <div class="setting-input">
228
  <textarea id="signatureText">{{ table.settings.elements.signatureText | default('') }}</textarea>
229
  <input type="hidden" name="elements[signatureText]" value="{{ table.settings.elements.signatureText | default('') }}" />
 
230
  </div>
231
  </div>
232
+ <div class="setting-wrapper">
233
+ <div class="setting-label">
234
  <label for="table-elements-head">
235
  {{ environment.translate('Header') }}
236
  {{ tooltip.icon('<img src="http://supsystic.com/_assets/tables/tooltip/Header.jpg"/>', 'top', true) }}
237
  </label>
238
  </div>
239
+ <div class="setting-check">
240
  <input type="checkbox" name="elements[head]"
241
  {{ checkbox.checked(table.settings.elements.head) }}
242
  id="table-elements-head"
243
  data-target-toggle=".table-elements-head-options"/>
 
244
  </div>
245
  </div>
246
+ <div class="setting-wrapper table-elements-head-options setting-suboption"
247
  {% if table.settings.elements.head is not defined %}
248
  style="display:none"
249
  {% endif %}
250
  >
251
+ <div class="setting-label">
252
  <label for="headerRowsCount">
253
  {{ environment.translate('Count of Header Rows') }}
254
  {{ tooltip.icon(environment.translate('Count of table rows, which will be moved to header.')) }}
255
  </label>
256
  </div>
257
+ <div class="setting-input">
258
  <input name="headerRowsCount" id="headerRowsCount" type="text" value="{{ table.settings.headerRowsCount | default(1) }}">
259
  </div>
260
  </div>
261
+ <div class="setting-wrapper">
262
+ <div class="setting-label">
263
  <label for="table-elements-foot">
264
  {{ environment.translate('Footer') }}
265
  {{ tooltip.icon('<img src="http://supsystic.com/_assets/tables/tooltip/footer.jpg"/>', 'top', true) }}
266
  </label>
267
  </div>
268
+ <div class="setting-check">
269
  <input type="checkbox" name="elements[foot]"
270
  {{ checkbox.checked(table.settings.elements.foot) }}
271
  id="table-elements-foot"
272
  data-target-toggle=".table-elements-foot-options"/>
 
273
  </div>
274
  </div>
275
+ <div class="setting-wrapper table-elements-foot-options setting-suboption"
276
  {% if table.settings.elements.foot is not defined %}
277
  style="display:none"
278
  {% endif %}
279
  >
280
+ <div class="setting-label">
281
  <label for="customFooter">
282
  {{ environment.translate('Custom Footer') }}
283
  {{ tooltip.icon(environment.translate('If checked - footer will be created from the last table rows. Otherwise - footer will be created from header rows.')) }}
284
  </label>
285
  </div>
286
+ <div class="setting-check">
287
  <input type="checkbox" name="customFooter"
288
  {{ checkbox.checked(table.settings.customFooter) }}
289
  id="customFooter"
290
  data-target-toggle=".custom-footer-options"/>
291
  </div>
292
  </div>
293
+ <div class="setting-wrapper custom-footer-options setting-suboption"
294
  {% if table.settings.elements.foot is not defined or table.settings.customFooter is not defined %}
295
  style="display:none"
296
  {% endif %}
297
  >
298
+ <div class="setting-label">
299
  <label for="footerRowsCount">
300
  {{ environment.translate('Count of Footer Rows') }}
301
  {{ tooltip.icon(environment.translate('Count of table rows, which will be moved to footer.')) }}
302
  </label>
303
  </div>
304
+ <div class="setting-input">
305
  <input name="footerRowsCount" id="footerRowsCount" type="text" value="{{ table.settings.footerRowsCount | default(1) }}">
306
  </div>
307
  </div>
308
+ <div class="setting-wrapper">
309
+ <div class="setting-label">
310
  <label for="features-fixed-header">
311
  {{ environment.translate('Fixed Header') }}
312
  {{ tooltip.icon(environment.translate('Allows to fix the table\'s header during table scrolling. Important! Header option must be enabled for using this feature. Also you need to set Fixed Table Height to create a vertical scroll for your table. To see the work of this feature you should not use such Responsive Modes such as Standard and Automatic columns hiding.')) }}
313
  </label>
314
  </div>
315
+ <div class="setting-check">
316
  <input type="checkbox" name="fixedHeader"
317
  {{ checkbox.checked(table.settings.fixedHeader) }}
318
  id="features-fixed-header"
319
  class="features-fixed-header-footer"/>
 
320
  </div>
321
  </div>
322
+ <div class="setting-wrapper">
323
+ <div class="setting-label">
324
  <label for="features-fixed-footer">
325
  {{ environment.translate('Fixed Footer') }}
326
  {{ tooltip.icon(environment.translate('Allows to fix the table\'s footer during table scrolling. Important! Footer option must be enabled for using this feature. Also you need to set Fixed Table Height to create a vertical scroll at the table. To see the work of this feature you should not use such Responsive Modes as Standard and Automatic columns hiding.')) }}
327
  </label>
328
  </div>
329
+ <div class="setting-check">
330
  <input type="checkbox" name="fixedFooter"
331
  {{ checkbox.checked(table.settings.fixedFooter) }}
332
  id="features-fixed-footer"
334
  <!-- /#features-fixed-footer -->
335
  </div>
336
  </div>
337
+ <div class="setting-wrapper features-fixed-height setting-suboption"
338
  {% if table.settings.fixedHeader is not defined and table.settings.fixedFooter is not defined %}
339
  style="display:none"
340
  {% endif %}
341
  >
342
+ <div class="setting-label">
343
  <label for="fixedHeight">
344
  {{ environment.translate('Fixed Table Height') }}
345
  {{ tooltip.icon(environment.translate('Fixed table height in px. This value must be less than the original table height to create a vertical scroll, otherwise you will not see that the fixed header / footer exists.')) }}
346
  </label>
347
  </div>
348
+ <div class="setting-input">
349
  <input name="fixedHeight" id="fixedHeight" type="text" value="{{ table.settings.fixedHeight | default(400) }}">
350
  </div>
351
  </div>
352
+ <div class="setting-wrapper">
353
+ <div class="setting-label">
354
  <label for="features-fixed-columns">
355
  {{ environment.translate('Fixed Columns') }}
356
  {{ tooltip.icon(environment.translate('Allows to fix columns during table scrolling. Important! The fixing of columns suggests that the table will have a horisontal scroll type of responsive mode, otherwise you will not see that the fixed columns exist. So this feature is a kind of responsive mode on its own and will not work with such Responsive Modes as Standard and Automatic columns hiding.')) }}
357
  </label>
358
  </div>
359
+ <div class="setting-check">
360
  <input type="checkbox" name="fixedColumns"
361
  {{ checkbox.checked(table.settings.fixedColumns) }}
362
  id="features-fixed-columns"
363
  data-target-toggle=".fixed-columns-options"/>
 
364
  </div>
365
  </div>
366
+ <div class="setting-wrapper fixed-columns-options setting-options"
367
  {% if table.settings.fixedColumns is not defined %}
368
  style="display:none"
369
  {% endif %}
370
  >
371
+ <div class="setting-label">
372
  <label for="fixedLeftColumnsCount">
373
  {{ environment.translate('Left Columns Count') }}
374
  {{ tooltip.icon(environment.translate('Number of column to fix by left side of the table.')) }}
375
  </label>
376
  </div>
377
+ <div class="setting-input">
378
  <input name="fixedLeftColumnsCount" id="fixedLeftColumnsCount" type="text" value="{{ table.settings.fixedLeftColumnsCount | default(1) }}">
379
  </div>
380
  </div>
381
+ <div class="setting-wrapper fixed-columns-options setting-options"
382
  {% if table.settings.fixedColumns is not defined %}
383
  style="display:none"
384
  {% endif %}
385
  >
386
+ <div class="setting-label">
387
  <label for="fixedRightColumnsCount">
388
  {{ environment.translate('Right Columns Count') }}
389
  {{ tooltip.icon(environment.translate('Number of column to fix by right side of the table.')) }}
390
  </label>
391
  </div>
392
+ <div class="setting-input">
393
  <input name="fixedRightColumnsCount" id="fixedRightColumnsCount" type="text" value="{{ table.settings.fixedRightColumnsCount | default(0) }}">
394
  </div>
395
  </div>
396
+ <div class="setting-wrapper setting-wrapper-inline">
397
+ <div class="setting-label">
398
  <label for="autoIndex">
399
  {{ environment.translate('Auto Index') }}
400
  {{ tooltip.icon('Add index (row number) to table.', 'top', true) }}
401
  </label>
402
  </div>
403
+ <div class="setting-input">
404
  <select name="autoIndex" id="autoIndex">
405
  {% for value, title in {'off': 'No index', 'first': 'Use first column', 'new':'Create new column'} %}
406
  <option value="{{ value }}"
413
  </select>
414
  </div>
415
  </div>
416
+ <div class="setting-title">
 
 
417
  <h3>{{ environment.translate('Options') }}</h3>
418
  </div>
419
+ <div class="setting-wrapper">
420
+ <div class="setting-label">
421
  <label for="disable-table-cache">
422
  {{ environment.translate('Disable Table Cache') }}
423
  {{ tooltip.icon(environment.translate("This feature is necessary for those cases, when table contains the shortcodes. By checking the box, you can make sure that they will be rendered correctly and won't be influenced by cache.")) }}
424
  </label>
425
  </div>
426
+ <div class="setting-check">
427
+ <input type="checkbox" name="disableCache" id="disable-table-cache" data-preview-not-redraw="1" {{ checkbox.checked(table.settings.disableCache) }} />
428
  </div>
429
  </div>
430
+ <div class="setting-title">
431
  <h3>{{ environment.translate('Data Formats') }}</h3>
432
  </div>
433
+ <div class="setting-wrapper">
434
+ <div class="setting-label">
435
  <label for="editor-use-comma-as-delimiter">
436
  {{ environment.translate('Use Comma as Delimiter') }}
437
  {{ tooltip.icon(environment.translate('Use comma as delimiter of integer and fractional parts of number for editable fields on frontend')) }}
438
  </label>
439
  </div>
440
+ <div class="setting-check">
441
  <input type="checkbox" name="useCommaAsDelimiter"
442
  {{ checkbox.checked(table.settings.useCommaAsDelimiter) }}
443
  id="editor-use-comma-as-delimiter" />
444
  </div>
445
  </div>
446
+ <div class="setting-wrapper">
447
+ <div class="setting-label">
448
  <label for="editor-use-number-format">
449
  {{ environment.translate('Number Formatting') }}
450
  {{ tooltip.icon(environment.translate('Set format of all numbers in the table')) }}
451
  </label>
452
  </div>
453
+ <div class="setting-check">
454
  <input type="checkbox" name="useNumberFormat"
455
  {{ checkbox.checked(table.settings.useNumberFormat) }}
456
  id="editor-use-number-format" />
457
  </div>
458
  </div>
459
+ <div class="setting-wrapper use-number-format-options setting-suboption"
460
  {% if table.settings.useNumberFormat is not defined %}
461
  style="display:none"
462
  {% endif %}
463
  >
464
+ <div class="setting-label">
465
  <label for="editor-set-number-format">
466
  {{ environment.translate('Number') }}
467
  {{ tooltip.icon(environment.translate('Set output format for numbers e.g. 1,000.00, 1.00')) }}
468
  </label>
469
  </div>
470
+ <div class="setting-input">
471
  <input name="numberFormat" id="editor-set-number-format" type="text" value="{{ table.settings.numberFormat | default('1,000.00') }}">
472
  </div>
473
  </div>
474
+ <div class="setting-wrapper setting-wrapper-inline">
475
+ <div class="setting-label">
476
  <label for="editor-set-currency-format">
477
  {{ environment.translate('Currency') }}
478
  {{ tooltip.icon(environment.translate('Set output format for currencies. Supports only 1 currency for 1 table. Besides here you can establish needed divider between integer and fractional parts and quantity of zeros at fractional part. For example:<br />
480
  € 1.00')) }}
481
  </label>
482
  </div>
483
+ <div class="setting-input">
484
+ <input name="currencyFormat" id="editor-set-currency-format" type="text" data-need-data-save='1' value="{{ table.settings.currencyFormat | default('$1,000.00') }}">
485
  </div>
486
  </div>
487
+ <div class="setting-wrapper setting-wrapper-inline">
488
+ <div class="setting-label">
489
  <label for="editor-set-percent-format">
490
  {{ environment.translate('Percent') }}
491
  {{ tooltip.icon(environment.translate('Set output format for percent numbers. For example:<br />
493
  10%')) }}
494
  </label>
495
  </div>
496
+ <div class="setting-input">
497
+ <input name="percentFormat" id="editor-set-percent-format" type="text" data-need-data-save='1' value="{{ table.settings.percentFormat | default('10.00%') }}">
498
  </div>
499
  </div>
500
+ <div class="setting-wrapper setting-wrapper-inline">
501
+ <div class="setting-label">
502
  <label for="editor-set-date-format">
503
  {{ environment.translate('Date') }}
504
  {{ tooltip.icon(environment.translate('Set output format for date. For example:<br />
506
  DD.MM.YY - 25.12.91')) }}
507
  </label>
508
  </div>
509
+ <div class="setting-input">
510
+ <input name="dateFormat" id="editor-set-date-format" type="text" data-need-data-save='1' value="{{ table.settings.dateFormat | default('DD.MM.YYYY') }}">
511
  </div>
512
  </div>
513
+ <div class="setting-wrapper setting-wrapper-inline">
514
+ <div class="setting-label">
515
  <label for="editor-set-time-duration-format">
516
  {{ environment.translate('Time / Duration') }}
517
  {{ tooltip.icon(environment.translate('Set output format for time and duration. For example:<br />
523
  hh:mm:ss - 36:40:12')) }}
524
  </label>
525
  </div>
526
+ <div class="setting-input">
527
+ <input name="timeDurationFormat" id="editor-set-time-duration-format" type="text" data-need-data-save='1' value="{{ table.settings.timeDurationFormat | default('HH:mm') }}">
528
  </div>
529
  </div>
 
 
530
  </section>
531
+ <section class="row-settings-block" id="stb-anl-features">
532
+ <div class="settings-block-title">
533
+ <h3><i class="fa fa-fw fa-cogs"></i> {{ environment.translate('Features') }}</h3>
534
  </div>
535
+ <div class="setting-title">
 
536
  <h3>{{ environment.translate('General') }}</h3>
537
  </div>
538
+ <div class="setting-wrapper setting-wrapper-inline">
539
+ <div class="setting-label">
540
  <label for="features-responsive-mode">
541
  {{ environment.translate('Responsive Mode') }}
542
  {{ tooltip.icon(
543
  environment.translate('Standard Responsive mode - in this mode if table content doesn\'t fit all columns become under each other with one cell per row') ~ '<br>' ~ '<br>' ~
544
  environment.translate('Automatic column hiding - in this mode table columns will collapse from right to left if content does not fit to parent container width') ~ '<br>' ~ '<br>' ~
545
+ environment.translate('Horizontal scroll - in this mode scroll bar will be added if table overflows parent container width') ~ '<br>' ~ '<br>' ~
546
+ environment.translate('Disable Responsivity - default table fluid layout <a href="https://supsystic.com/example/data-table-responsive-modes/" target="_blank">Read more.</a>') ~ '<br>'
547
  ) }}
548
  </label>
549
  </div>
550
+ <div class="setting-input">
551
  <select name="responsiveMode" id="features-responsive-mode">
552
  {% for value, name in {
553
  '0': environment.translate('Standard Responsive mode'),
566
  </select>
567
  </div>
568
  </div>
569
+ <div class="setting-wrapper">
570
+ <div class="setting-label">
571
  <label for="features-info">
572
  {{ environment.translate('Table Information') }}
573
  {{ tooltip.icon(environment.translate('Table information display field. %s') | format('<img src="http://supsystic.com/_assets/tables/tooltip/info.jpg"/>') | raw, 'top', true) }}
574
  </label>
575
  </div>
576
+ <div class="setting-check">
577
  <input type="checkbox" name="features[info]" {{ checkbox.checked(table.settings.features.info) }} id="features-info"/>
578
  </div>
579
  </div>
580
+ <div class="setting-wrapper">
581
+ <div class="setting-label">
582
  <label for="features-ordering">
583
  {{ environment.translate('Sorting') }}
584
+ {{ tooltip.icon('<p style="width:227px; padding:5px margin:0">To allow dynamic sorting with arrows you must enable Header option.</p><p style="width:227px; padding:5px margin:0;color:red">Note that if there are merged cells in the table sorting will be disabled.</p><img src="http://supsystic.com/_assets/tables/tooltip/Ordrering.jpg"/>', 'top', true) }}
585
  </label>
586
  </div>
587
+ <div class="setting-check">
588
  <input type="checkbox" name="features[ordering]"
589
  {{ checkbox.checked(table.settings.features.ordering) }}
590
  id="features-ordering"
591
  data-target-toggle=".sorting-options"/>
 
592
  </div>
593
  </div>
594
+ <div class="setting-wrapper sorting-options setting-suboption"
595
  {% if table.settings.features.ordering is not defined %}
596
  style="display:none"
597
  {% endif %}
598
  >
599
+ <div class="setting-label">
600
  <label for="features-sorting-order">
601
  {{ environment.translate('Sorting Order') }}
602
  {{ tooltip.icon(environment.translate('Set sort order by default')) }}
603
  </label>
604
  </div>
605
+ <div class="setting-input">
606
  <select name="sortingOrder" id="features-sorting-order">
607
  <option value="asc">{{ environment.translate('Ascending') }}</option>
608
  <option value="desc"
613
  </select>
614
  </div>
615
  </div>
616
+ <div class="setting-wrapper sorting-options setting-suboption"
617
  {% if table.settings.features.ordering is not defined %}
618
  style="display:none"
619
  {% endif %}
620
  >
621
+ <div class="setting-label">
622
  <label for="sorting-order-column">
623
  {{ environment.translate('Sorting Column') }}
624
  {{ tooltip.icon(environment.translate('Number of column to apply sort order. Set no value to disable table sorting by default.')) }}
625
  </label>
626
  </div>
627
+ <div class="setting-input">
628
  <input name="sortingOrderColumn" id="sorting-order-column" type="text" value="{{ table.settings.sortingOrderColumn | default(1) }}">
629
  </div>
630
  </div>
631
+ <div class="setting-wrapper">
632
+ <div class="setting-label">
633
  <label for="features-pagination">
634
  {{ environment.translate('Pagination') }}
635
  {{ tooltip.icon('<img src="http://supsystic.com/_assets/tables/tooltip/Pagination.jpg"/>', 'top', true) }}
636
  </label>
637
  </div>
638
+ <div class="setting-check">
639
  <input data-toggle="collapse" type="checkbox" name="features[paging]"
640
  {{ checkbox.checked(table.settings.features.paging) }}
641
  id="features-pagination"
642
  data-target-toggle=".pagination-options"/>
 
643
  </div>
644
  </div>
645
+ <div class="setting-wrapper pagination-options setting-suboption"
646
  {% if table.settings.features.paging is not defined %}
647
  style="display:none"
648
  {% endif %}
649
  >
650
+ <div class="setting-label">
651
  <label for="pagination-length">
652
  {{ environment.translate('Pagination List Content') }}
653
  {{ tooltip.icon('Here you can set the number of rows to display on one Pagination page. Establish several numbers separated by comma to let users choose it personally. First number will be displayed by default. Since that the number of Pagination Pages will be recounted also.', 'top', true) }}
654
  </label>
655
  </div>
656
+ <div class="setting-input">
657
  <input type="text"
658
  name="paginationMenuLength"
659
  value="{{ table.settings.paginationMenuLength | default('50,100,All') }}"
660
  id="pagination-length" />
661
  </div>
662
  </div>
663
+ <div class="setting-wrapper pagination-options setting-suboption"
664
  {% if table.settings.features.paging is not defined %}
665
  style="display:none"
666
  {% endif %}
667
  >
668
+ <div class="setting-label">
669
  <label for="pagination-size">
670
  {{ environment.translate('Pagination Size') }}
671
  </label>
672
  </div>
673
+ <div class="setting-input">
674
  <select name="paginationSize" id="pagination-size" >
675
  {% for value, name in {
676
  'pagination-large': environment.translate('Large'),
688
  </select>
689
  </div>
690
  </div>
691
+ <div class="setting-wrapper pagination-options setting-suboption"
692
  {% if table.settings.features.paging is not defined %}
693
  style="display:none"
694
  {% endif %}
695
  >
696
+ <div class="setting-label">
697
+ <label for="scroll-top-by-pagination">
698
+ {{ environment.translate('Scroll top by pagination') }}
699
+ {{ tooltip.icon(environment.translate('Scroll to table top for pagination change.')) }}
700
+ </label>
701
+ </div>
702
+ <div class="setting-check">
703
+ <input type="checkbox" name="scrollTopByPagination" id="scroll-top-by-pagination"
704
+ {{ checkbox.checked(table.settings.scrollTopByPagination) }}
705
+ >
706
+ </div>
707
+ </div>
708
+ <div class="setting-wrapper pagination-options setting-suboption"
709
+ {% if table.settings.features.paging is not defined %}
710
+ style="display:none"
711
+ {% endif %}
712
+ >
713
+ <div class="setting-label">
714
  <label for="pagination-server-processing">
715
  {{ environment.translate('Server-side Processing') }}
716
  {{ tooltip.icon(environment.translate('This option is recommended for a large tables that cannot be processed in conventional way. The table will be sequentially loaded by ajax on a per page basis, all filtering, ordering and search clauses is server-side implemented too.')) }}
717
  </label>
718
  </div>
719
+ <div class="setting-check">
720
+ <input type="checkbox" name="serverSideProcessing" id="server-side-processing" data-need-settings-save='1'
721
  {{ checkbox.checked(table.settings.serverSideProcessing) }}
722
  >
723
  </div>
724
  </div>
725
+ <div class="setting-wrapper">
726
+ <div class="setting-label">
727
  <label for="features-searching">
728
  {{ environment.translate('Searching') }}
729
  {{ tooltip.icon('<img src="http://supsystic.com/_assets/tables/tooltip/Searching.jpg"/>', 'top', true) }}
730
  </label>
731
  </div>
732
+ <div class="setting-check">
733
  <input type="checkbox" name="features[searching]"
734
  {{ checkbox.checked(table.settings.features.searching) }}
735
  id="features-searching"
736
  data-target-toggle=".searching-options"/>
737
  </div>
738
  </div>
739
+ <div class="setting-wrapper searching-options setting-suboption"
740
  {% if table.settings.features.searching is not defined %}
741
  style="display:none"
742
  {% endif %}
743
  >
744
+ <div class="setting-label">
745
  <label for="features-search-by-column">
746
  {{ environment.translate('Search by Columns') }}
747
  {{ tooltip.icon(environment.translate('Add search by table columns. Use a semicolon as separator for select any of the values.')) }}
748
  </label>
749
  </div>
750
+ <div class="setting-check">
751
  <input type="checkbox" name="searching[columnSearch]" id="features-search-by-column"
752
  {{ checkbox.checked(table.settings.searching.columnSearch) }}
753
  >
754
  </div>
755
  </div>
756
+ <div class="setting-wrapper searching-options setting-suboption"
757
  {% if table.settings.features.searching is not defined
758
  or (table.settings.features.searching is defined and table.settings.searching.columnSearch is not defined)
759
  %}
760
  style="display:none"
761
  {% endif %}
762
  >
763
+ <div class="setting-label">
764
  <label for="features-search-by-column-position">
765
  {{ environment.translate('Location of Search Fields') }}
766
  {{ tooltip.icon(environment.translate('Here you can choose where the column search fields will be: at the top or bottom of the table.')) }}
767
  </label>
768
  </div>
769
+ <div class="setting-input">
770
  <select name="searching[columnSearchPosition]" id="features-search-by-column-position" >
771
  {% for value, name in {
772
  'bottom': environment.translate('Bottom'),
783
  </select>
784
  </div>
785
  </div>
786
+ <div class="setting-wrapper searching-options setting-suboption"
787
  {% if table.settings.features.searching is not defined %}
788
  style="display:none"
789
  {% endif %}
790
  >
791
+ <div class="setting-label">
792
  <label for="features-search-by-hidden-fields">
793
  {{ environment.translate('Search by Hidden Fields') }}
794
  {{ tooltip.icon(environment.translate('Lets make search by fields, marked as hidden (see appropriate button on editor toolbar)')) }}
795
  </label>
796
  </div>
797
+ <div class="setting-check">
798
  <input type="checkbox" name="searching[searchByHiddenField]" id="features-search-by-hidden-fields"
799
  {{ checkbox.checked(table.settings.searching.searchByHiddenField) }}
800
  >
801
  </div>
802
  </div>
803
+ <div class="setting-wrapper searching-options setting-suboption"
804
  {% if table.settings.features.searching is not defined %}
805
  style="display:none"
806
  {% endif %}
807
  >
808
+ <div class="setting-label">
809
  <label for="features-searching-result-only">
810
  {{ environment.translate('Show Only Search Results') }}
811
  {{ tooltip.icon(environment.translate('Hide table by default and show only if search has a result.')) }}
812
  </label>
813
  </div>
814
+ <div class="setting-check">
815
  <input type="checkbox" name="searching[resultOnly]" id="features-searching-result-only"
816
  {{ checkbox.checked(table.settings.searching.resultOnly) }}
817
  >
818
  </div>
819
  </div>
820
+ <div class="setting-wrapper searching-options setting-suboption"
821
  {% if table.settings.features.searching is not defined
822
  or (table.settings.features.searching is defined and table.settings.searching.resultOnly is not defined)
823
  %}
824
  style="display:none"
825
  {% endif %}
826
  >
827
+ <div class="setting-label">
 
828
  <label for="features-searching-show-table">
829
  {{ environment.translate('Show Empty Table') }}
830
  {{ tooltip.icon(environment.translate('Table will not be hidden by default , but will be empty.')) }}
831
  </label>
832
  </div>
833
+ <div class="setting-check">
834
  <input type="checkbox" name="searching[showTable]" id="features-searching-show-table"
835
  {{ checkbox.checked(table.settings.searching.showTable) }}
836
  >
837
  </div>
838
  </div>
839
+ <div class="setting-wrapper searching-options setting-suboption"
840
  {% if table.settings.features.searching is not defined %}
841
  style="display:none"
842
  {% endif %}
843
  >
844
+ <div class="setting-label">
845
  <label for="features-searching-strict-matching">
846
  {{ environment.translate('Strict Matching') }}
847
  {{ tooltip.icon(environment.translate('Display only entries with matching characters in the beginning of words')) }}
848
  </label>
849
  </div>
850
+ <div class="setting-check">
851
  <input type="checkbox" name="searching[strictMatching]" id="features-searching-strict-matching"
852
  {{ checkbox.checked(table.settings.searching.strictMatching) }}
853
  >
854
  </div>
855
  </div>
856
+ <div class="setting-wrapper searching-options setting-suboption"
857
  {% if table.settings.features.searching is not defined %}
858
  style="display:none"
859
  {% endif %}
860
  >
861
+ <div class="setting-label">
862
  <label for="features-searching-strict-min-chars">
863
  {{ environment.translate('Minimum Count of Characters') }}
864
  {{ tooltip.icon(environment.translate('Set minimum count of characters to start search in Search field. Set 0 to make search in any case.')) }}
865
  </label>
866
  </div>
867
+ <div class="setting-input">
868
  <input type="text" name="searching[minChars]" id="features-searching-strict-min-chars"
869
  value="{{ table.settings.searching.minChars|default('0') }}" />
870
  </div>
871
  </div>
872
+ <div class="setting-wrapper">
873
+ <div class="setting-label">
874
  <label for="features-disallow-indexing">
875
  {{ environment.translate('Disallow Indexing') }}
876
  {{ tooltip.icon(environment.translate('Disable indexing table for search bots')) }}
877
  </label>
878
  </div>
879
+ <div class="setting-check">
880
  <input type="checkbox" name="disallowIndexing" id="features-disallow-indexing"
881
  {{ checkbox.checked(table.settings.disallowIndexing) }} />
882
  </div>
883
  </div>
884
+ <div class="setting-wrapper">
885
+ <div class="setting-label">
886
  <label for="enable-after-table-loaded-script">
887
  {{ environment.translate('Execute JS Script After Table Load') }}
888
  {{ tooltip.icon(environment.translate('Allows to execute custom javascript code after table is loaded.')) }}
889
  </label>
890
  </div>
891
+ <div class="setting-check">
892
  <input type="checkbox" name="features[enable_after_table_loaded_script]"
893
  id="enable-after-table-loaded-script"
894
  data-target-toggle=".after-table-loaded-script-options"
895
  {{ checkbox.checked(table.settings.features.enable_after_table_loaded_script) }} />
896
  </div>
897
  </div>
898
+ <div class="setting-wrapper after-table-loaded-script-options setting-suboption"
899
  {% if table.settings.features.enable_after_table_loaded_script is not defined %}
900
  style="display:none"
901
  {% endif %}
902
  >
903
+ <div class="setting-label">
904
  <label for="after-table-loaded-script-text">
905
  {{ environment.translate('JS Script Text') }}
906
  </label>
907
  </div>
908
+ <div class="setting-input">
909
+ <textarea id="after-table-loaded-script-text" placeholder="{{ environment.translate('Paste script code here')}}">{{ table.settings.features.after_table_loaded_script | default('') }}</textarea>
910
  <input type="hidden" name="features[after_table_loaded_script]" value="{{ table.settings.features.after_table_loaded_script | default('') }}" />
911
  </div>
912
  </div>
913
+
914
+ <div class="setting-title">
 
915
  <h3>{{ environment.translate('Frontend Fields') }}</h3>
916
  </div>
917
  {% if environment.isPro() == false %}
918
+ <div class="setting-wrapper">
919
+ <div class="setting-label">
920
  <label for="save-editable-fields-unavailable">
921
  {{ environment.translate('Save Frontend Fields') }}
922
  {{ tooltip.icon(environment.translate('Save table data entered through frontend fields. Refer to the first two buttons on the second row of the editor toolbar:<br />Add editable field<br />Add dropdown list')) }}
923
  <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'editable_fields_feature' }) }}">{{ environment.translate('PRO option') }}</a>
924
  </label>
925
  </div>
926
+ <div class="setting-check">
927
  <input type="checkbox" disabled="disabled" id="save-editable-fields-unavailable"/>
928
  </div>
929
  </div>
930
+ <div class="setting-wrapper">
931
+ <div class="setting-label">
932
  <label for="mark-last-edited-cell-unavailable">
933
  {{ environment.translate('Mark Last Edited Cell') }}
934
  {{ tooltip.icon(environment.translate('Adds a symbol ✓ to last edited cell.')) }}
935
  <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'mark_last_edited_cell' }) }}">{{ environment.translate('PRO option') }}</a>
936
  </label>
937
  </div>
938
+ <div class="setting-check">
939
  <input type="checkbox" disabled="disabled" id="mark-last-edited-cell-unavailable"/>
940
  </div>
941
  </div>
942
+ <div class="setting-wrapper">
943
+ <div class="setting-label">
944
  <label for="editable-fields-logged-in-unavailable">
945
  {{ environment.translate('Use for Logged In Users Only') }}
946
  {{ 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/')) }}
947
  <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'editable_fields_for_logged_in_only' }) }}">{{ environment.translate('PRO option') }}</a>
948
  </label>
949
  </div>
950
+ <div class="setting-check">
951
  <input type="checkbox" disabled="disabled" id="editable-fields-logged-in-unavailable"/>
952
  </div>
953
  </div>
954
+ <div class="setting-wrapper editable-fields-logged-in-options">
955
+ <div class="setting-label">
956
  <label for="editable-fields-roles-unavailable">
957
  {{ environment.translate('Use for Current Roles Only') }}
958
  {{ 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.')) }}
959
  <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'editable_fields_for_current_roles' }) }}">{{ environment.translate('PRO option') }}</a>
960
  </label>
961
  </div>
962
+ <div class="setting-input">
963
  <select name="useEditableFieldsForCurRoles[]" disabled="disabled" id="editable-fields-roles-unavailable" data-placeholder="{{ environment.translate('Select roles')}}">
964
  <option>{{ environment.translate('Select roles')}}</option>
965
  </select>
967
  </div>
968
  {% endif %}
969
  {% if environment.isPro() == false %}
970
+ <div class="setting-title">
971
  <h3>{{ environment.translate('Export / Import') }}</h3>
972
  </div>
973
+ <div class="setting-wrapper">
974
+ <div class="setting-label">
975
  <label for="features-export-unavailable">
976
  {{ environment.translate('Frontend Export') }}
977
  {{ tooltip.icon(environment.translate('Allows to export table in pdf, csv, xls formats from the front-end. Choose needed formats')) }}
978
  <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'export_feature' }) }}">{{ environment.translate('PRO option') }}</a>
979
  </label>
980
  </div>
981
+ <div class="setting-input">
982
  <select name="features[export][]" disabled="disabled" id="features-export-unavailable" data-placeholder="{{ environment.translate('Select Some Options')}}">
983
  <option>{{ environment.translate('Select Some Options')}}</option>
984
  </select>
985
  </div>
986
  </div>
987
+ <div class="setting-wrapper">
988
+ <div class="setting-label">
989
  <label for="features-export-pdf-paper-size-unavailable">
990
  {{ environment.translate('PDF Paper Size') }}
991
  {{ tooltip.icon(environment.translate('Choose the paper size for PDF pages')) }}
992
  </label>
993
  <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'export_feature_pdf_paper_size' }) }}">{{ environment.translate('PRO option') }}</a>
994
  </div>
995
+ <div class="setting-input">
996
  <select name="pdfPaperSize" disabled="disabled" id="features-export-pdf-paper-size-unavailable" data-placeholder="{{ environment.translate('Automatic')}}">
997
  <option>{{ environment.translate('Automatic')}}</option>
998
  </select>
999
  </div>
1000
  </div>
1001
+ <div class="setting-wrapper">
1002
+ <div class="setting-label">
1003
  <label for="features-export-pdf-orientation-unavailable">
1004
  {{ environment.translate('PDF Page Orientation') }}
1005
  {{ tooltip.icon(environment.translate('Choose the orientation for PDF pages')) }}
1006
  </label>
1007
  <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'export_feature_pdf_orientation' }) }}">{{ environment.translate('PRO option') }}</a>
1008
  </div>
1009
+ <div class="setting-input">
1010
  <select name="pdfOrientation" disabled="disabled" id="features-export-pdf-orientation-unavailable" data-placeholder="{{ environment.translate('Portrait')}}">
1011
  <option>{{ environment.translate('Portrait')}}</option>
1012
  </select>
1013
  </div>
1014
  </div>
1015
+ <div class="setting-wrapper">
1016
+ <div class="setting-label">
1017
  <label for="features-export-pdf-export-fonts-unavailable">
1018
  {{ environment.translate('Export Fonts to PDF') }}
1019
  {{ tooltip.icon(environment.translate('Allows export to PDF file the fonts, which were set for table content via editor toolbar. Important! Custom fonts might not contain some specific characters (greek, cyrillic etc.), so after importing of fonts your PDF file might lost part of content.')) }}
1020
  </label>
1021
  <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'export_feature_pdf_export_fonts' }) }}">{{ environment.translate('PRO option') }}</a>
1022
  </div>
1023
+ <div class="setting-check">
1024
  <input type="checkbox" name="pdfExportFonts" disabled="disabled" id="features-export-pdf-export-fonts-unavailable" />
1025
  </div>
1026
  </div>
1027
+ <div class="setting-wrapper">
1028
+ <div class="setting-label">
1029
  <label for="features-export-select-logo-unavailable">
1030
  {{ environment.translate('Export Logo') }}
1031
  {{ tooltip.icon(environment.translate('Automticaly appends selected logo for output pdf or printing')) }}
1032
  </label>
1033
  <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'export_feature_select_logo' }) }}">{{ environment.translate('PRO option') }}</a>
1034
  </div>
1035
+ <div class="setting-input">
1036
  <button class="button" disabled="disabled" id="features-export-select-logo-unavailable">{{ environment.translate('Select Logo') }}</button>
1037
  </div>
1038
  </div>
1039
+ <div class="setting-wrapper">
1040
+ <div class="setting-label">
1041
  <label for="google-tables-automatically-update-unavailable">
1042
  {{ environment.translate('Autoimport from Google Sheet') }}
1043
  {{ 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/')) }}
1044
  </label>
1045
  <a target="_blank" class="supsystic-pro-feature" href="{{ build_pro_url({ 'utm_medium': 'google_tables_automatically_update' }) }}">{{ environment.translate('PRO option') }}</a>
1046
  </div>
1047
+ <div class="setting-check">
1048
+ <input type="checkbox" disabled="disabled" name="features[google_tables_automatically_update]" data-preview-not-redraw='1' id="google-tables-automatically-update-unavailable" />
1049
  </div>
1050
  </div>
1051
  {% endif %}
1052
  {{ environment.getDispatcher().dispatch('tables-view-features', [table]) }}
 
 
1053
  </section>
1054
+ <section class="row-settings-block" id="stb-anl-appearance">
1055
+ <div class="settings-block-title">
1056
+ <h3><i class="fa fa-fw fa-picture-o"></i> {{ environment.translate('Appearance') }}</h3>
1057
  </div>
1058
+ <div class="setting-wrapper">
1059
+ <div class="setting-label">
 
 
1060
  <label for="features-auto-width">
1061
  {{ environment.translate('Auto Table Width') }}
1062
  {{ tooltip.icon(environment.translate('If checked - width of table columns will be calculated automatically for table width 100%.<br /><br />
1066
  option to "auto" and check "Compact Table" option.')) }}
1067
  </label>
1068
  </div>
1069
+ <div class="setting-check">
1070
  <input type="checkbox" name="features[auto_width]"
1071
  {{ checkbox.checked(table.settings.features.auto_width) }}
1072
  id="features-auto-width"
1074
  <!-- /#features-auto-width -->
1075
  </div>
1076
  </div>
1077
+ <div class="setting-wrapper auto-width-options setting-suboption"
1078
  {% if table.settings.features.auto_width is defined %}
1079
  style="display:none"
1080
  {% endif %}
1081
  >
1082
+ <div class="setting-label">
1083
  <label for="fixed-table-width">
1084
  {{ environment.translate('Fixed Table Width') }}
1085
  {{ tooltip.icon(environment.translate('Set fixed table width in px or %. Choose &quot;disable&quot; to make table width adjust by table content.')) }}
1086
  </label>
1087
  </div>
1088
+ <div class="setting-input-inline-wrapper">
1089
+ <div class="setting-input setting-input-inline">
1090
+ <input type="text" name="tableWidth" value="{{ table.settings.tableWidth | default('100') }}" id="fixed-table-width"
1091
+ {% if table.settings.tableWidthType == 'auto' %}
1092
+ style="display:none"
1093
+ {% endif %}/>
1094
+ {% set tableWidthTypeDefault = '%' %}
1095
+ </div>
1096
+ <div class="setting-input setting-input-inline">
1097
+ <label for="fixed-table-width-type-percent" class="sub-label">
1098
+ <input type="radio" name="tableWidthType" id="fixed-table-width-type-percent" value="%" {{ checkbox.radio_checked(table.settings.tableWidthType|default(tableWidthTypeDefault), '%') }} />
1099
+ <span>%</span>
1100
+ </label>
1101
+ <label for="fixed-table-width-type-pixels" class="sub-label">
1102
+ <input type="radio" name="tableWidthType" id="fixed-table-width-type-pixels" value="px" {{ checkbox.radio_checked(table.settings.tableWidthType|default(tableWidthTypeDefault), 'px') }} />
1103
+ <span>px</span>
1104
+ </label>
1105
+ <label for="fixed-table-width-type-auto" class="sub-label">
1106
+ <input type="radio" name="tableWidthType" id="fixed-table-width-type-auto" value="auto" {{ checkbox.radio_checked(table.settings.tableWidthType|default(tableWidthTypeDefault), 'auto') }} />
1107
+ <span>{{ environment.translate('disable') }}</span>
1108
+ </label>
1109
+ </div>
1110
+ </div>
1111
  </div>
1112
+ <div class="setting-wrapper auto-width-options setting-suboption"
1113
  {% if table.settings.features.auto_width is defined %}
1114
  style="display:none"
1115
  {% endif %}
1116
  >
1117
+ <div class="setting-label">
1118
  <label for="fixed-table-width-mobile">
1119
  {{ environment.translate('Fixed Table Width (mobile)') }}
1120
  {{ tooltip.icon(environment.translate('Set fixed table width in px or %. Choose &quot;disable&quot; to make table width adjust by table content.')) }}
1121
  </label>
1122
  </div>
1123
+ <div class="setting-input-inline-wrapper">
1124
+ <div class="setting-input setting-input-inline">
1125
+ <input type="text" name="tableWidthMobile" value="{{ table.settings.tableWidthMobile | default('100') }}" id="fixed-table-width-mobile"
1126
+ {% if table.settings.tableWidthMobileType == 'auto' %}
1127
+ style="display:none"
1128
+ {% endif %}/>
1129
+ {% set tableWidthMobileTypeDefault = '%' %}
1130
+ </div>
1131
+ <div class="setting-input setting-input-inline">
1132
+ <label for="fixed-table-width-mobile-type-percent" class="sub-label">
1133
+ <input type="radio" name="tableWidthMobileType" id="fixed-table-width-mobile-type-percent" value="%" {{ checkbox.radio_checked(table.settings.tableWidthMobileType|default(tableWidthMobileTypeDefault), '%') }} />
1134
+ <span>%</span>
1135
+ </label>
1136
+ <label for="fixed-table-width-mobile-type-pixels" class="sub-label">
1137
+ <input type="radio" name="tableWidthMobileType" id="fixed-table-width-mobile-type-pixels" value="px" {{ checkbox.radio_checked(table.settings.tableWidthMobileType|default(tableWidthMobileTypeDefault), 'px') }} />
1138
+ <span>px</span>
1139
+ </label>
1140
+ <label for="fixed-table-width-mobile-type-auto" class="sub-label">
1141
+ <input type="radio" name="tableWidthMobileType" id="fixed-table-width-mobile-type-auto" value="auto" {{ checkbox.radio_checked(table.settings.tableWidthMobileType|default(tableWidthMobileTypeDefault), 'auto') }} />
1142
+ <span>{{ environment.translate('disable') }}</span>
1143
+ </label>
1144
+ </div>
1145
+ </div>
 
 
 
 
 
 
 
 
 
 
 
1146
  </div>
1147
+ <div class="setting-wrapper auto-width-options setting-suboption"
1148
  {% if table.settings.features.auto_width is defined %}
1149
  style="display:none"
1150
  {% endif %}
1151
  >
1152
+ <div class="setting-label">
1153
  <label for="table-alignment-on-page">
1154
  {{ environment.translate('Align by First Table') }}
1155
  {{ tooltip.icon(environment.translate('If checked - this table will be resized by first supsystic table on page. Important! This option makes sense only if table is not on responsive mode or responsive mode is disabled. Also if the first table has different count of columns or different settings, their sizes may not be equal.')) }}
1156
  </label>
1157
  </div>
1158
+ <div class="setting-check">
1159
  <input type="checkbox" name="alignByFirstTable"
1160
  {{ checkbox.checked(table.settings.alignByFirstTable) }}
1161
  id="table-alignment-on-page"/>
1162
  </div>
1163
  </div>
1164
+ <div class="setting-wrapper">
1165
+ <div class="setting-label">
1166
+ <label for="styling-compact">
1167
+ {{ environment.translate('Compact Table') }}
1168
+ {{ tooltip.icon(environment.translate('Decrease the amount of whitespace in the table.')) }}
1169
+ </label>
1170
+ </div>
1171
+ <div class="setting-check">
1172
+ <input type="checkbox"
1173
+ name="styling[compact]"
1174
+ {{ checkbox.checked(attribute(table.settings.styling, 'compact')) }}
1175
+ id="styling-compact"/>
1176
+ </div>
1177
+ </div>
1178
+ <div class="setting-wrapper">
1179
+ <div class="setting-label">
1180
  <label for="styling-nowrap">
1181
  {{ environment.translate('Disable Wrapping') }}
1182
  {{ tooltip.icon(environment.translate('Disable wrapping of content in the table, so every word in the cells will be in one single line.')) }}
1183
  </label>
1184
  </div>
1185
+ <div class="setting-check">
1186
  <input type="checkbox"
1187
  name="styling[nowrap]"
1188
  {{ checkbox.checked(attribute(table.settings.styling, 'nowrap')) }}
1189
  id="styling-nowrap"/>
 
1190
  </div>
1191
  </div>
1192
+ <div class="setting-wrapper">
1193
+ <div class="setting-label">
1194
  <label for="paragraphMode">
1195
  {{ environment.translate('Paragraph Mode') }}
1196
  {{ tooltip.icon(environment.translate('This mode allows you to separate the content into paragraphs. To move to a new line in the cell - please press CTRL + Enter.')) }}
1197
  </label>
1198
  </div>
1199
+ <div class="setting-check">
1200
  <input type="checkbox"
1201
  name="styling[paragraphMode]"
1202
  {{ checkbox.checked(attribute(table.settings.styling, 'paragraphMode')) }}
1203
  id="paragraphMode"/>
1204
  </div>
1205
  </div>
1206
+ <div class="setting-wrapper">
1207
+ <div class="setting-label">
1208
  <label for="lightboxImg">
1209
  {{ environment.translate('Lightbox') }}
1210
  {{ tooltip.icon(environment.translate('Add Lightbox fo images . <a href="https://supsystic.com/documentation/lightbox-with-full-size-images/">https://supsystic.com/documentation/lightbox-with-full-size-images/</a>')) }}
1213
  {% endif %}
1214
  </label>
1215
  </div>
1216
+ <div class="setting-check">
1217
  {% if environment.isPro() == false %}
1218
  <input type="checkbox" disabled="disabled" id="save-editable-fields-unavailable"/>
1219
  {% else %}
1224
  {% endif %}
1225
  </div>
1226
  </div>
1227
+ <div class="setting-wrapper">
1228
+ <div class="setting-label">
1229
  <label for="lightboxImg">
1230
  {{ environment.translate('Merge cells align') }}
1231
  {{ tooltip.icon(environment.translate('Align columns which have include merge cells to left (in responcive mode)')) }}
1232
  </label>
1233
  </div>
1234
+ <div class="setting-check">
1235
  <input type="checkbox"
1236
  name="styling[ColWithMergeCellsAlign]"
1237
  {{ checkbox.checked(attribute(table.settings.styling, 'ColWithMergeCellsAlign')) }}
1238
  id="ColWithMergeCellsAlign"/>
1239
  </div>
1240
  </div>
1241
+ <div class="setting-wrapper setting-wrapper-inline">
1242
+ <div class="setting-label">
 
 
 
1243
  <label for="styling-border">
1244
  {{ environment.translate('Borders') }}
1245
  {{ tooltip.icon(environment.translate('Cell - adds border around all four sides of each cell, Row - adds border only over and under each row. (i.e. only for the rows).')) }}
1246
  </label>
1247
  </div>
1248
+ <div class="setting-input">
1249
  <select name="styling[border]"
1250
  id="styling-border">
1251
  {% for option in [
1256
  <option value="{{ option.value }}" {% if table.settings.styling.border == option.value %}selected="selected"{% endif %}>{{ option.name }}</option>
1257
  {% endfor %}
1258
  </select>
 
1259
  </div>
1260
  </div>
1261
+ <div class="setting-wrapper">
1262
+ <div class="setting-label">
1263
  <label for="styling-stripe">
1264
  {{ environment.translate('Row Striping') }}
1265
  {{ tooltip.icon(environment.translate('Add automatic highlight for table odd rows')) }}
1266
  </label>
1267
  </div>
1268
+ <div class="setting-check">
1269
  <input type="checkbox"
1270
  name="styling[stripe]"
1271
  {{ checkbox.checked(attribute(table.settings.styling, 'stripe')) }}
1272
  id="styling-stripe"/>
 
1273
  </div>
1274
  </div>
1275
+ <div class="setting-wrapper">
1276
+ <div class="setting-label">
1277
  <label for="styling-hover">
1278
  {{ environment.translate('Highlighting by Mousehover') }}
1279
  {{ tooltip.icon(environment.translate('Row highlighting by mouse hover.')) }}
1280
  </label>
1281
  </div>
1282
+ <div class="setting-check">
1283
  <input type="checkbox" name="styling[hover]"
1284
  {{ checkbox.checked(attribute(table.settings.styling, 'hover')) }}
1285
  id="styling-hover"/>
 
1286
  </div>
1287
  </div>
1288
+ <div class="setting-wrapper">
1289
+ <div class="setting-label">
1290
  <label for="styling-order-column">
1291
  {{ environment.translate('Highlight the Order Column') }}
1292
  {{ tooltip.icon(environment.translate('If checked - the current sorted column will be highlighted')) }}
1293
  </label>
1294
  </div>
1295
+ <div class="setting-check">
1296
  <input type="checkbox"
1297
  name="styling[order-column]"
1298
  {{ checkbox.checked(attribute(table.settings.styling, 'order-column')) }}
1299
  id="styling-order-column"/>
 
1300
  </div>
1301
  </div>
1302
+ <div class="setting-wrapper">
1303
+ <div class="setting-label">
1304
  <label for="hide-table-loader">
1305
  {{ environment.translate('Hide Table Loader') }}
1306
  {{ tooltip.icon(environment.translate('Enable / disable table loader icon before table will be completely loaded.')) }}
1307
  </label>
1308
  </div>
1309
+ <div class="setting-check">
1310
  <input type="checkbox"
1311
  name="tableLoader[disable]"
1312
  {{ checkbox.checked(table.settings.tableLoader.disable) }}
1313
  id="hide-table-loader"
1314
  data-target-toggle=".hide-table-loader-options" />
 
1315
  </div>
1316
  </div>
1317
+ <div class="setting-wrapper hide-table-loader-options setting-suboption"
1318
  {% if table.settings.tableLoader.disable is defined %}
1319
  style="display:none"
1320
  {% endif %}
1321
  >
1322
+ <div class="setting-label">
1323
  <label for="table-loaedr-icon">
1324
  {{ environment.translate('Table Loader Icon') }}
1325
  {{ tooltip.icon(environment.translate('Choose icon for loader')) }}
1328
  {% set tblLoaderIconItems = table.settings.tableLoader.iconItems | default('0') %}
1329
  {% set tblLoaderColor = table.settings.tableLoader.color | default('#000000') %}
1330
  </div>
1331
+ <div class="setting-input">
1332
  <button class="button selectTableLoaderIcon" id="table-loaedr-icon">{{ environment.translate('Choose Icon') }}</button>
1333
  <input type="hidden" name="tableLoader[iconName]" value="{{ tblLoaderIconName }}" />
1334
  <input type="hidden" name="tableLoader[iconItems]" value="{{ tblLoaderIconItems }}" />
1346
  </div>
1347
  </div>
1348
  </div>
1349
+ <div class="setting-wrapper hide-table-loader-options setting-suboption"
1350
  {% if table.settings.tableLoader.disable is defined %}
1351
  style="display:none"
1352
  {% endif %}
1353
  >
1354
+ <div class="setting-label">
1355
  <label for="tableLoaderColorContainer">
1356
  {{ environment.translate('Table Loader Color') }}
1357
  {{ tooltip.icon(environment.translate('Choose color for loader')) }}
1358
  </label>
1359
  </div>
1360
+ <div class="setting-input">
1361
  <div id="tableLoaderColorContainer" class="colorPickerShell">
1362
  <div class="tableLoaderColorArea colorPickerArea" style="background-color: {{ tblLoaderColor }};"></div>
1363
  <input type="hidden" name="tableLoader[color]" value="{{ tblLoaderColor }}" />
1364
  </div>
1365
  </div>
1366
  </div>
1367
+ <div class="setting-title">
1368
+ <h3>{{ environment.translate('Table Styling') }}</h3>
1369
+ </div>
1370
+ {% if table.settings.styles.useCustomStyles is defined and table.settings.styles.useCustomStyles == 'on' %}
1371
+ {% set hiddenOption = false %}
1372
+ {% else %}
1373
+ {% set hiddenOption = true %}
1374
+ {% endif %}
1375
+ {% set customCss = table.settings.styles.customCss | default('') %}
1376
+ {% set externalBorderColor = table.settings.styles.externalBorderColor | default('') %}
1377
+ {% set headerBorderColor = table.settings.styles.headerBorderColor | default('') %}
1378
+ {% set rowBorderColor = table.settings.styles.rowBorderColor | default('') %}
1379
+ {% set columnBorderColor = table.settings.styles.columnBorderColor | default('') %}
1380
+ <div class="setting-wrapper">
1381
+ <div class="setting-label">
1382
+ <label for="use-custom-styles">
1383
+ {{ environment.translate('Use custom styles') }}
1384
+ {{ tooltip.icon(environment.translate('Choose your custom table styles below. Any settings you leave blank will default to your theme styles.')) }}
1385
+ </label>
1386
+ </div>
1387
+ <div class="setting-check">
1388
+ <input type="checkbox" data-preview-not-redraw="1"
1389
+ name="styles[useCustomStyles]"
1390
+ {{ checkbox.checked(attribute(table.settings.styles, 'useCustomStyles')) }}
1391
+ id="use-custom-styles"/>
1392
+ <input type="hidden" name="styles[customCss]" value="{{ customCss }}" />
1393
+ </div>
1394
+ </div>
1395
+ <div class="setting-wrapper table-styles-options setting-suboption"
1396
+ {% if hiddenOption %}
1397
+ style="display:none"
1398
+ {% endif %}>
1399
+ <div class="setting-label">
1400
+ <label>
1401
+ {{ environment.translate('Borders external') }}
1402
+ </label>
1403
+ </div>
1404
+ <div class="setting-input">
1405
+ <div class="color-settings-wrapper">
1406
+ <div class="color-picker-wrapper">
1407
+ <div class="color-picker-preview" style="background-color: {{ externalBorderColor }};"></div>
1408
+ </div>
1409
+ <input type="text" class="color-input" data-preview-not-redraw="1" name="styles[externalBorderColor]" value="{{ externalBorderColor }}" />
1410
+ <label class="inner-label">width</label>
1411
+ <input type="text" class="input-small" data-preview-not-redraw="1" name="styles[externalBorderWidth]" value="{{ table.settings.styles.externalBorderWidth | default('') }}" />
1412
+ <label class="right-label">px</label>
1413
+ </div>
1414
+ </div>
1415
+ </div>
1416
+ <div class="setting-wrapper table-styles-options setting-suboption"
1417
+ {% if hiddenOption %}
1418
+ style="display:none"
1419
+ {% endif %}>
1420
+ <div class="setting-label">
1421
+ <label>
1422
+ {{ environment.translate('Borders header') }}
1423
+ </label>
1424
+ </div>
1425
+ <div class="setting-input">
1426
+ <div class="color-settings-wrapper">
1427
+ <div class="color-picker-wrapper">
1428
+ <div class="color-picker-preview" style="background-color: {{ headerBorderColor }};"></div>
1429
+ </div>
1430
+ <input type="text" class="color-input" data-preview-not-redraw="1" name="styles[headerBorderColor]" value="{{ headerBorderColor }}" />
1431
+ <label class="inner-label">width</label>
1432
+ <input type="text" class="input-small" data-preview-not-redraw="1" name="styles[headerBorderWidth]" value="{{ table.settings.styles.headerBorderWidth | default('') }}" />
1433
+ <label class="right-label">px</label>
1434
+ </div>
1435
+ </div>
1436
+ </div>
1437
+ <div class="setting-wrapper table-styles-options setting-suboption"
1438
+ {% if hiddenOption %}
1439
+ style="display:none"
1440
+ {% endif %}>
1441
+ <div class="setting-label">
1442
+ <label>
1443
+ {{ environment.translate('Borders rows') }}
1444
+ </label>
1445
+ </div>
1446
+ <div class="setting-input">
1447
+ <div class="color-settings-wrapper">
1448
+ <div class="color-picker-wrapper">
1449
+ <div class="color-picker-preview" style="background-color: {{ rowBorderColor }};"></div>
1450
+ </div>
1451
+ <input type="text" class="color-input" data-preview-not-redraw="1" name="styles[rowBorderColor]" value="{{ rowBorderColor }}" />
1452
+ <label class="inner-label">width</label>
1453
+ <input type="text" class="input-small" data-preview-not-redraw="1" name="styles[rowBorderWidth]" value="{{ table.settings.styles.rowBorderWidth | default('') }}" />
1454
+ <label class="right-label">px</label>
1455
+ </div>
1456
+ </div>
1457
+ </div>
1458
+ <div class="setting-wrapper table-styles-options setting-suboption"
1459
+ {% if hiddenOption %}
1460
+ style="display:none"
1461
+ {% endif %}>
1462
+ <div class="setting-label">
1463
+ <label>
1464
+ {{ environment.translate('Borders columns') }}
1465
+ </label>
1466
+ </div>
1467
+ <div class="setting-input">
1468
+ <div class="color-settings-wrapper">
1469
+ <div class="color-picker-wrapper">
1470
+ <div class="color-picker-preview" style="background-color: {{ columnBorderColor }};"></div>
1471
+ </div>
1472
+ <input type="text" class="color-input" data-preview-not-redraw="1" name="styles[columnBorderColor]" value="{{ columnBorderColor }}" />
1473
+ <label class="inner-label">width</label>
1474
+ <input type="text" class="input-small" data-preview-not-redraw="1" name="styles[columnBorderWidth]" value="{{ table.settings.styles.columnBorderWidth | default('') }}" />
1475
+ <label class="right-label">px</label>
1476
+ </div>
1477
+ </div>
1478
+ </div>
1479
+ {% set headerBackgroundColor = table.settings.styles.headerBackgroundColor | default('') %}
1480
+ {% set headerFontColor = table.settings.styles.headerFontColor | default('') %}
1481
+
1482
+ <div class="setting-wrapper table-styles-options setting-suboption"
1483
+ {% if hiddenOption %}
1484
+ style="display:none"
1485
+ {% endif %}>
1486
+ <div class="setting-label">
1487
+ <label>
1488
+ {{ environment.translate('Header background') }}
1489
+ </label>
1490
+ </div>
1491
+ <div class="setting-input">
1492
+ <div class="color-settings-wrapper">
1493
+ <div class="color-picker-wrapper">
1494
+ <div class="color-picker-preview" style="background-color: {{ headerBackgroundColor }};"></div>
1495
+ </div>
1496
+ <input type="text" class="color-input" data-preview-not-redraw="1" name="styles[headerBackgroundColor]" value="{{ headerBackgroundColor }}" />
1497
+ </div>
1498
+ </div>
1499
+ </div>
1500
+ <div class="setting-wrapper table-styles-options setting-suboption"
1501
+ {% if hiddenOption %}
1502
+ style="display:none"
1503
+ {% endif %}>
1504
+ <div class="setting-label">
1505
+ <label>
1506
+ {{ environment.translate('Header font') }}
1507
+ </label>
1508
+ </div>
1509
+ <div class="setting-input">
1510
+ <select data-preview-not-redraw="1" name="styles[headerFontFamily]" data-value="{{ table.settings.styles.headerFontFamily | default('default') }}">
1511
+ </select>
1512
+ </div>
1513
+ </div>
1514
+ <div class="setting-wrapper table-styles-options setting-suboption"
1515
+ {% if hiddenOption %}
1516
+ style="display:none"
1517
+ {% endif %}>
1518
+ <div class="setting-input">
1519
+ <div class="color-settings-wrapper">
1520
+ <div class="color-picker-wrapper">
1521
+ <div class="color-picker-preview" style="background-color: {{ headerFontColor }};"></div>
1522
+ </div>
1523
+ <input type="text" class="color-input" data-preview-not-redraw="1" name="styles[headerFontColor]" value="{{ headerFontColor }}" />
1524
+ <label class="inner-label">size</label>
1525
+ <input type="text" class="input-small" data-preview-not-redraw="1" name="styles[headerFontSize]" value="{{ table.settings.styles.headerFontSize | default('') }}" />
1526
+ <label class="right-label">px</label>
1527
+ </div>
1528
+ </div>
1529
+ </div>
1530
+
1531
+ {% set cellBackgroundColor = table.settings.styles.cellBackgroundColor | default('') %}
1532
+ {% set cellFontColor = table.settings.styles.cellFontColor | default('') %}
1533
+ <div class="setting-wrapper table-styles-options setting-suboption"
1534
+ {% if hiddenOption %}
1535
+ style="display:none"
1536
+ {% endif %}>
1537
+ <div class="setting-label">
1538
+ <label>
1539
+ {{ environment.translate('Cell background') }}
1540
+ </label>
1541
+ </div>
1542
+ <div class="setting-input">
1543
+ <div class="color-settings-wrapper">
1544
+ <div class="color-picker-wrapper">
1545
+ <div class="color-picker-preview" style="background-color: {{ cellBackgroundColor }};"></div>
1546
+ </div>
1547
+ <input type="text" class="color-input" data-preview-not-redraw="1" name="styles[cellBackgroundColor]" value="{{ cellBackgroundColor }}" />
1548
+ </div>
1549
+ </div>
1550
+ </div>
1551
+ <div class="setting-wrapper table-styles-options setting-suboption"
1552
+ {% if hiddenOption %}
1553
+ style="display:none"
1554
+ {% endif %}>
1555
+ <div class="setting-label">
1556
+ <label>
1557
+ {{ environment.translate('Cell font') }}
1558
+ </label>
1559
+ </div>
1560
+ <div class="setting-input">
1561
+ <select data-preview-not-redraw="1" name="styles[cellFontFamily]" data-value="{{ table.settings.styles.cellFontFamily | default('default') }}">
1562
+ </select>
1563
+ </div>
1564
+ </div>
1565
+ <div class="setting-wrapper table-styles-options setting-suboption"
1566
+ {% if hiddenOption %}
1567
+ style="display:none"
1568
+ {% endif %}>
1569
+ <div class="setting-input">
1570
+ <div class="color-settings-wrapper">
1571
+ <div class="color-picker-wrapper">
1572
+ <div class="color-picker-preview" style="background-color: {{ cellFontColor }};"></div>
1573
+ </div>
1574
+ <input type="text" class="color-input" data-preview-not-redraw="1" name="styles[cellFontColor]" value="{{ cellFontColor }}" />
1575
+ <label class="inner-label">size</label>
1576
+ <input type="text" class="input-small" data-preview-not-redraw="1" name="styles[cellFontSize]" value="{{ table.settings.styles.cellFontSize | default('') }}" />
1577
+ <label class="right-label">px</label>
1578
+ </div>
1579
+ </div>
1580
+ </div>
1581
+ {% set searchBackgroundColor = table.settings.styles.searchBackgroundColor | default('') %}
1582
+ {% set searchFontColor = table.settings.styles.searchFontColor | default('') %}
1583
+ {% set searchBorderColor = table.settings.styles.searchBorderColor | default('') %}
1584
+ <div class="setting-wrapper table-styles-options setting-suboption"
1585
+ {% if hiddenOption %}
1586
+ style="display:none"
1587
+ {% endif %}>
1588
+ <div class="setting-label">
1589
+ <label>
1590
+ {{ environment.translate('Search Bar Colors') }}
1591
+ </label>
1592
+ </div>
1593
+ <div class="setting-input">
1594
+ <div class="color-settings-wrapper">
1595
+ <div class="color-picker-wrapper">
1596
+ <div class="color-picker-preview" style="background-color: {{ searchBackgroundColor }};"></div>
1597
+ </div>
1598
+ <input type="text" class="color-input" data-preview-not-redraw="1" name="styles[searchBackgroundColor]" value="{{ searchBackgroundColor }}" />
1599
+ <label class="right-label">{{ environment.translate('background')}}</label>
1600
+ </div>
1601
+ </div>
1602
+ </div>
1603
+ <div class="setting-wrapper table-styles-options setting-suboption"
1604
+ {% if hiddenOption %}
1605
+ style="display:none"
1606
+ {% endif %}>
1607
+ <div class="setting-input">
1608
+ <div class="color-settings-wrapper">
1609
+ <div class="color-picker-wrapper">
1610
+ <div class="color-picker-preview" style="background-color: {{ searchFontColor }};"></div>
1611
+ </div>
1612
+ <input type="text" class="color-input" data-preview-not-redraw="1" name="styles[searchFontColor]" value="{{ searchFontColor }}" />
1613
+ <label class="right-label">{{ environment.translate('font')}}</label>
1614
+ </div>
1615
+ </div>
1616
+ </div>
1617
+ <div class="setting-wrapper table-styles-options setting-suboption"
1618
+ {% if hiddenOption %}
1619
+ style="display:none"
1620
+ {% endif %}>
1621
+ <div class="setting-input">
1622
+ <div class="color-settings-wrapper">
1623
+ <div class="color-picker-wrapper">
1624
+ <div class="color-picker-preview" style="background-color: {{ searchBorderColor }};"></div>
1625
+ </div>
1626
+ <input type="text" class="color-input" data-preview-not-redraw="1" name="styles[searchBorderColor]" value="{{ searchBorderColor }}" />
1627
+ <label class="right-label">{{ environment.translate('border')}}</label>
1628
+ </div>
1629
+ </div>
1630
+ </div>
1631
+ <div class="setting-wrapper table-styles-options setting-suboption"
1632
+ {% if hiddenOption %}
1633
+ style="display:none"
1634
+ {% endif %}>
1635
+ <div class="setting-label">
1636
+ <label for="use-fixed-layout">
1637
+ {{ environment.translate('Fixed Layout') }}
1638
+ {{ tooltip.icon(environment.translate('Set all columns of the same width.')) }}
1639
+ </label>
1640
+ </div>
1641
+ <div class="setting-check">
1642
+ <input type="checkbox" data-preview-not-redraw="1"
1643
+ name="styles[fixedLayout]"
1644
+ {{ checkbox.checked(attribute(table.settings.styles, 'fixedLayout')) }}
1645
+ id="use-fixed-layout"/>
1646
+ </div>
1647
+ </div>
1648
+ {% set verticalAlignment = table.settings.styles.verticalAlignment | default('') %}
1649
+ <div class="setting-wrapper table-styles-options setting-suboption"
1650
+ {% if hiddenOption %}
1651
+ style="display:none"
1652
+ {% endif %}>
1653
+ <div class="setting-label">
1654
+ <label for="use-custom-styles">
1655
+ {{ environment.translate('Vertical alignment') }}
1656
+ {{ tooltip.icon(environment.translate('Set vertical alignment of table cell contents.')) }}
1657
+ </label>
1658
+ </div>
1659
+ <div class="setting-input">
1660
+ <select name="styles[verticalAlignment]" data-preview-not-redraw="1">
1661
+ {% for option in [
1662
+ { 'name': environment.translate('None'), 'value': '' },
1663
+ { 'name': environment.translate('Top'), 'value': 'top' },
1664
+ { 'name': environment.translate('Middle'), 'value': 'middle' },
1665
+ { 'name': environment.translate('Bottom'), 'value': 'bottom' }
1666
+ ] %}
1667
+ <option value="{{ option.value }}" {% if verticalAlignment == option.value %}selected="selected"{% endif %}>{{ option.name }}</option>
1668
+ {% endfor %}
1669
+ </select>
1670
+ </div>
1671
+ </div>
1672
+ {% set horizontalAlignment = table.settings.styles.horizontalAlignment | default('') %}
1673
+ <div class="setting-wrapper table-styles-options setting-suboption"
1674
+ {% if hiddenOption %}
1675
+ style="display:none"
1676
+ {% endif %}>
1677
+ <div class="setting-label">
1678
+ <label for="use-custom-styles">
1679
+ {{ environment.translate('Horizontal alignment') }}
1680
+ {{ tooltip.icon(environment.translate('Set horizontal alignment of table cell contents.')) }}
1681
+ </label>
1682
+ </div>
1683
+ <div class="setting-input">
1684
+ <select name="styles[horizontalAlignment]" data-preview-not-redraw="1">
1685
+ {% for option in [
1686
+ { 'name': environment.translate('None'), 'value': '' },
1687
+ { 'name': environment.translate('Left'), 'value': 'left' },
1688
+ { 'name': environment.translate('Center'), 'value': 'center' },
1689
+ { 'name': environment.translate('Right'), 'value': 'right' }
1690
+ ] %}
1691
+ <option value="{{ option.value }}" {% if horizontalAlignment == option.value %}selected="selected"{% endif %}>{{ option.name }}</option>
1692
+ {% endfor %}
1693
+ </select>
1694
+ </div>
1695
+ </div>
1696
+ {% set paginationPosition = table.settings.styles.paginationPosition | default('') %}
1697
+ <div class="setting-wrapper table-styles-options setting-suboption"
1698
+ {% if hiddenOption %}
1699
+ style="display:none"
1700
+ {% endif %}>
1701
+ <div class="setting-label">
1702
+ <label for="use-custom-styles">
1703
+ {{ environment.translate('Pagination Position') }}
1704
+ {{ tooltip.icon(environment.translate('Set horizontal pagination buttons position.')) }}
1705
+ </label>
1706
+ </div>
1707
+ <div class="setting-input">
1708
+ <select name="styles[paginationPosition]" data-preview-not-redraw="1">
1709
+ {% for option in [
1710
+ { 'name': environment.translate('None'), 'value': '' },
1711
+ { 'name': environment.translate('Left'), 'value': 'left' },
1712
+ { 'name': environment.translate('Center'), 'value': 'center' },
1713
+ { 'name': environment.translate('Right'), 'value': 'right' }
1714
+ ] %}
1715
+ <option value="{{ option.value }}" {% if paginationPosition == option.value %}selected="selected"{% endif %}>{{ option.name }}</option>
1716
+ {% endfor %}
1717
+ </select>
1718
+ </div>
1719
+ </div>
1720
+ <div class="setting-wrapper table-styles-options setting-suboption"
1721
+ {% if hiddenOption %}
1722
+ style="display:none"
1723
+ {% endif %}>
1724
+ <div class="setting-label">
1725
+ <label for="show-sort-hover">
1726
+ {{ environment.translate('Show sorting icon on mouse over') }}
1727
+ </label>
1728
+ </div>
1729
+ <div class="setting-check">
1730
+ <input type="checkbox" data-preview-not-redraw="1"
1731
+ name="styles[showSortHover]"
1732
+ {{ checkbox.checked(attribute(table.settings.styles, 'showSortHover')) }}
1733
+ id="show-sort-hover"/>
1734
+ </div>
1735
+ </div>
1736
  </section>
1737
+ <section class="row-settings-block" id="stb-anl-text">
1738
+ <div class="settings-block-title">
1739
+ <h3><i class="fa fa-fw fa-language"></i> {{ environment.translate('Language and Text') }}</h3>
1740
  </div>
1741
+ <div class="setting-title">
 
1742
  <h3>{{ environment.translate('Overwrite Table Text') }}</h3>
1743
  </div>
1744
  {% set language_override = {
1780
  },
1781
  } %}
1782
  {% for key, data in language_override %}
1783
+ <div class="setting-wrapper">
1784
+ <div class="setting-label">
1785
  <label for="language-{{ key }}">
1786
  {{ data.label }}
1787
  {% if data.info is not empty %}
1789
  {% endif %}
1790
  </label>
1791
  </div>
1792
+ <div class="setting-input">
1793
  <input id="language-{{ key }}" type="text" name="language[{{ key }}]" value="{{ attribute(table.settings.language, key) }}" placeholder="{{ data.default }}">
1794
  </div>
1795
  </div>
1796
  {% endfor %}
1797
+ <div class="setting-title">
 
 
1798
  <h3>{{ environment.translate('Language') }}</h3>
1799
  </div>
1800
+ <div class="setting-wrapper setting-wrapper-inline">
1801
+ <div class="setting-label">
1802
  <label for="language-file">
1803
  {{ environment.translate('Table Language') }}
1804
  {{ tooltip.icon(environment.translate('Allows to choose language for the table\'s labels (pagination, search ets.). The dafault language is English.')) }}
1805
  </label>
1806
  </div>
1807
+ <div class="setting-input">
1808
  <select name="language[file]" id="language-file">
1809
  {% for supportedLanguage in translations %}
1810
  <option value="{{ supportedLanguage }}" {% if table.settings.language.file == supportedLanguage %}selected="selected"{% endif %}>
1818
  </select>
1819
  </div>
1820
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1821
  </section>
1822
  </section>
1823
  </form>
1824
  </div>
1825
+ </section>
1826
+ <section class="preview-section">
1827
+ <div class="row preview-styling">
1828
+ <div class="stb-wraper-anchor-nav-links">
1829
+ <a href="#stb-style-desktop" class="stb-anchor-nav-links active">{{ translate('Desktop')}}</a>
1830
+ <a href="#stb-style-tablet" class="stb-anchor-nav-links">{{ translate('Tablet')}}</a>
1831
+ <a href="#stb-style-mobile" class="stb-anchor-nav-links">{{ translate('Mobile')}}</a>
1832
+ </div>
1833
+ </div>
1834
+ <div id="preview-container">
1835
+ <style type="text/css" id="stb-preview-css"></style>
1836
+ <div id="table-preview"></div>
1837
+ <p class="description">
1838
+ <i class="fa fa-fw fa-exclamation-circle"></i>
1839
+ {{ environment.translate('Note that the table may look a little different depending on your theme style.') }}
1840
+ </p>
1841
+ </div>
1842
+ </section>
1843
  </div>
1844
 
1845
  <div class="row row-tab" id="row-tab-editor">
2159
  ></div>
2160
  <!-- /#tableEditor -->
2161
  </div>
 
 
 
 
 
 
 
 
 
2162
  <div class="row row-tab" id="row-tab-css">
2163
 
2164
 
src/SupsysticTables/Ui/views/tooltip.twig CHANGED
@@ -8,7 +8,7 @@
8
  {% import _self as tooltip %}
9
 
10
  {% spaceless %}
11
- <i class="fa fa-question supsystic-tooltip tooltipstered" {{ attr | raw }} {{ tooltip.attr(text, placement, html) }}></i>
12
  <!-- /.fa fa-question supsystic-tooltip tooltipstered -->
13
  {% endspaceless %}
14
  {% endmacro %}
8
  {% import _self as tooltip %}
9
 
10
  {% spaceless %}
11
+ <i class="fa fa-info-circle supsystic-tooltip tooltipstered" {{ attr | raw }} {{ tooltip.attr(text, placement, html) }}></i>
12
  <!-- /.fa fa-question supsystic-tooltip tooltipstered -->
13
  {% endspaceless %}
14
  {% endmacro %}
src/SupsysticTables/Woocommerce/assets/img/wooadsfool.gif DELETED
Binary file
src/SupsysticTables/Woocommerce/views/partials/tab.twig CHANGED
@@ -1,6 +1,6 @@
1
  <li>
2
  <a href="#row-tab-woocommerce" class="button">
3
  <i class="fa fa-fw fa-bar-chart"></i>
4
- {{ environment.translate('Woocommerce') }}
5
  </a>
6
  </li>
1
  <li>
2
  <a href="#row-tab-woocommerce" class="button">
3
  <i class="fa fa-fw fa-bar-chart"></i>
4
+ {{ environment.translate('WooCommerce') }}
5
  </a>
6
  </li>
src/SupsysticTables/Woocommerce/views/partials/tabContent.twig CHANGED
@@ -9,7 +9,7 @@
9
  </div>
10
  <div class="col-xs-12">
11
  <a href="https://supsystic.com/plugins/woocommerce-product-table/" target="_blank">
12
- <img style="max-width:800px" src="{{ environment.getModule('woocommerce').getLocationUrl() }}/assets/img/wooadsfool.gif" alt="Woo ads gig" title="Available in PRO version" style="width: 100%; height: auto;">
13
  </a>
14
  </div>
15
  {% endblock %}
9
  </div>
10
  <div class="col-xs-12">
11
  <a href="https://supsystic.com/plugins/woocommerce-product-table/" target="_blank">
12
+ <img style="max-width:100%" src="{{ environment.getModule('core').getCdnUrl() }}_assets/tables/img/settings/woo_addon.gif" alt="Woo ads gig" title="Available in PRO version" style="width: 100%; height: auto;">
13
  </a>
14
  </div>
15
  {% endblock %}