Page Builder by SiteOrigin - Version 2.4

Version Description

  • April 1 2016 =
  • Created new Live Editor.
  • Changes to Page Builder admin HTML structure for Live Editor.
  • New layout for prebuilt dialog.
  • Now possible to append, prepend and replace layouts in prebuilt dialog.
  • Fixed contextual menu in Layout Builder widget.
  • Added row/widget actions to contextual menu.
  • Clarified functionality of "Switch to Editor" button by renaming to "Revert to Editor".
  • refreshPanelsData function is called more consistently.
  • Various background performance enhancements.
  • Full JS code refactoring.
  • Fixed cell bottom margins with reverse collapse order.
  • Improved window scroll locking for dialogs.
  • Added in_widget_form action when rendering widget forms
  • Custom home page now saves revisions.
Download this release

Release Info

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

Code changes from version 2.3.2 to 2.4

css/admin.css CHANGED
@@ -9,7 +9,8 @@
9
  #so-panels-panels.attached-to-editor {
10
  margin-top: 20px;
11
  }
12
- #so-panels-panels.attached-to-editor .hndle {
 
13
  display: none !important;
14
  }
15
  #so-panels-panels.attached-to-editor .inside {
@@ -25,11 +26,6 @@
25
  /* These are generic iconic buttons used in the page builder interface */
26
  /* Page Builder icons */
27
  }
28
- .siteorigin-panels-builder .so-builder-container {
29
- /* Top padding for the toolbar */
30
- padding-top: 38px;
31
- position: relative;
32
- }
33
  .siteorigin-panels-builder .so-tool-button {
34
  padding: 6px 7px;
35
  font-size: 11px;
@@ -40,6 +36,7 @@
40
  display: block;
41
  visibility: visible;
42
  position: relative;
 
43
  border: 1px solid #C0C0C0;
44
  background: #F0F0F0;
45
  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #F0F0F0), color-stop(1, #F9F9F9));
@@ -76,10 +73,10 @@
76
  border-bottom: 1px solid #D0D0D0;
77
  background: #F5F5F5;
78
  line-height: 1em;
79
- position: absolute;
80
  z-index: 101;
81
  white-space: nowrap;
82
  overflow-x: hidden;
 
83
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
84
  top: 0;
85
  left: 0;
@@ -114,6 +111,7 @@
114
  position: absolute;
115
  top: 5px;
116
  right: 10px;
 
117
  display: none;
118
  text-decoration: none;
119
  color: #666666;
@@ -130,20 +128,6 @@
130
  border: 1px solid #999999;
131
  color: #444444;
132
  }
133
- @media screen and (max-width: 600px) {
134
- .siteorigin-panels-builder .so-builder-toolbar {
135
- padding: 10px;
136
- }
137
- .siteorigin-panels-builder .so-builder-toolbar > .so-tool-button {
138
- padding-right: 2px;
139
- }
140
- .siteorigin-panels-builder .so-builder-toolbar > .so-tool-button .so-panels-icon {
141
- font-size: 20px;
142
- }
143
- .siteorigin-panels-builder .so-builder-toolbar > .so-tool-button span.so-button-text {
144
- display: none;
145
- }
146
- }
147
  .siteorigin-panels-builder .so-rows-container {
148
  padding: 20px 15px 0 15px;
149
  }
@@ -173,59 +157,13 @@
173
  .siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-tool-button.so-row-move {
174
  cursor: move;
175
  }
176
- .siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper {
177
- position: relative;
178
- float: right;
179
- }
180
  .siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper {
181
  display: none;
182
- z-index: 11;
183
- position: absolute;
184
  right: -10px;
185
- padding: 6px 0 0 0;
186
  top: 22px;
187
  width: 125px;
188
  }
189
- .siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper ul {
190
- margin: 0;
191
- border: 1px solid #C0C0C0;
192
- background: #F9F9F9;
193
- -webkit-border-radius: 2px;
194
- -moz-border-radius: 2px;
195
- border-radius: 2px;
196
- padding: 4px 0;
197
- -webkit-box-shadow: 0 2px 2px rgba(0,0,0,0.1);
198
- -moz-box-shadow: 0 2px 2px rgba(0,0,0,0.1);
199
- box-shadow: 0 2px 2px rgba(0,0,0,0.1);
200
- }
201
- .siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper ul li {
202
- margin: 0;
203
- }
204
- .siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper ul li:first-child {
205
- border-top-width: 1px;
206
- }
207
- .siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper ul li a {
208
- display: block;
209
- padding: 2px 8px;
210
- text-decoration: none;
211
- color: #666;
212
- font-size: 11px;
213
- outline: 0 !important;
214
- -webkit-box-shadow: none;
215
- -moz-box-shadow: none;
216
- box-shadow: none;
217
- /* Specific drop down hovers */
218
- }
219
- .siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper ul li a:hover {
220
- background: #F0F0F0;
221
- color: #444;
222
- }
223
- .siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper ul li a .dashicons {
224
- font-size: 16px;
225
- margin: 0;
226
- float: right;
227
- line-height: 16px;
228
- }
229
  .siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper ul li a.so-row-delete {
230
  color: #a00;
231
  }
@@ -233,16 +171,6 @@
233
  color: #FFF;
234
  background: #a00;
235
  }
236
- .siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper ul .so-pointer {
237
- width: 12px;
238
- height: 6px;
239
- position: absolute;
240
- z-index: 12;
241
- background: url("images/dropdown-pointer.png");
242
- background-size: 12px 6px;
243
- top: 1px;
244
- right: 18px;
245
- }
246
  .siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper:hover .so-dropdown-links-wrapper {
247
  display: block;
248
  }
@@ -255,7 +183,7 @@
255
  box-sizing: border-box;
256
  }
257
  .siteorigin-panels-builder .so-rows-container .so-row-container {
258
- margin-bottom: 20px;
259
  -webkit-user-select: none;
260
  -moz-user-select: none;
261
  -ms-user-select: none;
@@ -307,7 +235,7 @@
307
  .siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .cell-wrapper {
308
  background: #e4eff4;
309
  border: 1px solid #bcccd2;
310
- padding: 10px 10px 4px 10px;
311
  /* 6px bottom to remove bottom margin from panels */
312
  height: 100%;
313
  min-height: 70px;
@@ -345,11 +273,27 @@
345
  }
346
  .siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget:hover {
347
  border: 1px solid #93a7ad;
348
- background: #feffff;
349
  -webkit-box-shadow: 0 2px 2px rgba(0,0,0,0.075);
350
  -moz-box-shadow: 0 2px 2px rgba(0,0,0,0.075);
351
  box-shadow: 0 2px 2px rgba(0,0,0,0.075);
352
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
353
  .siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget .so-widget-wrapper {
354
  padding: 7px 9px;
355
  overflow: hidden;
@@ -417,10 +361,6 @@
417
  .siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget .form {
418
  display: none;
419
  }
420
- .siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.widget-being-dragged {
421
- opacity: 0.9;
422
- pointer-events: none;
423
- }
424
  .siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget-sortable-highlight {
425
  border: 1px solid;
426
  -ms-box-sizing: border-box;
@@ -515,10 +455,30 @@
515
  color: #777;
516
  font-size: 0.8em;
517
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
518
  /* This is to display a draggable widget */
519
  .so-widget.ui-sortable-helper.widget-being-dragged {
520
  /* Need a high z-index for layout builder widget */
521
  z-index: 500002 !important;
 
 
522
  cursor: move;
523
  margin-bottom: 5px;
524
  background: #f9f9fb;
@@ -534,11 +494,27 @@
534
  }
535
  .so-widget.ui-sortable-helper.widget-being-dragged:hover {
536
  border: 1px solid #93a7ad;
537
- background: #feffff;
538
  -webkit-box-shadow: 0 2px 2px rgba(0,0,0,0.075);
539
  -moz-box-shadow: 0 2px 2px rgba(0,0,0,0.075);
540
  box-shadow: 0 2px 2px rgba(0,0,0,0.075);
541
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
542
  .so-widget.ui-sortable-helper.widget-being-dragged .so-widget-wrapper {
543
  padding: 7px 9px;
544
  overflow: hidden;
@@ -606,10 +582,6 @@
606
  .so-widget.ui-sortable-helper.widget-being-dragged .form {
607
  display: none;
608
  }
609
- .so-widget.ui-sortable-helper.widget-being-dragged.widget-being-dragged {
610
- opacity: 0.9;
611
- pointer-events: none;
612
- }
613
  /* Handles displaying a builder in the WordPress widget interface */
614
  .widgets-holder-wrap .widget-inside .siteorigin-panels-builder .so-builder-container {
615
  padding-top: 0;
@@ -634,7 +606,7 @@
634
  .so-panels-dialog .so-toolbar,
635
  .so-panels-dialog .so-left-sidebar,
636
  .so-panels-dialog .so-right-sidebar {
637
- z-index: 100000;
638
  position: fixed;
639
  -ms-box-sizing: border-box;
640
  -moz-box-sizing: border-box;
@@ -782,6 +754,7 @@
782
  height: 58px;
783
  background-color: #fafafa;
784
  border-top: 1px solid #D8D8D8;
 
785
  }
786
  .so-panels-dialog .so-toolbar .so-status {
787
  float: left;
@@ -805,6 +778,7 @@
805
  margin-top: -0.65em;
806
  }
807
  .so-panels-dialog .so-toolbar .so-buttons .action-buttons a {
 
808
  display: inline;
809
  padding: 0.2em 0.5em;
810
  line-height: 1em;
@@ -1192,62 +1166,6 @@
1192
  padding-left: 10px;
1193
  padding-right: 10px;
1194
  }
1195
- .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .layout {
1196
- -ms-box-sizing: border-box;
1197
- -moz-box-sizing: border-box;
1198
- -webkit-box-sizing: border-box;
1199
- box-sizing: border-box;
1200
- float: left;
1201
- width: 33.333%;
1202
- padding: 0 5px 10px 5px;
1203
- }
1204
- .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .layout .layout-inside {
1205
- padding: 10px 15px;
1206
- cursor: pointer;
1207
- border: 1px solid #cccccc;
1208
- background: #F8F8F8;
1209
- -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.075);
1210
- -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.075);
1211
- box-shadow: 0 1px 2px rgba(0,0,0,0.075);
1212
- }
1213
- .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .layout .layout-inside:hover {
1214
- border: 1px solid #BBBBBB;
1215
- background: #FFFFFF;
1216
- -webkit-box-shadow: 0 2px 2px rgba(0,0,0,0.075);
1217
- -moz-box-shadow: 0 2px 2px rgba(0,0,0,0.075);
1218
- box-shadow: 0 2px 2px rgba(0,0,0,0.075);
1219
- }
1220
- .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .layout .layout-inside h4 {
1221
- font-size: 15px;
1222
- margin: 0;
1223
- line-height: 1.2em;
1224
- height: 1.2em;
1225
- overflow: hidden;
1226
- }
1227
- .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .layout .layout-inside .description {
1228
- line-height: 1.2em;
1229
- height: 1.2em;
1230
- margin-top: 0.7em;
1231
- font-size: 12px;
1232
- color: #888;
1233
- overflow: hidden;
1234
- }
1235
- .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .layout .layout-inside .dashicons {
1236
- display: none;
1237
- float: left;
1238
- margin-top: 10px;
1239
- }
1240
- .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .layout.so-selected .layout-inside {
1241
- border: 1px solid #aaaaaa;
1242
- background: #F2F2F2;
1243
- }
1244
- .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .layout.so-selected .layout-inside h4,
1245
- .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .layout.so-selected .layout-inside .description {
1246
- margin-left: 35px;
1247
- }
1248
- .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .layout.so-selected .layout-inside .dashicons {
1249
- display: inline-block;
1250
- }
1251
  .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-error-message {
1252
  font-size: 14px;
1253
  border: 1px solid #cccccc;
@@ -1268,7 +1186,8 @@
1268
  display: block;
1269
  }
1270
  .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .import-upload-ui p.drag-drop-message {
1271
- font-size: 0.9em;
 
1272
  }
1273
  .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .import-upload-ui .drag-upload-area {
1274
  display: block;
@@ -1355,6 +1274,7 @@
1355
  background: #ffffff;
1356
  margin-bottom: 10px;
1357
  border: 1px solid #d0d0d0;
 
1358
  }
1359
  .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-screenshot.so-loading {
1360
  background-image: url("images/wpspin_light.gif");
@@ -1372,7 +1292,7 @@
1372
  width: 100%;
1373
  height: auto;
1374
  }
1375
- .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-screenshot a {
1376
  display: block;
1377
  min-height: 40px;
1378
  }
@@ -1382,30 +1302,29 @@
1382
  margin-bottom: 10px;
1383
  }
1384
  .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-bottom {
1385
- height: 49px;
1386
  position: relative;
1387
  margin: 10px -10px -15px -10px;
1388
  background: #fcfcfc;
1389
  border-top: 1px solid #d0d0d0;
1390
  }
1391
  .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-bottom .so-title {
1392
- position: absolute;
1393
- top: 1em;
1394
- left: 10px;
1395
- z-index: 1;
1396
  }
1397
  .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-bottom .so-buttons {
1398
  position: absolute;
1399
  z-index: 2;
1400
  top: 0;
 
1401
  right: 0;
 
1402
  visibility: hidden;
1403
  -ms-box-sizing: border-box;
1404
  -moz-box-sizing: border-box;
1405
  -webkit-box-sizing: border-box;
1406
  box-sizing: border-box;
1407
  padding: 11px 10px 10px 15px;
1408
- height: 49px;
1409
  border-left: 1px solid #d0d0d0;
1410
  background: #f6f6f6;
1411
  -webkit-box-shadow: -1px 0 1px rgba(0, 0, 0, 0.05);
@@ -1415,6 +1334,24 @@
1415
  .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item:hover .so-buttons {
1416
  visibility: visible;
1417
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1418
  @media only screen and (min-width: 1680px) {
1419
  .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item {
1420
  width: 20%;
@@ -1454,6 +1391,9 @@
1454
  .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-pages .button-disabled {
1455
  pointer-events: none;
1456
  }
 
 
 
1457
  .so-panels-dialog .so-visual-styles {
1458
  margin: -15px;
1459
  /* All the field types */
@@ -1608,6 +1548,19 @@
1608
  padding-left: 0;
1609
  padding-right: 0;
1610
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
1611
  /* Display the dialog with a proper z-index in the customizer */
1612
  .wp-customizer .so-panels-dialog .so-overlay,
1613
  .wp-customizer .so-panels-dialog .so-content,
@@ -1620,144 +1573,150 @@
1620
  .so-panels-live-editor > div {
1621
  position: fixed;
1622
  z-index: 99999;
 
 
 
 
1623
  }
1624
  .so-panels-live-editor .live-editor-form {
1625
  display: none;
1626
  }
1627
- .so-panels-live-editor .so-overlay {
1628
- top: 0;
1629
- right: 0;
1630
- bottom: 0;
1631
- left: 0;
1632
- background: rgba(0, 0, 0, 0.75);
 
1633
  }
1634
- .so-panels-live-editor .so-sidebar {
1635
- top: 0;
1636
- left: 0;
1637
- bottom: 0;
1638
- width: 260px;
1639
- overflow-y: auto;
1640
- background: #F2F2F2;
1641
- border-right: 1px solid #D0D0D0;
1642
- -ms-box-sizing: border-box;
1643
- -moz-box-sizing: border-box;
1644
- -webkit-box-sizing: border-box;
1645
- box-sizing: border-box;
1646
  }
1647
- .so-panels-live-editor .so-sidebar .so-sidebar-tools {
 
 
1648
  background: #eee;
1649
- border-bottom: 1px solid #ddd;
 
 
 
1650
  }
1651
- .so-panels-live-editor .so-sidebar .so-sidebar-tools .live-editor-close {
1652
- -ms-box-sizing: border-box;
1653
- -moz-box-sizing: border-box;
1654
- -webkit-box-sizing: border-box;
1655
- box-sizing: border-box;
1656
- display: block;
1657
- width: 45px;
1658
- height: 45px;
1659
  background: #eee;
1660
- border-right: 1px solid #ddd;
1661
- color: #444;
1662
- cursor: pointer;
1663
- text-decoration: none;
1664
- position: relative;
1665
- text-align: center;
1666
- padding-top: 12px;
1667
  }
1668
- .so-panels-live-editor .so-sidebar .so-sidebar-tools .live-editor-close:hover {
1669
- background: #FFFFFF;
 
1670
  }
1671
- .so-panels-live-editor .so-sidebar .so-sidebar-tools .live-editor-close:before {
1672
- font: 400 22px/1 dashicons;
1673
- content: "\f341";
1674
- top: 7px;
1675
- left: 13px;
1676
  }
1677
- .so-panels-live-editor .so-sidebar .page-widgets .page-widgets-section .section-header {
 
 
 
1678
  cursor: pointer;
1679
- background: #ffffff;
1680
- padding: 15px 10px;
1681
- border: solid #ddd;
1682
- border-width: 1px 0;
1683
  }
1684
- .so-panels-live-editor .so-sidebar .page-widgets .page-widgets-section .section-header h4 {
1685
- margin: 0;
1686
- font-size: 16px;
1687
  }
1688
- .so-panels-live-editor .so-sidebar .page-widgets .page-widgets-section .section-widgets {
1689
- padding: 10px;
1690
  }
1691
- .so-panels-live-editor .so-sidebar .page-widgets .page-widgets-section:first-child .section-header {
1692
- border-top: 0;
1693
  }
1694
- .so-panels-live-editor .so-sidebar .page-widgets .so-widget {
1695
- border: 1px solid #cccccc;
1696
- cursor: pointer;
1697
- padding: 10px;
1698
- background: #F8F8F8;
1699
- -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.075), inset 0 1px 0 #FFFFFF;
1700
- -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.075), inset 0 1px 0 #FFFFFF;
1701
- box-shadow: 0 1px 2px rgba(0,0,0,0.075), inset 0 1px 0 #FFFFFF;
1702
- margin-bottom: 6px;
1703
  }
1704
- .so-panels-live-editor .so-sidebar .page-widgets .so-widget:hover,
1705
- .so-panels-live-editor .so-sidebar .page-widgets .so-widget.so-hovered {
1706
- -webkit-box-shadow: 0 2px 2px rgba(0,0,0,0.0125), inset 0 1px 0 #FFFFFF;
1707
- -moz-box-shadow: 0 2px 2px rgba(0,0,0,0.0125), inset 0 1px 0 #FFFFFF;
1708
- box-shadow: 0 2px 2px rgba(0,0,0,0.0125), inset 0 1px 0 #FFFFFF;
1709
- border: 1px solid #9bafb5;
1710
- background: #f4f9fd;
1711
  }
1712
- .so-panels-live-editor .so-sidebar .page-widgets .so-widget.so-current {
1713
- border-color: #0074a2;
1714
- background: #2ea2cc;
1715
- cursor: auto;
1716
- -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.15), inset 0 1px 0 rgba(255,255,255,0.2);
1717
- -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.15), inset 0 1px 0 rgba(255,255,255,0.2);
1718
- box-shadow: 0 1px 2px rgba(0,0,0,0.15), inset 0 1px 0 rgba(255,255,255,0.2);
1719
  }
1720
- .so-panels-live-editor .so-sidebar .page-widgets .so-widget.so-current h4 {
1721
- color: #FFFFFF;
 
1722
  }
1723
- .so-panels-live-editor .so-sidebar .page-widgets .so-widget.so-current small {
1724
- color: #eeeeee;
 
 
 
 
 
 
1725
  }
1726
- .so-panels-live-editor .so-sidebar .page-widgets .so-widget.so-current:hover {
1727
- border-color: #0074a2;
1728
- background: #2ea2cc;
 
 
 
 
 
 
 
 
1729
  }
1730
- .so-panels-live-editor .so-sidebar .page-widgets .so-widget:last-child {
1731
- margin-bottom: 0;
 
 
 
1732
  }
1733
- .so-panels-live-editor .so-sidebar .page-widgets .so-widget h4 {
1734
- margin: 0 0 7px 0;
1735
- padding: 0;
1736
- height: 1.2em;
1737
- color: #222222;
1738
- font-size: 14px;
1739
  }
1740
- .so-panels-live-editor .so-sidebar .page-widgets .so-widget .actions {
1741
  display: none;
1742
  }
1743
- .so-panels-live-editor .so-sidebar .page-widgets .so-widget small {
1744
- font-size: 11px;
1745
- line-height: 1.2em;
1746
- height: 1.2em;
1747
- display: block;
1748
- overflow: hidden;
1749
- color: #888888;
1750
  }
1751
- .so-panels-live-editor .so-preview {
1752
- top: 0;
1753
- right: 0;
1754
- bottom: 0;
1755
- left: 260px;
1756
- background: #F4F4F4;
1757
  }
1758
- .so-panels-live-editor .so-preview iframe {
1759
- width: 100%;
1760
- height: 100%;
 
 
1761
  }
1762
  .so-panels-loading {
1763
  background-image: url("images/wpspin_light.gif");
@@ -1923,8 +1882,9 @@
1923
  width: 180px;
1924
  top: 20px;
1925
  left: 20px;
1926
- z-index: 9991;
1927
  display: none;
 
1928
  }
1929
  .so-panels-contextual-menu,
1930
  .so-panels-contextual-menu * {
@@ -1977,8 +1937,82 @@
1977
  background: #F0F0F0;
1978
  color: #444;
1979
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1980
  .so-panels-contextual-menu .so-section .so-no-results {
1981
  padding: 0px 10px 5px 10px;
1982
  display: none;
1983
  font-style: italic;
1984
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  #so-panels-panels.attached-to-editor {
10
  margin-top: 20px;
11
  }
12
+ #so-panels-panels.attached-to-editor .hndle,
13
+ #so-panels-panels.attached-to-editor .handlediv {
14
  display: none !important;
15
  }
16
  #so-panels-panels.attached-to-editor .inside {
26
  /* These are generic iconic buttons used in the page builder interface */
27
  /* Page Builder icons */
28
  }
 
 
 
 
 
29
  .siteorigin-panels-builder .so-tool-button {
30
  padding: 6px 7px;
31
  font-size: 11px;
36
  display: block;
37
  visibility: visible;
38
  position: relative;
39
+ cursor: pointer;
40
  border: 1px solid #C0C0C0;
41
  background: #F0F0F0;
42
  background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #F0F0F0), color-stop(1, #F9F9F9));
73
  border-bottom: 1px solid #D0D0D0;
74
  background: #F5F5F5;
75
  line-height: 1em;
 
76
  z-index: 101;
77
  white-space: nowrap;
78
  overflow-x: hidden;
79
+ position: relative;
80
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
81
  top: 0;
82
  left: 0;
111
  position: absolute;
112
  top: 5px;
113
  right: 10px;
114
+ cursor: pointer;
115
  display: none;
116
  text-decoration: none;
117
  color: #666666;
128
  border: 1px solid #999999;
129
  color: #444444;
130
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  .siteorigin-panels-builder .so-rows-container {
132
  padding: 20px 15px 0 15px;
133
  }
157
  .siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-tool-button.so-row-move {
158
  cursor: move;
159
  }
 
 
 
 
160
  .siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper {
161
  display: none;
162
+ z-index: 101;
 
163
  right: -10px;
 
164
  top: 22px;
165
  width: 125px;
166
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  .siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper .so-dropdown-links-wrapper ul li a.so-row-delete {
168
  color: #a00;
169
  }
171
  color: #FFF;
172
  background: #a00;
173
  }
 
 
 
 
 
 
 
 
 
 
174
  .siteorigin-panels-builder .so-rows-container .so-row-toolbar .so-dropdown-wrapper:hover .so-dropdown-links-wrapper {
175
  display: block;
176
  }
183
  box-sizing: border-box;
184
  }
185
  .siteorigin-panels-builder .so-rows-container .so-row-container {
186
+ margin-bottom: 15px;
187
  -webkit-user-select: none;
188
  -moz-user-select: none;
189
  -ms-user-select: none;
235
  .siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .cell-wrapper {
236
  background: #e4eff4;
237
  border: 1px solid #bcccd2;
238
+ padding: 7px 7px 1px 7px;
239
  /* 6px bottom to remove bottom margin from panels */
240
  height: 100%;
241
  min-height: 70px;
273
  }
274
  .siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget:hover {
275
  border: 1px solid #93a7ad;
276
+ background: #fff;
277
  -webkit-box-shadow: 0 2px 2px rgba(0,0,0,0.075);
278
  -moz-box-shadow: 0 2px 2px rgba(0,0,0,0.075);
279
  box-shadow: 0 2px 2px rgba(0,0,0,0.075);
280
  }
281
+ .siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-hovered {
282
+ background: #3a7096;
283
+ border: 1px solid #39618c;
284
+ -webkit-box-shadow: 0 2px 2px rgba(0,0,0,0.1);
285
+ -moz-box-shadow: 0 2px 2px rgba(0,0,0,0.1);
286
+ box-shadow: 0 2px 2px rgba(0,0,0,0.1);
287
+ }
288
+ .siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-hovered h4,
289
+ .siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-hovered span,
290
+ .siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-hovered small {
291
+ color: #fff;
292
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.85);
293
+ }
294
+ .siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget.so-hovered small {
295
+ color: #eee;
296
+ }
297
  .siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget .so-widget-wrapper {
298
  padding: 7px 9px;
299
  overflow: hidden;
361
  .siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget .form {
362
  display: none;
363
  }
 
 
 
 
364
  .siteorigin-panels-builder .so-rows-container .so-row-container .so-cells .cell .widgets-container .so-widget-sortable-highlight {
365
  border: 1px solid;
366
  -ms-box-sizing: border-box;
455
  color: #777;
456
  font-size: 0.8em;
457
  }
458
+ .siteorigin-panels-builder.so-display-narrow .so-builder-toolbar {
459
+ padding: 10px;
460
+ }
461
+ .siteorigin-panels-builder.so-display-narrow .so-builder-toolbar > .so-tool-button {
462
+ padding-right: 2px;
463
+ }
464
+ .siteorigin-panels-builder.so-display-narrow .so-builder-toolbar > .so-tool-button .so-panels-icon {
465
+ font-size: 14px;
466
+ }
467
+ .siteorigin-panels-builder.so-display-narrow .so-builder-toolbar > .so-tool-button span.so-button-text {
468
+ display: none;
469
+ }
470
+ .siteorigin-panels-builder.so-display-narrow .so-builder-toolbar .so-switch-to-standard {
471
+ display: none !important;
472
+ }
473
+ .siteorigin-panels-builder.so-display-narrow .widgets-container .so-widget .actions {
474
+ display: none !important;
475
+ }
476
  /* This is to display a draggable widget */
477
  .so-widget.ui-sortable-helper.widget-being-dragged {
478
  /* Need a high z-index for layout builder widget */
479
  z-index: 500002 !important;
480
+ opacity: 0.9;
481
+ pointer-events: none;
482
  cursor: move;
483
  margin-bottom: 5px;
484
  background: #f9f9fb;
494
  }
495
  .so-widget.ui-sortable-helper.widget-being-dragged:hover {
496
  border: 1px solid #93a7ad;
497
+ background: #fff;
498
  -webkit-box-shadow: 0 2px 2px rgba(0,0,0,0.075);
499
  -moz-box-shadow: 0 2px 2px rgba(0,0,0,0.075);
500
  box-shadow: 0 2px 2px rgba(0,0,0,0.075);
501
  }
502
+ .so-widget.ui-sortable-helper.widget-being-dragged.so-hovered {
503
+ background: #3a7096;
504
+ border: 1px solid #39618c;
505
+ -webkit-box-shadow: 0 2px 2px rgba(0,0,0,0.1);
506
+ -moz-box-shadow: 0 2px 2px rgba(0,0,0,0.1);
507
+ box-shadow: 0 2px 2px rgba(0,0,0,0.1);
508
+ }
509
+ .so-widget.ui-sortable-helper.widget-being-dragged.so-hovered h4,
510
+ .so-widget.ui-sortable-helper.widget-being-dragged.so-hovered span,
511
+ .so-widget.ui-sortable-helper.widget-being-dragged.so-hovered small {
512
+ color: #fff;
513
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.85);
514
+ }
515
+ .so-widget.ui-sortable-helper.widget-being-dragged.so-hovered small {
516
+ color: #eee;
517
+ }
518
  .so-widget.ui-sortable-helper.widget-being-dragged .so-widget-wrapper {
519
  padding: 7px 9px;
520
  overflow: hidden;
582
  .so-widget.ui-sortable-helper.widget-being-dragged .form {
583
  display: none;
584
  }
 
 
 
 
585
  /* Handles displaying a builder in the WordPress widget interface */
586
  .widgets-holder-wrap .widget-inside .siteorigin-panels-builder .so-builder-container {
587
  padding-top: 0;
606
  .so-panels-dialog .so-toolbar,
607
  .so-panels-dialog .so-left-sidebar,
608
  .so-panels-dialog .so-right-sidebar {
609
+ z-index: 100001;
610
  position: fixed;
611
  -ms-box-sizing: border-box;
612
  -moz-box-sizing: border-box;
754
  height: 58px;
755
  background-color: #fafafa;
756
  border-top: 1px solid #D8D8D8;
757
+ z-index: 100002;
758
  }
759
  .so-panels-dialog .so-toolbar .so-status {
760
  float: left;
778
  margin-top: -0.65em;
779
  }
780
  .so-panels-dialog .so-toolbar .so-buttons .action-buttons a {
781
+ cursor: pointer;
782
  display: inline;
783
  padding: 0.2em 0.5em;
784
  line-height: 1em;
1166
  padding-left: 10px;
1167
  padding-right: 10px;
1168
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1169
  .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-error-message {
1170
  font-size: 14px;
1171
  border: 1px solid #cccccc;
1186
  display: block;
1187
  }
1188
  .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .import-upload-ui p.drag-drop-message {
1189
+ font-size: 1em;
1190
+ margin-bottom: 0;
1191
  }
1192
  .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .import-upload-ui .drag-upload-area {
1193
  display: block;
1274
  background: #ffffff;
1275
  margin-bottom: 10px;
1276
  border: 1px solid #d0d0d0;
1277
+ cursor: pointer;
1278
  }
1279
  .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-screenshot.so-loading {
1280
  background-image: url("images/wpspin_light.gif");
1292
  width: 100%;
1293
  height: auto;
1294
  }
1295
+ .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-screenshot .so-screenshot-wrapper {
1296
  display: block;
1297
  min-height: 40px;
1298
  }
1302
  margin-bottom: 10px;
1303
  }
1304
  .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-bottom {
 
1305
  position: relative;
1306
  margin: 10px -10px -15px -10px;
1307
  background: #fcfcfc;
1308
  border-top: 1px solid #d0d0d0;
1309
  }
1310
  .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-bottom .so-title {
1311
+ margin: 0;
1312
+ padding: 16px 10px;
1313
+ cursor: pointer;
 
1314
  }
1315
  .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item .so-bottom .so-buttons {
1316
  position: absolute;
1317
  z-index: 2;
1318
  top: 0;
1319
+ bottom: 0;
1320
  right: 0;
1321
+ height: 100%;
1322
  visibility: hidden;
1323
  -ms-box-sizing: border-box;
1324
  -moz-box-sizing: border-box;
1325
  -webkit-box-sizing: border-box;
1326
  box-sizing: border-box;
1327
  padding: 11px 10px 10px 15px;
 
1328
  border-left: 1px solid #d0d0d0;
1329
  background: #f6f6f6;
1330
  -webkit-box-shadow: -1px 0 1px rgba(0, 0, 0, 0.05);
1334
  .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item:hover .so-buttons {
1335
  visibility: visible;
1336
  }
1337
+ .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item.selected {
1338
+ background-color: #e5f4fa;
1339
+ }
1340
+ .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item.selected .so-directory-item-wrapper {
1341
+ background: #deeef4;
1342
+ border-color: #9abcc7;
1343
+ }
1344
+ .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item.selected .so-bottom {
1345
+ background: #f8fdff;
1346
+ border-color: #bcccd2;
1347
+ }
1348
+ .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item.selected .so-bottom .so-title {
1349
+ color: #3e484c;
1350
+ }
1351
+ .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item.selected .so-bottom .so-buttons {
1352
+ background: #eaf2f6;
1353
+ border-color: #bcccd2;
1354
+ }
1355
  @media only screen and (min-width: 1680px) {
1356
  .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-items .so-directory-item {
1357
  width: 20%;
1391
  .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-content .so-directory-pages .button-disabled {
1392
  pointer-events: none;
1393
  }
1394
+ .so-panels-dialog.so-panels-dialog-prebuilt-layouts .so-toolbar .so-buttons select.so-layout-position {
1395
+ vertical-align: baseline;
1396
+ }
1397
  .so-panels-dialog .so-visual-styles {
1398
  margin: -15px;
1399
  /* All the field types */
1548
  padding-left: 0;
1549
  padding-right: 0;
1550
  }
1551
+ .so-panels-dialog .so-dropdown-wrapper input[type="button"].button-primary {
1552
+ width: 125px;
1553
+ height: 28px;
1554
+ }
1555
+ .so-panels-dialog .so-dropdown-wrapper .so-dropdown-links-wrapper {
1556
+ display: block;
1557
+ z-index: 11;
1558
+ bottom: 28px;
1559
+ width: 125px;
1560
+ }
1561
+ .so-panels-dialog .so-dropdown-wrapper .so-dropdown-links-wrapper.hidden {
1562
+ display: none;
1563
+ }
1564
  /* Display the dialog with a proper z-index in the customizer */
1565
  .wp-customizer .so-panels-dialog .so-overlay,
1566
  .wp-customizer .so-panels-dialog .so-content,
1573
  .so-panels-live-editor > div {
1574
  position: fixed;
1575
  z-index: 99999;
1576
+ -ms-box-sizing: border-box;
1577
+ -moz-box-sizing: border-box;
1578
+ -webkit-box-sizing: border-box;
1579
+ box-sizing: border-box;
1580
  }
1581
  .so-panels-live-editor .live-editor-form {
1582
  display: none;
1583
  }
1584
+ .so-panels-live-editor .live-editor-collapse {
1585
+ position: fixed;
1586
+ top: 18px;
1587
+ left: 10px;
1588
+ line-height: 1em;
1589
+ cursor: pointer;
1590
+ z-index: 100000;
1591
  }
1592
+ .so-panels-live-editor .live-editor-collapse .collapse-icon {
1593
+ float: left;
1594
+ margin: -4px 6px 0 0;
1595
+ border-radius: 50%;
1596
+ width: 20px;
1597
+ height: 20px;
1598
+ overflow: hidden;
1599
+ -webkit-transition: all 0.25s ease;
1600
+ -moz-transition: all 0.25s ease;
1601
+ -o-transition: all 0.25s ease;
1602
+ transition: all 0.25s ease;
 
1603
  }
1604
+ .so-panels-live-editor .live-editor-collapse .collapse-icon:before {
1605
+ display: block;
1606
+ content: "\f148";
1607
  background: #eee;
1608
+ font: normal 20px/1 dashicons;
1609
+ speak: none;
1610
+ padding: 0;
1611
+ -webkit-font-smoothing: antialiased;
1612
  }
1613
+ .so-panels-live-editor .live-editor-collapse:hover {
1614
+ color: #0073aa;
1615
+ }
1616
+ .so-panels-live-editor .live-editor-collapse:hover .collapse-icon {
1617
+ box-shadow: 0 0 3px rgba(30, 140, 190, 0.8);
1618
+ }
1619
+ .so-panels-live-editor .so-sidebar-tools {
 
1620
  background: #eee;
1621
+ border-bottom: 1px solid #ddd;
1622
+ border-right: 1px solid #D0D0D0;
1623
+ top: 0;
1624
+ left: 0;
1625
+ height: 46px;
1626
+ width: 360px;
 
1627
  }
1628
+ .so-panels-live-editor .so-sidebar-tools .live-editor-close {
1629
+ margin: 9px 10px 0 15px;
1630
+ float: right;
1631
  }
1632
+ .so-panels-live-editor .so-sidebar-tools .live-editor-mode {
1633
+ float: right;
1634
+ margin: 9px 4px 0 0;
 
 
1635
  }
1636
+ .so-panels-live-editor .so-sidebar-tools .live-editor-mode .dashicons {
1637
+ font-size: 30px;
1638
+ width: 30px;
1639
+ height: 30px;
1640
  cursor: pointer;
1641
+ color: #999;
 
 
 
1642
  }
1643
+ .so-panels-live-editor .so-sidebar-tools .live-editor-mode .dashicons:hover {
1644
+ color: #666;
 
1645
  }
1646
+ .so-panels-live-editor .so-sidebar-tools .live-editor-mode.so-active .dashicons {
1647
+ color: #0073aa;
1648
  }
1649
+ .so-panels-live-editor .so-sidebar-tools .live-editor-mode.so-active .dashicons:hover {
1650
+ color: #0073aa;
1651
  }
1652
+ .so-panels-live-editor .so-sidebar {
1653
+ top: 46px;
1654
+ left: 0;
1655
+ bottom: 0;
1656
+ width: 360px;
1657
+ overflow-y: auto;
1658
+ background: #F2F2F2;
1659
+ border-right: 1px solid #D0D0D0;
 
1660
  }
1661
+ .so-panels-live-editor .so-preview {
1662
+ top: 0;
1663
+ right: 0;
1664
+ bottom: 0;
1665
+ left: 360px;
1666
+ background-color: #F4F4F4;
 
1667
  }
1668
+ .so-panels-live-editor .so-preview form {
1669
+ display: none;
 
 
 
 
 
1670
  }
1671
+ .so-panels-live-editor .so-preview iframe {
1672
+ width: 100%;
1673
+ height: 100%;
1674
  }
1675
+ .so-panels-live-editor .so-preview-overlay {
1676
+ display: none;
1677
+ opacity: 0.975;
1678
+ top: 0;
1679
+ right: 0;
1680
+ bottom: 0;
1681
+ left: 360px;
1682
+ background-color: #F4F4F4;
1683
  }
1684
+ .so-panels-live-editor .so-preview-overlay .so-loading-container {
1685
+ opacity: 0.6;
1686
+ position: absolute;
1687
+ top: 50%;
1688
+ width: 200px;
1689
+ padding: 2px;
1690
+ border-radius: 5px;
1691
+ left: 50%;
1692
+ margin-left: -104px;
1693
+ margin-top: -9px;
1694
+ border: 2px solid #aaa;
1695
  }
1696
+ .so-panels-live-editor .so-preview-overlay .so-loading-container .so-loading-bar {
1697
+ width: 50%;
1698
+ border-radius: 3px;
1699
+ height: 10px;
1700
+ background: #aaa;
1701
  }
1702
+ .so-panels-live-editor.so-collapsed .live-editor-collapse .collapse-icon {
1703
+ transform: rotate(180deg);
 
 
 
 
1704
  }
1705
+ .so-panels-live-editor.so-collapsed .so-sidebar-tools {
1706
  display: none;
1707
  }
1708
+ .so-panels-live-editor.so-collapsed .so-sidebar {
1709
+ display: none;
 
 
 
 
 
1710
  }
1711
+ .so-panels-live-editor.so-collapsed .so-preview,
1712
+ .so-panels-live-editor.so-collapsed .so-preview-overlay {
1713
+ left: 0;
 
 
 
1714
  }
1715
+ .so-panels-live-editor.live-editor-mobile-mode .so-preview iframe {
1716
+ max-width: 480px;
1717
+ }
1718
+ .so-panels-live-editor.live-editor-tablet-mode .so-preview iframe {
1719
+ max-width: 768px;
1720
  }
1721
  .so-panels-loading {
1722
  background-image: url("images/wpspin_light.gif");
1882
  width: 180px;
1883
  top: 20px;
1884
  left: 20px;
1885
+ z-index: 999999;
1886
  display: none;
1887
+ overflow-y: auto;
1888
  }
1889
  .so-panels-contextual-menu,
1890
  .so-panels-contextual-menu * {
1937
  background: #F0F0F0;
1938
  color: #444;
1939
  }
1940
+ .so-panels-contextual-menu .so-section ul li.so-confirm {
1941
+ color: #a00;
1942
+ }
1943
+ .so-panels-contextual-menu .so-section ul li.so-confirm:hover,
1944
+ .so-panels-contextual-menu .so-section ul li.so-confirm.so-active {
1945
+ background: #a00;
1946
+ color: #fff;
1947
+ }
1948
+ .so-panels-contextual-menu .so-section ul li .dashicons {
1949
+ width: 12px;
1950
+ height: 12px;
1951
+ font-size: 12px;
1952
+ margin: 0;
1953
+ float: right;
1954
+ line-height: 12px;
1955
+ }
1956
  .so-panels-contextual-menu .so-section .so-no-results {
1957
  padding: 0px 10px 5px 10px;
1958
  display: none;
1959
  font-style: italic;
1960
  }
1961
+ .so-dropdown-wrapper {
1962
+ position: relative;
1963
+ float: right;
1964
+ }
1965
+ .so-dropdown-wrapper .so-dropdown-links-wrapper {
1966
+ position: absolute;
1967
+ padding: 6px 0 0 0;
1968
+ }
1969
+ .so-dropdown-wrapper .so-dropdown-links-wrapper ul {
1970
+ margin: 0;
1971
+ border: 1px solid #C0C0C0;
1972
+ background: #F9F9F9;
1973
+ -webkit-border-radius: 2px;
1974
+ -moz-border-radius: 2px;
1975
+ border-radius: 2px;
1976
+ padding: 4px 0;
1977
+ -webkit-box-shadow: 0 2px 2px rgba(0,0,0,0.1);
1978
+ -moz-box-shadow: 0 2px 2px rgba(0,0,0,0.1);
1979
+ box-shadow: 0 2px 2px rgba(0,0,0,0.1);
1980
+ }
1981
+ .so-dropdown-wrapper .so-dropdown-links-wrapper ul li {
1982
+ margin: 0;
1983
+ }
1984
+ .so-dropdown-wrapper .so-dropdown-links-wrapper ul li:first-child {
1985
+ border-top-width: 1px;
1986
+ }
1987
+ .so-dropdown-wrapper .so-dropdown-links-wrapper ul li a {
1988
+ display: block;
1989
+ padding: 2px 8px;
1990
+ text-decoration: none;
1991
+ color: #666;
1992
+ font-size: 11px;
1993
+ cursor: pointer;
1994
+ outline: 0 !important;
1995
+ -webkit-box-shadow: none;
1996
+ -moz-box-shadow: none;
1997
+ box-shadow: none;
1998
+ }
1999
+ .so-dropdown-wrapper .so-dropdown-links-wrapper ul li a:hover {
2000
+ background: #F0F0F0;
2001
+ color: #444;
2002
+ }
2003
+ .so-dropdown-wrapper .so-dropdown-links-wrapper ul li a .dashicons {
2004
+ font-size: 16px;
2005
+ margin: 0;
2006
+ float: right;
2007
+ line-height: 16px;
2008
+ }
2009
+ .so-dropdown-wrapper .so-dropdown-links-wrapper ul .so-pointer {
2010
+ width: 12px;
2011
+ height: 6px;
2012
+ position: absolute;
2013
+ z-index: 12;
2014
+ background: url("images/dropdown-pointer.png");
2015
+ background-size: 12px 6px;
2016
+ top: 1px;
2017
+ right: 18px;
2018
+ }
css/images/prebuilt-default.png ADDED
Binary file
css/live-editor-front.css ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ .so-panel {
2
+ -webkit-transition-duration: 0.6s !important;
3
+ transition-duration: 0.6s !important;
4
+ }
5
+ .so-panel.so-panels-highlighted {
6
+ opacity: 1 !important;
7
+ }
8
+ .so-panel.so-panels-faded {
9
+ opacity: 0.275 !important;
10
+ }
inc/admin-actions.php CHANGED
@@ -46,102 +46,119 @@ function siteorigin_panels_ajax_widget_form(){
46
  }
47
  add_action('wp_ajax_so_panels_widget_form', 'siteorigin_panels_ajax_widget_form');
48
 
49
- /**
50
- * Admin action for loading a list of prebuilt layouts based on the given type
51
- */
52
- function siteorigin_panels_ajax_prebuilt_layouts(){
53
- if( empty($_REQUEST['type']) ) wp_die();
54
  if( empty( $_REQUEST['_panelsnonce'] ) || !wp_verify_nonce($_REQUEST['_panelsnonce'], 'panels_action') ) wp_die();
55
 
56
  // Get any layouts that the current user could edit.
57
  header('content-type: application/json');
58
 
59
- $return = array();
 
 
60
 
61
- if( $_REQUEST['type'] == 'prebuilt' ) {
62
- // Display the prebuilt layouts that come with the theme.
 
 
 
 
 
 
63
  $layouts = apply_filters( 'siteorigin_panels_prebuilt_layouts', array() );
64
 
65
  foreach($layouts as $id => $vals) {
66
- $return[$id] = array(
67
- 'name' => $vals['name'],
68
- 'description' => isset($vals['description']) ? $vals['description'] : __('No description', 'siteorigin-panels')
69
- );
70
- }
71
 
72
- if( !empty($return) ) {
73
- echo json_encode( $return );
74
- }
75
- else {
76
- $message = '';
77
- $message .= __("Your theme doesn't have any prebuilt layouts.", 'siteorigin-panels') . ' ';
78
- $message .= __("You can still clone existing pages though.", 'siteorigin-panels') . ' ';
79
- echo json_encode( array(
80
- 'error_message' => $message,
81
- ) );
82
  }
83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
 
 
85
  }
86
- elseif( strpos( $_REQUEST['type'], 'clone_' ) === 0 ) {
87
  // Check that the user can view the given page types
88
- $post_type = str_replace('clone_', '', $_REQUEST['type'] );
89
- global $wpdb;
90
 
 
 
 
91
  $user_can_read_private = ( $post_type == 'post' && current_user_can( 'read_private_posts' ) || ( $post_type == 'page' && current_user_can( 'read_private_pages' ) ));
92
  $include_private = $user_can_read_private ? "OR posts.post_status = 'private' " : "";
 
93
  // Select only the posts with the given post type that also have panels_data
94
- $results = $wpdb->get_results( $wpdb->prepare("
95
- SELECT ID, post_title, meta.meta_value
96
  FROM {$wpdb->posts} AS posts
97
  JOIN {$wpdb->postmeta} AS meta ON posts.ID = meta.post_id
98
  WHERE
99
- posts.post_type = %s
100
  AND meta.meta_key = 'panels_data'
 
101
  AND ( posts.post_status = 'publish' OR posts.post_status = 'draft' " . $include_private . ")
102
- ORDER BY post_title
103
- LIMIT 200
104
- ", $post_type ) );
105
 
106
  foreach( $results as $result ) {
107
- $meta_value = unserialize( $result->meta_value );
108
- if( empty($meta_value['widgets']) ) continue;
109
-
110
- // Create the return array
111
- $return[$result->ID] = array(
112
- 'name' => $result->post_title,
113
- 'description' => __('Clone', 'siteorigin-panels')
114
  );
115
  }
116
 
117
- if( !empty($return) ) {
118
- echo json_encode( $return );
119
- }
120
- else {
121
- $type_object = get_post_type_object( $post_type );
122
- if( empty($type_object->labels->name) ) {
123
- $type_name = ucfirst( $post_type );
124
- }
125
- else {
126
- $type_name = $type_object->labels->name;
127
- }
128
-
129
- $message = '';
130
- // TRANSLATORS: Indicate if there are items to clone. %s will be pages, posts, etc.
131
- $message .= sprintf( __("There are no %s with Page Builder content to clone.", 'siteorigin-panels') , $type_name );
132
- echo json_encode( array(
133
- 'error_message' => $message,
134
- ) );
135
- }
136
 
137
  }
138
  else {
139
- // Send back an error
 
 
 
 
 
140
  }
141
 
 
 
142
  wp_die();
143
  }
144
- add_action('wp_ajax_so_panels_prebuilt_layouts', 'siteorigin_panels_ajax_prebuilt_layouts');
145
 
146
  /**
147
  * Ajax handler to get an individual prebuilt layout
@@ -164,10 +181,26 @@ function siteorigin_panels_ajax_get_prebuilt_layout(){
164
  if( isset($layout['name']) ) unset($layout['name']);
165
 
166
  $layout = apply_filters('siteorigin_panels_prebuilt_layout', $layout);
 
167
 
168
  echo json_encode( $layout );
169
  wp_die();
170
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  elseif( current_user_can('edit_post', $_REQUEST['lid']) ) {
172
  $panels_data = get_post_meta( $_REQUEST['lid'], 'panels_data', true );
173
  $panels_data = apply_filters('siteorigin_panels_data', $panels_data);
@@ -175,7 +208,7 @@ function siteorigin_panels_ajax_get_prebuilt_layout(){
175
  wp_die();
176
  }
177
  }
178
- add_action('wp_ajax_so_panels_get_prebuilt_layout', 'siteorigin_panels_ajax_get_prebuilt_layout');
179
 
180
  /**
181
  * Ajax handler to import a layout
@@ -221,64 +254,3 @@ function siteorigin_panels_ajax_directory_enable(){
221
  wp_die();
222
  }
223
  add_action('wp_ajax_so_panels_directory_enable', 'siteorigin_panels_ajax_directory_enable');
224
-
225
- /**
226
- * Query the layout directory for a list of layouts
227
- */
228
- function siteorigin_panels_ajax_directory_query(){
229
- if( empty( $_REQUEST['_panelsnonce'] ) || !wp_verify_nonce($_REQUEST['_panelsnonce'], 'panels_action') ) wp_die();
230
-
231
- $query = array();
232
- if( !empty($_GET['search']) ) {
233
- $query['search'] = urlencode( $_GET['search'] );
234
- }
235
- if( !empty($_GET['page']) ) {
236
- $query['page'] = intval( $_GET['page'] );
237
- }
238
-
239
- // Lets start by contacting the remote server
240
- $url = add_query_arg( $query, SITEORIGIN_PANELS_LAYOUT_URL . '/wp-admin/admin-ajax.php?action=query_layouts');
241
- $response = wp_remote_get( $url );
242
-
243
- if( is_array($response) && $response['response']['code'] == 200 ) {
244
- $results = json_decode( $response['body'] );
245
- if ( empty( $results ) ) {
246
- $results = array();
247
- }
248
-
249
- // For now, we'll just create a pretend list of items
250
- header( 'content-type: application/json' );
251
- echo json_encode( $results );
252
- }
253
- else {
254
- // Display some sort of error message
255
- echo $response->get_error_message();
256
- }
257
- wp_die();
258
- }
259
- add_action('wp_ajax_so_panels_directory_query', 'siteorigin_panels_ajax_directory_query');
260
-
261
- /**
262
- * Query the layout directory for a specific item
263
- */
264
- function siteorigin_panels_ajax_directory_item_json(){
265
- if( empty( $_REQUEST['_panelsnonce'] ) || !wp_verify_nonce($_REQUEST['_panelsnonce'], 'panels_action') ) wp_die();
266
- if( empty( $_REQUEST['layout_slug'] ) ) wp_die();
267
-
268
- $response = wp_remote_get(
269
- SITEORIGIN_PANELS_LAYOUT_URL . '/layout/' . urlencode($_REQUEST['layout_slug']) . '/?action=download'
270
- );
271
-
272
- // var_dump($response['body']);
273
- if( $response['response']['code'] == 200 ) {
274
- // For now, we'll just pretend to load this
275
- header('content-type: application/json');
276
- echo $response['body'];
277
- wp_die();
278
- }
279
- else {
280
- // Display some sort of error message
281
- }
282
-
283
- }
284
- add_action('wp_ajax_so_panels_directory_item', 'siteorigin_panels_ajax_directory_item_json');
46
  }
47
  add_action('wp_ajax_so_panels_widget_form', 'siteorigin_panels_ajax_widget_form');
48
 
49
+
50
+ function siteorigin_panels_ajax_get_prebuilt_layouts(){
 
 
 
51
  if( empty( $_REQUEST['_panelsnonce'] ) || !wp_verify_nonce($_REQUEST['_panelsnonce'], 'panels_action') ) wp_die();
52
 
53
  // Get any layouts that the current user could edit.
54
  header('content-type: application/json');
55
 
56
+ $type = !empty( $_REQUEST['type'] ) ? $_REQUEST['type'] : 'directory';
57
+ $search = !empty($_REQUEST['search']) ? trim( strtolower( $_REQUEST['search'] ) ) : '';
58
+ $page = !empty( $_REQUEST['page'] ) ? intval( $_REQUEST['page'] ) : 1;
59
 
60
+ $return = array(
61
+ 'title' => '',
62
+ 'items' => array()
63
+ );
64
+ if( $type == 'prebuilt' ) {
65
+ $return['title'] = __( 'Theme Defined Layouts', 'siteorigin-panels' );
66
+
67
+ // This is for theme bundled prebuilt directories
68
  $layouts = apply_filters( 'siteorigin_panels_prebuilt_layouts', array() );
69
 
70
  foreach($layouts as $id => $vals) {
71
+ if( !empty($search) && strpos( strtolower($vals['name']), $search ) === false ) {
72
+ continue;
73
+ }
 
 
74
 
75
+ $return['items'][] = array(
76
+ 'title' => $vals['name'],
77
+ 'id' => $id,
78
+ 'type' => 'prebuilt',
79
+ 'description' => isset($vals['description']) ? $vals['description'] : '',
80
+ 'screenshot' => !empty($vals['screenshot']) ? $vals['screenshot'] : ''
81
+ );
 
 
 
82
  }
83
 
84
+ $return['max_num_pages'] = 1;
85
+ }
86
+ elseif( $type == 'directory' ) {
87
+ $return['title'] = __( 'Layouts Directory', 'siteorigin-panels' );
88
+
89
+ // This is a query of the prebuilt layout directory
90
+ $query = array();
91
+ if( !empty($search) ) $query['search'] = $search;
92
+ $query['page'] = $page;
93
+
94
+ $url = add_query_arg( $query, SITEORIGIN_PANELS_LAYOUT_URL . '/wp-admin/admin-ajax.php?action=query_layouts');
95
+ $response = wp_remote_get( $url );
96
+
97
+ if( is_array($response) && $response['response']['code'] == 200 ) {
98
+ $results = json_decode( $response['body'], true );
99
+ if ( !empty( $results ) && !empty($results['items']) ) {
100
+ foreach( $results['items'] as $item ) {
101
+ $item['id'] = $item['slug'];
102
+ $item['screenshot'] = 'http://s.wordpress.com/mshots/v1/' . urlencode( $item['preview'] ) . '?w=400';
103
+ $item['type'] = 'directory';
104
+ $return['items'][] = $item;
105
+ }
106
+ }
107
 
108
+ $return['max_num_pages'] = $results['max_num_pages'];
109
+ }
110
  }
111
+ elseif ( strpos( $type, 'clone_' ) !== false ) {
112
  // Check that the user can view the given page types
113
+ $post_type = str_replace('clone_', '', $type );
 
114
 
115
+ $return['title'] = sprintf( __( 'Clone %s', 'siteorigin-panels' ), esc_html( ucfirst( $post_type ) ) );
116
+
117
+ global $wpdb;
118
  $user_can_read_private = ( $post_type == 'post' && current_user_can( 'read_private_posts' ) || ( $post_type == 'page' && current_user_can( 'read_private_pages' ) ));
119
  $include_private = $user_can_read_private ? "OR posts.post_status = 'private' " : "";
120
+
121
  // Select only the posts with the given post type that also have panels_data
122
+ $results = $wpdb->get_results( "
123
+ SELECT SQL_CALC_FOUND_ROWS DISTINCT ID, post_title, meta.meta_value
124
  FROM {$wpdb->posts} AS posts
125
  JOIN {$wpdb->postmeta} AS meta ON posts.ID = meta.post_id
126
  WHERE
127
+ posts.post_type = '" . esc_sql( $post_type ) . "'
128
  AND meta.meta_key = 'panels_data'
129
+ " . ( !empty($search) ? 'AND posts.post_title LIKE "%' . esc_sql( $search ) . '%"' : '' ) . "
130
  AND ( posts.post_status = 'publish' OR posts.post_status = 'draft' " . $include_private . ")
131
+ ORDER BY post_date DESC
132
+ LIMIT 16 OFFSET " . intval( ( $page - 1 ) * 16 ) );
133
+ $total_posts = $wpdb->get_var( "SELECT FOUND_ROWS();" );
134
 
135
  foreach( $results as $result ) {
136
+ $thumbnail = get_the_post_thumbnail_url( $result->ID, array( 400,300 ) );
137
+ $return['items'][] = array(
138
+ 'id' => $result->ID,
139
+ 'title' => $result->post_title,
140
+ 'type' => $type,
141
+ 'screenshot' => !empty($thumbnail) ? $thumbnail : ''
 
142
  );
143
  }
144
 
145
+ $return['max_num_pages'] = ceil( $total_posts / 16 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
 
147
  }
148
  else {
149
+ // An invalid type. Display an error message.
150
+ }
151
+
152
+ // Add the search part to the title
153
+ if( !empty($search) ) {
154
+ $return['title'] .= __(' - Results For:', 'siteorigin-panels') . ' <em>' . esc_html( $search ) . '</em>';
155
  }
156
 
157
+ echo json_encode( $return );
158
+
159
  wp_die();
160
  }
161
+ add_action('wp_ajax_so_panels_layouts_query', 'siteorigin_panels_ajax_get_prebuilt_layouts');
162
 
163
  /**
164
  * Ajax handler to get an individual prebuilt layout
181
  if( isset($layout['name']) ) unset($layout['name']);
182
 
183
  $layout = apply_filters('siteorigin_panels_prebuilt_layout', $layout);
184
+ $layout = apply_filters('siteorigin_panels_data', $layout);
185
 
186
  echo json_encode( $layout );
187
  wp_die();
188
  }
189
+ if( $_REQUEST['type'] == 'directory' ) {
190
+ $response = wp_remote_get(
191
+ SITEORIGIN_PANELS_LAYOUT_URL . '/layout/' . urlencode($_REQUEST['lid']) . '/?action=download'
192
+ );
193
+
194
+ // var_dump($response['body']);
195
+ if( $response['response']['code'] == 200 ) {
196
+ // For now, we'll just pretend to load this
197
+ echo $response['body'];
198
+ wp_die();
199
+ }
200
+ else {
201
+ // Display some sort of error message
202
+ }
203
+ }
204
  elseif( current_user_can('edit_post', $_REQUEST['lid']) ) {
205
  $panels_data = get_post_meta( $_REQUEST['lid'], 'panels_data', true );
206
  $panels_data = apply_filters('siteorigin_panels_data', $panels_data);
208
  wp_die();
209
  }
210
  }
211
+ add_action('wp_ajax_so_panels_get_layout', 'siteorigin_panels_ajax_get_prebuilt_layout');
212
 
213
  /**
214
  * Ajax handler to import a layout
254
  wp_die();
255
  }
256
  add_action('wp_ajax_so_panels_directory_enable', 'siteorigin_panels_ajax_directory_enable');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
inc/default-styles.php CHANGED
@@ -68,7 +68,7 @@ class SiteOrigin_Panels_Default_Styling {
68
  'name' => __('CSS Styles', 'siteorigin-panels'),
69
  'type' => 'code',
70
  'group' => 'attributes',
71
- 'description' => __('CSS Styles, given as one per row.', 'siteorigin-panels'),
72
  'priority' => 10,
73
  );
74
 
@@ -180,7 +180,7 @@ class SiteOrigin_Panels_Default_Styling {
180
  'name' => __('CSS Styles', 'siteorigin-panels'),
181
  'type' => 'code',
182
  'group' => 'attributes',
183
- 'description' => __('CSS Styles, given as one per row.', 'siteorigin-panels'),
184
  'priority' => 10,
185
  );
186
 
@@ -282,7 +282,12 @@ class SiteOrigin_Panels_Default_Styling {
282
  $attributes['style'] .= 'background-color:' . $args['background']. ';';
283
  }
284
 
285
- if( !empty($args['background_display']) && !empty( $args['background_image_attachment'] ) ) {
 
 
 
 
 
286
  $url = wp_get_attachment_image_src( $args['background_image_attachment'], 'full' );
287
 
288
  if( !empty($url) ) {
@@ -355,6 +360,10 @@ class SiteOrigin_Panels_Default_Styling {
355
  if( !empty($args['background_display']) && !empty( $args['background_image_attachment'] ) ) {
356
  $url = wp_get_attachment_image_src( $args['background_image_attachment'], 'full' );
357
 
 
 
 
 
358
  if( !empty($url) ) {
359
 
360
  if( $args['background_display'] == 'parallax' || $args['background_display'] == 'parallax-original' ) {
68
  'name' => __('CSS Styles', 'siteorigin-panels'),
69
  'type' => 'code',
70
  'group' => 'attributes',
71
+ 'description' => __('One style attribute per line.', 'siteorigin-panels'),
72
  'priority' => 10,
73
  );
74
 
180
  'name' => __('CSS Styles', 'siteorigin-panels'),
181
  'type' => 'code',
182
  'group' => 'attributes',
183
+ 'description' => __('One style attribute per line.', 'siteorigin-panels'),
184
  'priority' => 10,
185
  );
186
 
282
  $attributes['style'] .= 'background-color:' . $args['background']. ';';
283
  }
284
 
285
+ if( !empty( $args['background_display'] ) && !empty( $args['background_image_attachment'] ) ) {
286
+
287
+ if( $args['background_display'] == 'parallax' || $args['background_display'] == 'parallax-original' ) {
288
+ wp_enqueue_script('siteorigin-panels-front-styles');
289
+ }
290
+
291
  $url = wp_get_attachment_image_src( $args['background_image_attachment'], 'full' );
292
 
293
  if( !empty($url) ) {
360
  if( !empty($args['background_display']) && !empty( $args['background_image_attachment'] ) ) {
361
  $url = wp_get_attachment_image_src( $args['background_image_attachment'], 'full' );
362
 
363
+ if( $args['background_display'] == 'parallax' || $args['background_display'] == 'parallax-original' ) {
364
+ wp_enqueue_script('siteorigin-panels-front-styles');
365
+ }
366
+
367
  if( !empty($url) ) {
368
 
369
  if( $args['background_display'] == 'parallax' || $args['background_display'] == 'parallax-original' ) {
inc/live-editor.php CHANGED
@@ -10,8 +10,8 @@
10
  * @return array
11
  */
12
  function siteorigin_panels_live_editor($value, $post_id, $meta_key){
13
- if( $meta_key == 'panels_data' && !empty( $_GET['siteorigin_panels_live_editor'] ) && current_user_can( 'edit_post', $post_id ) && !empty( $_POST['siteorigin_panels_data'] ) ) {
14
- $data = json_decode( wp_unslash( $_POST['siteorigin_panels_data'] ), true );
15
  $value = array( $data );
16
  }
17
 
@@ -19,12 +19,32 @@ function siteorigin_panels_live_editor($value, $post_id, $meta_key){
19
  }
20
  add_action('get_post_metadata', 'siteorigin_panels_live_editor', 10, 3);
21
 
 
 
 
22
  /**
23
- * Hide the admin bar for the live editor
24
- *
25
- * @return bool
26
  */
27
- function siteorigin_panels_live_editor_admin_bar() {
28
- return empty( $_GET['siteorigin_panels_live_editor'] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  }
30
- add_filter('show_admin_bar', 'siteorigin_panels_live_editor_admin_bar');
10
  * @return array
11
  */
12
  function siteorigin_panels_live_editor($value, $post_id, $meta_key){
13
+ if( $meta_key == 'panels_data' && current_user_can( 'edit_post', $post_id ) && !empty( $_POST['live_editor_panels_data'] ) ) {
14
+ $data = json_decode( wp_unslash( $_POST['live_editor_panels_data'] ), true );
15
  $value = array( $data );
16
  }
17
 
19
  }
20
  add_action('get_post_metadata', 'siteorigin_panels_live_editor', 10, 3);
21
 
22
+ // Don't display the admin bar when in live editor mode
23
+ add_filter('show_admin_bar', '__return_false');
24
+
25
  /**
26
+ * Load the frontend scripts for the live editor
 
 
27
  */
28
+ function siteorigin_panels_live_editor_frontend_scripts(){
29
+ wp_enqueue_script(
30
+ 'live-editor-front',
31
+ plugin_dir_url(SITEORIGIN_PANELS_BASE_FILE) . '/js/live-editor/live-editor-front' . SITEORIGIN_PANELS_JS_SUFFIX . '.js',
32
+ array( 'jquery' ),
33
+ SITEORIGIN_PANELS_VERSION
34
+ );
35
+
36
+ wp_enqueue_script(
37
+ 'live-editor-scrollto',
38
+ plugin_dir_url(SITEORIGIN_PANELS_BASE_FILE) . '/js/live-editor/jquery.scrollTo' . SITEORIGIN_PANELS_JS_SUFFIX . '.js',
39
+ array( 'jquery' ),
40
+ SITEORIGIN_PANELS_VERSION
41
+ );
42
+
43
+ wp_enqueue_style(
44
+ 'live-editor-front',
45
+ plugin_dir_url(SITEORIGIN_PANELS_BASE_FILE) . '/css/live-editor-front.css',
46
+ array(),
47
+ SITEORIGIN_PANELS_VERSION
48
+ );
49
  }
50
+ add_action( 'wp_enqueue_scripts', 'siteorigin_panels_live_editor_frontend_scripts' );
js/live-editor/jquery.scrollTo.js ADDED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * jQuery.scrollTo
3
+ * Copyright (c) 2007-2015 Ariel Flesler - aflesler ○ gmail • com | http://flesler.blogspot.com
4
+ * Licensed under MIT
5
+ * http://flesler.blogspot.com/2007/10/jqueryscrollto.html
6
+ * @projectDescription Lightweight, cross-browser and highly customizable animated scrolling with jQuery
7
+ * @author Ariel Flesler
8
+ * @version 2.1.2
9
+ */
10
+ ;(function(factory) {
11
+ 'use strict';
12
+ if (typeof define === 'function' && define.amd) {
13
+ // AMD
14
+ define(['jquery'], factory);
15
+ } else if (typeof module !== 'undefined' && module.exports) {
16
+ // CommonJS
17
+ module.exports = factory(require('jquery'));
18
+ } else {
19
+ // Global
20
+ factory(jQuery);
21
+ }
22
+ })(function($) {
23
+ 'use strict';
24
+
25
+ var $scrollTo = $.scrollTo = function(target, duration, settings) {
26
+ return $(window).scrollTo(target, duration, settings);
27
+ };
28
+
29
+ $scrollTo.defaults = {
30
+ axis:'xy',
31
+ duration: 0,
32
+ limit:true
33
+ };
34
+
35
+ function isWin(elem) {
36
+ return !elem.nodeName ||
37
+ $.inArray(elem.nodeName.toLowerCase(), ['iframe','#document','html','body']) !== -1;
38
+ }
39
+
40
+ $.fn.scrollTo = function(target, duration, settings) {
41
+ if (typeof duration === 'object') {
42
+ settings = duration;
43
+ duration = 0;
44
+ }
45
+ if (typeof settings === 'function') {
46
+ settings = { onAfter:settings };
47
+ }
48
+ if (target === 'max') {
49
+ target = 9e9;
50
+ }
51
+
52
+ settings = $.extend({}, $scrollTo.defaults, settings);
53
+ // Speed is still recognized for backwards compatibility
54
+ duration = duration || settings.duration;
55
+ // Make sure the settings are given right
56
+ var queue = settings.queue && settings.axis.length > 1;
57
+ if (queue) {
58
+ // Let's keep the overall duration
59
+ duration /= 2;
60
+ }
61
+ settings.offset = both(settings.offset);
62
+ settings.over = both(settings.over);
63
+
64
+ return this.each(function() {
65
+ // Null target yields nothing, just like jQuery does
66
+ if (target === null) return;
67
+
68
+ var win = isWin(this),
69
+ elem = win ? this.contentWindow || window : this,
70
+ $elem = $(elem),
71
+ targ = target,
72
+ attr = {},
73
+ toff;
74
+
75
+ switch (typeof targ) {
76
+ // A number will pass the regex
77
+ case 'number':
78
+ case 'string':
79
+ if (/^([+-]=?)?\d+(\.\d+)?(px|%)?$/.test(targ)) {
80
+ targ = both(targ);
81
+ // We are done
82
+ break;
83
+ }
84
+ // Relative/Absolute selector
85
+ targ = win ? $(targ) : $(targ, elem);
86
+ /* falls through */
87
+ case 'object':
88
+ if (targ.length === 0) return;
89
+ // DOMElement / jQuery
90
+ if (targ.is || targ.style) {
91
+ // Get the real position of the target
92
+ toff = (targ = $(targ)).offset();
93
+ }
94
+ }
95
+
96
+ var offset = $.isFunction(settings.offset) && settings.offset(elem, targ) || settings.offset;
97
+
98
+ $.each(settings.axis.split(''), function(i, axis) {
99
+ var Pos = axis === 'x' ? 'Left' : 'Top',
100
+ pos = Pos.toLowerCase(),
101
+ key = 'scroll' + Pos,
102
+ prev = $elem[key](),
103
+ max = $scrollTo.max(elem, axis);
104
+
105
+ if (toff) {// jQuery / DOMElement
106
+ attr[key] = toff[pos] + (win ? 0 : prev - $elem.offset()[pos]);
107
+
108
+ // If it's a dom element, reduce the margin
109
+ if (settings.margin) {
110
+ attr[key] -= parseInt(targ.css('margin'+Pos), 10) || 0;
111
+ attr[key] -= parseInt(targ.css('border'+Pos+'Width'), 10) || 0;
112
+ }
113
+
114
+ attr[key] += offset[pos] || 0;
115
+
116
+ if (settings.over[pos]) {
117
+ // Scroll to a fraction of its width/height
118
+ attr[key] += targ[axis === 'x'?'width':'height']() * settings.over[pos];
119
+ }
120
+ } else {
121
+ var val = targ[pos];
122
+ // Handle percentage values
123
+ attr[key] = val.slice && val.slice(-1) === '%' ?
124
+ parseFloat(val) / 100 * max
125
+ : val;
126
+ }
127
+
128
+ // Number or 'number'
129
+ if (settings.limit && /^\d+$/.test(attr[key])) {
130
+ // Check the limits
131
+ attr[key] = attr[key] <= 0 ? 0 : Math.min(attr[key], max);
132
+ }
133
+
134
+ // Don't waste time animating, if there's no need.
135
+ if (!i && settings.axis.length > 1) {
136
+ if (prev === attr[key]) {
137
+ // No animation needed
138
+ attr = {};
139
+ } else if (queue) {
140
+ // Intermediate animation
141
+ animate(settings.onAfterFirst);
142
+ // Don't animate this axis again in the next iteration.
143
+ attr = {};
144
+ }
145
+ }
146
+ });
147
+
148
+ animate(settings.onAfter);
149
+
150
+ function animate(callback) {
151
+ var opts = $.extend({}, settings, {
152
+ // The queue setting conflicts with animate()
153
+ // Force it to always be true
154
+ queue: true,
155
+ duration: duration,
156
+ complete: callback && function() {
157
+ callback.call(elem, targ, settings);
158
+ }
159
+ });
160
+ $elem.animate(attr, opts);
161
+ }
162
+ });
163
+ };
164
+
165
+ // Max scrolling position, works on quirks mode
166
+ // It only fails (not too badly) on IE, quirks mode.
167
+ $scrollTo.max = function(elem, axis) {
168
+ var Dim = axis === 'x' ? 'Width' : 'Height',
169
+ scroll = 'scroll'+Dim;
170
+
171
+ if (!isWin(elem))
172
+ return elem[scroll] - $(elem)[Dim.toLowerCase()]();
173
+
174
+ var size = 'client' + Dim,
175
+ doc = elem.ownerDocument || elem.document,
176
+ html = doc.documentElement,
177
+ body = doc.body;
178
+
179
+ return Math.max(html[scroll], body[scroll]) - Math.min(html[size], body[size]);
180
+ };
181
+
182
+ function both(val) {
183
+ return $.isFunction(val) || $.isPlainObject(val) ? val : { top:val, left:val };
184
+ }
185
+
186
+ // Add special hooks so that window scroll properties can be animated
187
+ $.Tween.propHooks.scrollLeft =
188
+ $.Tween.propHooks.scrollTop = {
189
+ get: function(t) {
190
+ return $(t.elem)[t.prop]();
191
+ },
192
+ set: function(t) {
193
+ var curr = this.get(t);
194
+ // If interrupt is true and user scrolled, stop animating
195
+ if (t.options.interrupt && t._last && t._last !== curr) {
196
+ return $(t.elem).stop();
197
+ }
198
+ var next = Math.round(t.now);
199
+ // Don't waste CPU
200
+ // Browsers don't render floating point scroll
201
+ if (curr !== next) {
202
+ $(t.elem)[t.prop](next);
203
+ t._last = this.get(t);
204
+ }
205
+ }
206
+ };
207
+
208
+ // AMD requirement
209
+ return $scrollTo;
210
+ });
js/live-editor/jquery.scrollTo.min.js ADDED
@@ -0,0 +1 @@
 
1
+ !function(e){"use strict";"function"==typeof define&&define.amd?define(["jquery"],e):"undefined"!=typeof module&&module.exports?module.exports=e(require("jquery")):e(jQuery)}(function(e){"use strict";function t(t){return!t.nodeName||-1!==e.inArray(t.nodeName.toLowerCase(),["iframe","#document","html","body"])}function o(t){return e.isFunction(t)||e.isPlainObject(t)?t:{top:t,left:t}}var n=e.scrollTo=function(t,o,n){return e(window).scrollTo(t,o,n)};return n.defaults={axis:"xy",duration:0,limit:!0},e.fn.scrollTo=function(r,i,s){"object"==typeof i&&(s=i,i=0),"function"==typeof s&&(s={onAfter:s}),"max"===r&&(r=9e9),s=e.extend({},n.defaults,s),i=i||s.duration;var a=s.queue&&s.axis.length>1;return a&&(i/=2),s.offset=o(s.offset),s.over=o(s.over),this.each(function(){function f(t){var o=e.extend({},s,{queue:!0,duration:i,complete:t&&function(){t.call(l,m,s)}});d.animate(p,o)}if(null!==r){var u,c=t(this),l=c?this.contentWindow||window:this,d=e(l),m=r,p={};switch(typeof m){case"number":case"string":if(/^([+-]=?)?\d+(\.\d+)?(px|%)?$/.test(m)){m=o(m);break}m=c?e(m):e(m,l);case"object":if(0===m.length)return;(m.is||m.style)&&(u=(m=e(m)).offset())}var h=e.isFunction(s.offset)&&s.offset(l,m)||s.offset;e.each(s.axis.split(""),function(e,t){var o="x"===t?"Left":"Top",r=o.toLowerCase(),i="scroll"+o,x=d[i](),v=n.max(l,t);if(u)p[i]=u[r]+(c?0:x-d.offset()[r]),s.margin&&(p[i]-=parseInt(m.css("margin"+o),10)||0,p[i]-=parseInt(m.css("border"+o+"Width"),10)||0),p[i]+=h[r]||0,s.over[r]&&(p[i]+=m["x"===t?"width":"height"]()*s.over[r]);else{var w=m[r];p[i]=w.slice&&"%"===w.slice(-1)?parseFloat(w)/100*v:w}s.limit&&/^\d+$/.test(p[i])&&(p[i]=p[i]<=0?0:Math.min(p[i],v)),!e&&s.axis.length>1&&(x===p[i]?p={}:a&&(f(s.onAfterFirst),p={}))}),f(s.onAfter)}})},n.max=function(o,n){var r="x"===n?"Width":"Height",i="scroll"+r;if(!t(o))return o[i]-e(o)[r.toLowerCase()]();var s="client"+r,a=o.ownerDocument||o.document,f=a.documentElement,u=a.body;return Math.max(f[i],u[i])-Math.min(f[s],u[s])},e.Tween.propHooks.scrollLeft=e.Tween.propHooks.scrollTop={get:function(t){return e(t.elem)[t.prop]()},set:function(t){var o=this.get(t);if(t.options.interrupt&&t._last&&t._last!==o)return e(t.elem).stop();var n=Math.round(t.now);o!==n&&(e(t.elem)[t.prop](n),t._last=this.get(t))}},n});
js/live-editor/live-editor-front.js ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var iframe = window.frameElement;
2
+
3
+ if ( iframe ) {
4
+ iframe.contentDocument = document;
5
+ var windowParent = window.parent;
6
+
7
+ if( typeof windowParent !== 'undefined' && typeof windowParent.jQuery !== 'undefined' ) {
8
+ windowParent.jQuery( iframe ).trigger( "iframeloading" );
9
+ jQuery( function () {
10
+ windowParent.jQuery( iframe ).trigger( "iframeready" );
11
+ } );
12
+ }
13
+ }
14
+
15
+ /**
16
+ * Scroll this window over a specific element. Called by the main live editor.
17
+ * @param el
18
+ */
19
+ function liveEditorScrollTo( el ){
20
+ var $ = jQuery,
21
+ $el = $( el ),
22
+ rect = $el[0].getBoundingClientRect();
23
+
24
+ if( rect.top <= 0 || rect.bottom >= $(window).height() ) {
25
+ var newScrollTop = 0;
26
+
27
+ if( rect.top < 0 || $el.height() >= $( window ).height() * 0.8 ) {
28
+ // Scroll up to the element
29
+ newScrollTop = $( window ).scrollTop() + rect.top - 150;
30
+ } else if( rect.bottom > $(window).height() ) {
31
+ // Scroll down to the element
32
+ newScrollTop = $( window ).scrollTop() + ( rect.bottom - $(window).height() ) + 150;
33
+ }
34
+
35
+ $( window )
36
+ .clearQueue()
37
+ .animate({
38
+ scrollTop: newScrollTop
39
+ }, 450 );
40
+ }
41
+ };
js/live-editor/live-editor-front.min.js ADDED
@@ -0,0 +1 @@
 
1
+ function liveEditorScrollTo(e){var o=jQuery,i=o(e),n=i[0].getBoundingClientRect();if(n.top<=0||n.bottom>=o(window).height()){var t=0;n.top<0||i.height()>=.8*o(window).height()?t=o(window).scrollTop()+n.top-150:n.bottom>o(window).height()&&(t=o(window).scrollTop()+(n.bottom-o(window).height())+150),o(window).clearQueue().animate({scrollTop:t},450)}}var iframe=window.frameElement;if(iframe){iframe.contentDocument=document;var windowParent=window.parent;"undefined"!=typeof windowParent&&"undefined"!=typeof windowParent.jQuery&&(windowParent.jQuery(iframe).trigger("iframeloading"),jQuery(function(){windowParent.jQuery(iframe).trigger("iframeready")}))}
js/siteorigin-panels-23.js DELETED
@@ -1,5306 +0,0 @@
1
- (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
2
- var panels = window.panels;
3
-
4
- module.exports = Backbone.Collection.extend( {
5
- model: panels.model.cell,
6
-
7
- initialize: function(){
8
- },
9
-
10
- /**
11
- * Get the total weight for the cells in this collection.
12
- * @returns {number}
13
- */
14
- totalWeight: function(){
15
- var totalWeight = 0;
16
- this.each(function(cell){
17
- totalWeight += cell.get('weight');
18
- });
19
-
20
- return totalWeight;
21
- }
22
- } );
23
-
24
- },{}],2:[function(require,module,exports){
25
- var panels = window.panels;
26
-
27
- module.exports = Backbone.Collection.extend( {
28
- model: panels.model.historyEntry,
29
-
30
- /**
31
- * The builder model
32
- */
33
- builder: null,
34
-
35
- /**
36
- * The maximum number of items in the history
37
- */
38
- maxSize: 12,
39
-
40
- initialize: function(){
41
- this.on( 'add', this.onAddEntry, this );
42
- },
43
-
44
- /**
45
- * Add an entry to the collection.
46
- *
47
- * @param text The text that defines the action taken to get to this
48
- * @param data
49
- */
50
- addEntry: function(text, data) {
51
-
52
- if(typeof data === 'undefined' || data === null) {
53
- data = this.builder.getPanelsData();
54
- }
55
-
56
- var entry = new panels.model.historyEntry( {
57
- text: text,
58
- data: JSON.stringify( data ),
59
- time: parseInt( new Date().getTime() / 1000 ),
60
- collection: this
61
- } );
62
-
63
- this.add( entry );
64
- },
65
-
66
- /**
67
- * Resize the collection so it's not bigger than this.maxSize
68
- */
69
- onAddEntry: function(entry){
70
-
71
- if(this.models.length > 1) {
72
- var lastEntry = this.at(this.models.length - 2);
73
-
74
- if(
75
- ( entry.get('text') === lastEntry.get('text') && entry.get('time') - lastEntry.get('time') < 15 ) ||
76
- ( entry.get('data') === lastEntry.get('data') )
77
- ) {
78
- // If both entries have the same text and are within 20 seconds of each other, or have the same data, then remove most recent
79
- this.remove( entry );
80
- lastEntry.set( 'count', lastEntry.get('count') + 1 );
81
- }
82
- }
83
-
84
- // Make sure that there are not to many entries in this collection
85
- while( this.models.length > this.maxSize ) {
86
- this.shift();
87
- }
88
- }
89
- } );
90
- },{}],3:[function(require,module,exports){
91
- var panels = window.panels;
92
-
93
- module.exports = Backbone.Collection.extend( {
94
- model: panels.model.row,
95
-
96
- /**
97
- * Destroy all the rows in this collection
98
- */
99
- empty: function(){
100
- var model;
101
- do {
102
- model = this.collection.first();
103
- if( !model ) { break; }
104
-
105
- model.destroy();
106
- } while( true );
107
- }
108
- } );
109
- },{}],4:[function(require,module,exports){
110
- var panels = window.panels;
111
-
112
- module.exports = Backbone.Collection.extend( {
113
- model : panels.model.widget,
114
-
115
- initialize: function(){
116
- }
117
-
118
- } );
119
- },{}],5:[function(require,module,exports){
120
- var panels = window.panels, $ = jQuery;
121
-
122
- module.exports = panels.view.dialog.extend( {
123
- dialogClass : 'so-panels-dialog-add-builder',
124
-
125
- render: function(){
126
- // Render the dialog and attach it to the builder interface
127
- this.renderDialog( this.parseDialogContent( $('#siteorigin-panels-dialog-builder').html(), {} ) );
128
- this.$('.so-content .siteorigin-panels-builder').append( this.builder.$el );
129
- },
130
-
131
- initializeDialog: function(){
132
- var thisView = this;
133
- this.once('open_dialog_complete', function(){
134
- thisView.builder.initSortable();
135
- });
136
-
137
- this.on('open_dialog_complete', function(){
138
- thisView.builder.trigger('builder_resize');
139
- });
140
- }
141
- } );
142
- },{}],6:[function(require,module,exports){
143
- var panels = window.panels, $ = jQuery;
144
-
145
- module.exports = panels.view.dialog.extend( {
146
-
147
- historyEntryTemplate: _.template( $('#siteorigin-panels-dialog-history-entry').html().panelsProcessTemplate() ),
148
-
149
- entries: {},
150
- currentEntry: null,
151
- revertEntry: null,
152
- selectedEntry: null,
153
-
154
- dialogClass: 'so-panels-dialog-history',
155
-
156
- events: {
157
- 'click .so-close': 'closeDialog',
158
- 'click .so-restore': 'restoreSelectedEntry'
159
- },
160
-
161
- initializeDialog: function(){
162
- this.entries = new panels.collection.historyEntries();
163
-
164
- this.on('open_dialog', this.setCurrentEntry, this);
165
- this.on('open_dialog', this.renderHistoryEntries, this);
166
- },
167
-
168
- render: function(){
169
- // Render the dialog and attach it to the builder interface
170
- this.renderDialog( this.parseDialogContent( $('#siteorigin-panels-dialog-history').html(), {} ) );
171
-
172
- this.$('iframe.siteorigin-panels-history-iframe').load(function(){
173
- $(this).show();
174
- });
175
- },
176
-
177
- /**
178
- * Set the original entry. This should be set when creating the dialog.
179
- *
180
- * @param {panels.model.builder} builder
181
- */
182
- setRevertEntry: function(builder){
183
- this.revertEntry = new panels.model.historyEntry( {
184
- data: JSON.stringify( builder.getPanelsData() ),
185
- time: parseInt( new Date().getTime() / 1000 )
186
- } );
187
- },
188
-
189
- /**
190
- * This is triggered when the dialog is opened.
191
- */
192
- setCurrentEntry: function(){
193
- this.currentEntry = new panels.model.historyEntry( {
194
- data: JSON.stringify( this.builder.model.getPanelsData() ),
195
- time: parseInt( new Date().getTime() / 1000 )
196
- } );
197
-
198
- this.selectedEntry = this.currentEntry;
199
- this.previewEntry( this.currentEntry );
200
- this.$('.so-buttons .so-restore').addClass('disabled');
201
- },
202
-
203
- /**
204
- * Render the history entries in the sidebar
205
- */
206
- renderHistoryEntries: function(){
207
- // Set up an interval that will display the time since every 10 seconds
208
- var thisView = this;
209
-
210
- var c = this.$('.history-entries').empty();
211
-
212
- if( this.currentEntry.get('data') !== this.revertEntry.get('data') || this.entries.models.length > 0 ) {
213
- $(this.historyEntryTemplate({title: panelsOptions.loc.history.revert, count: 1}))
214
- .data('historyEntry', this.revertEntry)
215
- .prependTo(c);
216
- }
217
-
218
- // Now load all the entries in this.entries
219
- this.entries.each(function(entry){
220
-
221
- var html = thisView.historyEntryTemplate( {
222
- title: panelsOptions.loc.history[ entry.get('text') ],
223
- count: entry.get('count')
224
- } );
225
-
226
- $( html )
227
- .data('historyEntry', entry)
228
- .prependTo(c);
229
- });
230
-
231
-
232
- $(this.historyEntryTemplate({title: panelsOptions.loc.history['current'], count: 1}))
233
- .data('historyEntry', this.currentEntry)
234
- .addClass('so-selected')
235
- .prependTo(c);
236
-
237
- // Handle loading and selecting
238
- c.find('.history-entry').click(function(){
239
- var $$ = jQuery(this);
240
- c.find('.history-entry').not($$).removeClass('so-selected');
241
- $$.addClass('so-selected');
242
-
243
- var entry = $$.data('historyEntry');
244
-
245
- thisView.selectedEntry = entry;
246
-
247
- if( thisView.selectedEntry.cid !== thisView.currentEntry.cid ) {
248
- thisView.$('.so-buttons .so-restore').removeClass('disabled');
249
- }
250
- else {
251
- thisView.$('.so-buttons .so-restore').addClass('disabled');
252
- }
253
-
254
- thisView.previewEntry( entry );
255
- });
256
-
257
- this.updateEntryTimes();
258
- },
259
-
260
- /**
261
- * Preview an entry
262
- *
263
- * @param entry
264
- */
265
- previewEntry: function(entry){
266
- this.$('iframe.siteorigin-panels-history-iframe').hide();
267
- this.$('form.history-form input[name="siteorigin_panels_data"]').val( entry.get('data') );
268
- this.$('form.history-form').submit();
269
- },
270
-
271
- /**
272
- * Restore the current entry
273
- */
274
- restoreSelectedEntry: function(){
275
-
276
- if( this.$('.so-buttons .so-restore').hasClass('disabled') ) {
277
- return false;
278
- }
279
-
280
- if( this.currentEntry.get('data') === this.selectedEntry.get('data') ) {
281
- this.closeDialog();
282
- return false;
283
- }
284
-
285
- // Add an entry for this restore event
286
- if( this.selectedEntry.get('text') !== 'restore' ) {
287
- this.entries.addEntry( 'restore', this.builder.model.getPanelsData() );
288
- }
289
-
290
- this.builder.model.loadPanelsData( JSON.parse( this.selectedEntry.get('data') ) );
291
-
292
- this.closeDialog();
293
-
294
- return false;
295
- },
296
-
297
- /**
298
- * Update the entry times for the list of entries down the side
299
- */
300
- updateEntryTimes: function(){
301
- var thisView = this;
302
-
303
- this.$('.history-entries .history-entry').each(function(){
304
- var $$ = jQuery(this);
305
-
306
- var time = $$.find('.timesince');
307
- var entry = $$.data('historyEntry');
308
-
309
- time.html( thisView.timeSince( entry.get('time') ) );
310
- });
311
- },
312
-
313
- /**
314
- * Gets the time since as a nice string.
315
- *
316
- * @param date
317
- */
318
- timeSince: function(time){
319
- var diff = parseInt( new Date().getTime() / 1000 ) - time;
320
-
321
- var parts = [];
322
- var interval;
323
-
324
- // There are 3600 seconds in an hour
325
- if( diff > 3600 ) {
326
- interval = Math.floor( diff / 3600 );
327
- if(interval === 1) {
328
- parts.push(panelsOptions.loc.time.hour.replace('%d', interval ));
329
- }
330
- else {
331
- parts.push(panelsOptions.loc.time.hours.replace('%d', interval ));
332
- }
333
- diff -= interval * 3600;
334
- }
335
-
336
- // There are 60 seconds in a minute
337
- if( diff > 60 ) {
338
- interval = Math.floor( diff / 60 );
339
- if(interval === 1) {
340
- parts.push(panelsOptions.loc.time.minute.replace('%d', interval ));
341
- }
342
- else {
343
- parts.push(panelsOptions.loc.time.minutes.replace('%d', interval ));
344
- }
345
- diff -= interval * 60;
346
- }
347
-
348
- if( diff > 0 ) {
349
- if(diff === 1) {
350
- parts.push(panelsOptions.loc.time.second.replace('%d', diff ));
351
- }
352
- else {
353
- parts.push(panelsOptions.loc.time.seconds.replace('%d', diff ));
354
- }
355
- }
356
-
357
- // Return the amount of time ago
358
- return parts.length === 0 ? panelsOptions.loc.time.now : panelsOptions.loc.time.ago.replace('%s', parts.slice(0,2).join(', ') );
359
-
360
- }
361
-
362
- } );
363
- },{}],7:[function(require,module,exports){
364
- var panels = window.panels, $ = jQuery;
365
-
366
- module.exports = panels.view.dialog.extend( {
367
-
368
- entryTemplate : _.template( $('#siteorigin-panels-dialog-prebuilt-entry').html().panelsProcessTemplate() ),
369
- directoryTemplate : _.template( $('#siteorigin-panels-directory-items').html().panelsProcessTemplate() ),
370
-
371
- builder: null,
372
- dialogClass : 'so-panels-dialog-prebuilt-layouts',
373
-
374
- layoutCache : {},
375
- currentTab : false,
376
- directoryPage : 1,
377
-
378
- events: {
379
- 'click .so-close': 'closeDialog',
380
- 'click .so-sidebar-tabs li a' : 'tabClickHandler',
381
- 'click .so-content .layout' : 'layoutClickHandler',
382
- 'keyup .so-sidebar-search' : 'searchHandler',
383
-
384
- // The directory items
385
- 'click .so-content .so-directory-item .so-button-use' : 'directoryClickHandler',
386
- },
387
-
388
- /**
389
- * Initialize the prebuilt dialog.
390
- */
391
- initializeDialog: function(){
392
- var thisView = this;
393
-
394
- this.on('open_dialog', function(){
395
- thisView.$('.so-sidebar-tabs li a').first().click();
396
- thisView.$('.so-status').removeClass('so-panels-loading');
397
- });
398
- },
399
-
400
- /**
401
- * Render the prebuilt layouts dialog
402
- */
403
- render: function(){
404
- this.renderDialog( this.parseDialogContent( $('#siteorigin-panels-dialog-prebuilt').html(), {} ) );
405
- },
406
-
407
- /**
408
- *
409
- * @param e
410
- * @return {boolean}
411
- */
412
- tabClickHandler: function(e){
413
- this.$('.so-sidebar-tabs li').removeClass('tab-active');
414
-
415
- var $$ = jQuery(e.target);
416
- var tab = $$.attr('href').split('#')[1];
417
- $$.parent().addClass( 'tab-active' );
418
-
419
- var thisView = this;
420
-
421
- // Empty everything
422
- this.$('.so-content').empty();
423
-
424
- thisView.currentTab = tab;
425
-
426
- if( tab === 'directory' ) {
427
- this.displayLayoutDirectory();
428
- }
429
- else if( tab === 'import' ) {
430
- // Display the import export
431
- this.displayImportExport();
432
- }
433
- else if( typeof this.layoutCache[tab] === 'undefined' ) {
434
- // We need to load the tab items from the server
435
- this.$('.so-content').addClass('so-panels-loading');
436
-
437
- $.get(
438
- panelsOptions.ajaxurl,
439
- {
440
- action: 'so_panels_prebuilt_layouts',
441
- type: tab
442
- },
443
- function(layouts){
444
- thisView.layoutCache[ tab ] = layouts;
445
-
446
- if( thisView.currentTab === tab ) {
447
- // If the current tab is selected
448
- thisView.$( '.so-content' ).removeClass( 'so-panels-loading' );
449
- thisView.displayLayouts( tab, layouts );
450
- }
451
- }
452
- );
453
- }
454
- else {
455
- thisView.displayLayouts(tab, this.layoutCache[tab]);
456
- }
457
-
458
- thisView.$('.so-sidebar-search').val('');
459
-
460
- return false;
461
- },
462
-
463
- /**
464
- * Display a list of layouts taking into account the search argument
465
- */
466
- displayLayouts: function(type, layouts){
467
- var c = this.$('.so-content').empty();
468
- var query = this.$('.so-sidebar-search').val().toLowerCase();
469
-
470
- if( typeof layouts.error_message !== 'undefined' ) {
471
- this.$('.so-content').append(
472
- $('<div class="so-error-message">').html( layouts.error_message )
473
- );
474
- return;
475
- }
476
-
477
- if( _.size(layouts) ) {
478
- for (var lid in layouts) {
479
- if( layouts.hasOwnProperty(lid) ) {
480
- // Exclude the current post if we have one
481
- if (type !== 'prebuilt' && lid === $('#post_ID').val()) {
482
- continue;
483
- }
484
- if (query !== '' && layouts[lid].name.toLowerCase().indexOf(query) === -1) {
485
- continue;
486
- }
487
-
488
- // Create the layout item to display in the list
489
- var $l = $(this.entryTemplate({
490
- name: layouts[lid].name,
491
- description: layouts[lid].description
492
- }));
493
-
494
- // Create and append the
495
- $l.appendTo(c).data({'type': type, 'lid': lid});
496
- }
497
- }
498
- }
499
- },
500
-
501
- /**
502
- * Make the layout selected.
503
- * @param e
504
- */
505
- layoutClickHandler: function(e){
506
- var layout = $(e.target).closest('.layout');
507
-
508
- this.loadLayout(
509
- layout.data('type'),
510
- layout.data('lid')
511
- );
512
-
513
- return false;
514
- },
515
-
516
- /**
517
- * Load the layout into the main builder
518
- */
519
- loadLayout: function(type, lid){
520
- var thisView = this;
521
-
522
- if( !confirm(panelsOptions.loc.prebuilt_confirm) ) {
523
- return false;
524
- }
525
- this.setStatusMessage(panelsOptions.loc.prebuilt_loading, true);
526
-
527
- $.post(
528
- panelsOptions.ajaxurl,
529
- {
530
- action: 'so_panels_get_prebuilt_layout',
531
- type: type,
532
- lid: lid
533
- },
534
- function(layout){
535
- // TODO check for an error message
536
- thisView.setStatusMessage('', false);
537
- thisView.builder.addHistoryEntry('prebuilt_loaded');
538
-
539
- thisView.builder.model.loadPanelsData(layout);
540
- thisView.closeDialog();
541
- }
542
- );
543
- },
544
-
545
- /**
546
- * Display and setup the import/export form
547
- */
548
- displayImportExport: function(){
549
- var c = this.$( '.so-content').empty().removeClass( 'so-panels-loading' );
550
- c.html( $('#siteorigin-panels-dialog-prebuilt-importexport').html() );
551
-
552
- var thisView = this;
553
- var uploadUi = thisView.$('.import-upload-ui').hide();
554
-
555
- // Create the uploader
556
- var uploader = new plupload.Uploader({
557
- runtimes : 'html5,silverlight,flash,html4',
558
-
559
- browse_button : uploadUi.find('.file-browse-button').get(0),
560
- container : uploadUi.get(0),
561
- drop_element : uploadUi.find('.drag-upload-area').get(0),
562
-
563
- file_data_name : 'panels_import_data',
564
- multiple_queues : false,
565
- max_file_size : panelsOptions.plupload.max_file_size,
566
- url : panelsOptions.plupload.url,
567
- flash_swf_url : panelsOptions.plupload.flash_swf_url,
568
- silverlight_xap_url : panelsOptions.plupload.silverlight_xap_url,
569
- filters : [
570
- { title : panelsOptions.plupload.filter_title, extensions : 'json' }
571
- ],
572
-
573
- multipart_params : {
574
- action : 'so_panels_import_layout'
575
- },
576
-
577
- init: {
578
- PostInit: function(uploader){
579
- if( uploader.features.dragdrop ) {
580
- uploadUi.addClass('has-drag-drop');
581
- }
582
- uploadUi.show().find('.progress-precent').css('width', '0%');
583
- },
584
- FilesAdded: function(uploader){
585
- uploadUi.find('.file-browse-button').blur();
586
- uploadUi.find('.drag-upload-area').removeClass('file-dragover');
587
- uploadUi.find('.progress-bar').fadeIn('fast');
588
- uploader.start();
589
- },
590
- UploadProgress: function(uploader, file){
591
- uploadUi.find('.progress-precent').css('width', file.percent + '%');
592
- },
593
- FileUploaded : function(uploader, file, response){
594
- var layout = JSON.parse( response.response );
595
- if( typeof layout.widgets !== 'undefined' ) {
596
- thisView.builder.addHistoryEntry('prebuilt_loaded');
597
- thisView.builder.model.loadPanelsData(layout);
598
- thisView.closeDialog();
599
- }
600
- else {
601
- alert( panelsOptions.plupload.error_message );
602
- }
603
- },
604
- Error: function(){
605
- alert( panelsOptions.plupload.error_message );
606
- }
607
- }
608
- });
609
- uploader.init();
610
-
611
- // This is
612
- uploadUi.find('.drag-upload-area')
613
- .on('dragover', function(){
614
- $(this).addClass('file-dragover');
615
- })
616
- .on('dragleave', function(){
617
- $(this).removeClass('file-dragover');
618
- });
619
-
620
- // Handle exporting the file
621
- c.find('.so-export').submit( function(e){
622
- var $$ = jQuery(this);
623
- $$.find('input[name="panels_export_data"]').val( JSON.stringify( thisView.builder.model.getPanelsData() ) );
624
- } );
625
-
626
- },
627
-
628
- /**
629
- * Display the layout directory tab.
630
- *
631
- * @param query
632
- */
633
- displayLayoutDirectory: function( search, page ){
634
- var thisView = this;
635
- var c = this.$( '.so-content').empty().addClass('so-panels-loading');
636
-
637
- if( search === undefined ) {
638
- search = '';
639
- }
640
- if( page === undefined ) {
641
- page = 1;
642
- }
643
-
644
- if( !panelsOptions.directory_enabled ) {
645
- // Display the button to enable the prebuilt layout
646
- c.removeClass( 'so-panels-loading' ).html( $('#siteorigin-panels-directory-enable').html() );
647
- c.find('.so-panels-enable-directory').click( function(e){
648
- e.preventDefault();
649
- // Sent the query to enable the directory, then enable the directory
650
- $.get(
651
- panelsOptions.ajaxurl,
652
- { action: 'so_panels_directory_enable' },
653
- function(){
654
-
655
- }
656
- );
657
-
658
- // Enable the layout directory
659
- panelsOptions.directory_enabled = true;
660
- c.addClass( 'so-panels-loading' );
661
- thisView.displayLayoutDirectory( search, page );
662
- } );
663
- return;
664
- }
665
-
666
- // Get all the items for the current query
667
- $.get(
668
- panelsOptions.ajaxurl,
669
- {
670
- action: 'so_panels_directory_query',
671
- search: search,
672
- page: page
673
- },
674
- function( data ){
675
- // Skip this if we're no longer viewing the layout directory
676
- if( thisView.currentTab !== 'directory' ) return;
677
-
678
- // Add the directory items
679
- c.removeClass( 'so-panels-loading').html( thisView.directoryTemplate( data ) );
680
-
681
- // Lets setup the next and previous buttons
682
- var prev = c.find('.so-previous'), next = c.find('.so-next');
683
-
684
- if( page <= 1 ) {
685
- prev.addClass('button-disabled');
686
- }
687
- else {
688
- prev.click(function(e){
689
- e.preventDefault();
690
- thisView.displayLayoutDirectory( search, page - 1 );
691
- });
692
- }
693
- if( page === data.max_num_pages || data.max_num_pages == 0 ) {
694
- next.addClass('button-disabled');
695
- }
696
- else {
697
- next.click(function(e){
698
- e.preventDefault();
699
- thisView.displayLayoutDirectory( search, page + 1 );
700
- });
701
- }
702
-
703
- if( search !== '' ) {
704
- c.find('.so-directory-browse').html( panelsOptions.loc.search_results_header + '"<em>' + _.escape(search) + '</em>"' );
705
- }
706
-
707
- // Handle nice preloading of the screenshots
708
- c.find('.so-screenshot').each( function(){
709
- // Set the initial height
710
- var $$ = jQuery(this), $a = $$.find('a');
711
- $a.css( 'height', ($a.width()/4*3) + 'px' ).addClass('so-loading');
712
-
713
- var $img = $('<img/>').attr('src', $$.data('src')).load(function(){
714
- $a.removeClass('so-loading').css('height', 'auto');
715
- $img.appendTo($a).hide().fadeIn('fast');
716
- });
717
- } );
718
- },
719
- 'json'
720
- );
721
- },
722
-
723
- /**
724
- * Load a particular layout into the builder.
725
- *
726
- * @param id
727
- */
728
- directoryClickHandler: function( e ){
729
- e.preventDefault();
730
- var $$ = jQuery(e.currentTarget), thisView = this;
731
-
732
- if( !confirm(panelsOptions.loc.prebuilt_confirm) ) {
733
- return false;
734
- }
735
- this.setStatusMessage(panelsOptions.loc.prebuilt_loading, true);
736
-
737
- $.get(
738
- panelsOptions.ajaxurl,
739
- {
740
- action: 'so_panels_directory_item',
741
- layout_slug: $$.data('layout-slug')
742
- },
743
- function(layout){
744
-
745
- if( layout.error !== undefined ) {
746
- // There was an error
747
- alert( layout.error );
748
- }
749
- else {
750
- thisView.setStatusMessage('', false);
751
- thisView.builder.addHistoryEntry('prebuilt_loaded');
752
- thisView.builder.model.loadPanelsData(layout);
753
- thisView.closeDialog();
754
- }
755
- }
756
- );
757
- },
758
-
759
- /**
760
- * Handle an update to the search
761
- */
762
- searchHandler: function( e ){
763
- if( this.currentTab !== 'directory' ) {
764
- // This is for the tabs that support live search
765
- if( this.currentTab === false || typeof this.layoutCache[ this.currentTab ] === 'undefined') {
766
- return false;
767
- }
768
- this.displayLayouts(this.currentTab, this.layoutCache[ this.currentTab ] );
769
- }
770
- else if( e.keyCode === 13 ) {
771
- // Refresh the search results
772
- this.displayLayoutDirectory( $(e.currentTarget).val(), 1 );
773
- }
774
- }
775
- } );
776
- },{}],8:[function(require,module,exports){
777
- var panels = window.panels, $ = jQuery;
778
-
779
- module.exports = panels.view.dialog.extend( {
780
-
781
- cellPreviewTemplate : _.template( $('#siteorigin-panels-dialog-row-cell-preview').html().panelsProcessTemplate() ),
782
-
783
- events: {
784
- 'click .so-close': 'closeDialog',
785
-
786
- // Toolbar buttons
787
- 'click .so-toolbar .so-save': 'saveHandler',
788
- 'click .so-toolbar .so-insert': 'insertHandler',
789
- 'click .so-toolbar .so-delete': 'deleteHandler',
790
- 'click .so-toolbar .so-duplicate': 'duplicateHandler',
791
-
792
- // Changing the row
793
- 'change .row-set-form > *': 'setCellsFromForm',
794
- 'click .row-set-form button.set-row': 'setCellsFromForm'
795
- },
796
-
797
- dialogClass : 'so-panels-dialog-row-edit',
798
- styleType : 'row',
799
-
800
- dialogType : 'edit',
801
-
802
- /**
803
- * The current settings, not yet saved to the model
804
- */
805
- row : {
806
- // This is just the cell weights, cell content is not edited by this dialog
807
- cells : [ ],
808
- // The style settings of the row
809
- style : { }
810
- },
811
-
812
- initializeDialog: function(){
813
- this.on('open_dialog', function(){
814
- if( typeof this.model !== 'undefined' && this.model.cells.length !== 0 ) {
815
- this.setRowModel( this.model );
816
- }
817
- else {
818
- this.setRowModel( null );
819
- }
820
-
821
- this.regenerateRowPreview();
822
- }, this);
823
-
824
- // This is the default row layout
825
- this.row = {
826
- cells : [0.5, 0.5],
827
- style : { }
828
- };
829
- },
830
-
831
- /**
832
- *
833
- * @param dialogType Either "edit" or "create"
834
- */
835
- setRowDialogType: function(dialogType){
836
- this.dialogType = dialogType;
837
- },
838
-
839
- /**
840
- * Render the new row dialog
841
- */
842
- render: function(dialogType){
843
- this.renderDialog( this.parseDialogContent( $('#siteorigin-panels-dialog-row').html(), { dialogType: this.dialogType } ) );
844
-
845
- if( this.dialogType === 'edit' ) {
846
- // Now we need to attach the style window
847
- this.styles = new panels.view.styles();
848
- this.styles.model = this.model;
849
- this.styles.render( 'row', $('#post_ID').val(), {
850
- 'builderType' : this.builder.builderType
851
- } );
852
- this.styles.attach( this.$('.so-sidebar.so-right-sidebar') );
853
-
854
- // Handle the loading class
855
- this.styles.on('styles_loaded', function(){
856
- this.$('.so-sidebar.so-right-sidebar').removeClass('so-panels-loading');
857
- }, this);
858
- this.$('.so-sidebar.so-right-sidebar').addClass('so-panels-loading');
859
- }
860
-
861
- if( typeof this.model !== 'undefined' ) {
862
- // Set the initial value of the
863
- this.$('input.so-row-field').val( this.model.cells.length );
864
- }
865
-
866
- var thisView = this;
867
- this.$('input.so-row-field').keyup( function(){
868
- $(this).trigger('change');
869
- } );
870
-
871
- return this;
872
- },
873
-
874
- /**
875
- * Set the row model we'll be using for this dialog.
876
- *
877
- * @param model
878
- */
879
- setRowModel: function(model){
880
- this.model = model;
881
-
882
- if( _.isEmpty( this.model ) ) {
883
- return this;
884
- }
885
-
886
- // Set the rows to be a copy of the model
887
- this.row = {
888
- cells: this.model.cells.map( function(cell){
889
- return cell.get('weight');
890
- } ),
891
- style: { }
892
- };
893
-
894
- // Set the initial value of the cell field.
895
- this.$('input.so-row-field').val( this.model.cells.length );
896
-
897
- return this;
898
- },
899
-
900
- /**
901
- * Regenerate the row preview and resizing interface.
902
- */
903
- regenerateRowPreview: function(){
904
- var thisDialog = this;
905
- var rowPreview = this.$('.row-preview');
906
-
907
- rowPreview.empty();
908
-
909
- var timeout;
910
-
911
- // Represent the cells
912
- _.each(this.row.cells, function(cell, i){
913
- var newCell = $( this.cellPreviewTemplate( { weight: cell } ) );
914
- rowPreview.append( newCell );
915
-
916
- var prevCell = newCell.prev();
917
- var handle;
918
-
919
- if( prevCell.length !== 0 ) {
920
- handle = $('<div class="resize-handle"></div>');
921
- handle
922
- .appendTo( newCell )
923
- .dblclick(function(){
924
- var t = thisDialog.row.cells[i] + thisDialog.row.cells[i-1];
925
- thisDialog.row.cells[i] = thisDialog.row.cells[i-1] = t/2;
926
- thisDialog.scaleRowWidths();
927
- });
928
-
929
- handle.draggable({
930
- axis: 'x',
931
- containment: rowPreview,
932
- start: function(e, ui){
933
-
934
- // Create the clone for the current cell
935
- var newCellClone = newCell.clone().appendTo(ui.helper).css({
936
- position : 'absolute',
937
- top : '0',
938
- width : newCell.outerWidth(),
939
- left : 6,
940
- height: newCell.outerHeight()
941
- });
942
- newCellClone.find('.resize-handle').remove();
943
-
944
- // Create the clone for the previous cell
945
- var prevCellClone = prevCell.clone().appendTo(ui.helper).css({
946
- position : 'absolute',
947
- top : '0',
948
- width : prevCell.outerWidth(),
949
- right : 6,
950
- height: prevCell.outerHeight()
951
- });
952
- prevCellClone.find('.resize-handle').remove();
953
-
954
- $(this).data({
955
- 'newCellClone' : newCellClone,
956
- 'prevCellClone' : prevCellClone
957
- });
958
-
959
- // Hide the
960
- newCell.find('> .preview-cell-in').css('visibility', 'hidden');
961
- prevCell.find('> .preview-cell-in').css('visibility', 'hidden');
962
- },
963
- drag: function(e, ui){
964
- // Calculate the new cell and previous cell widths as a percent
965
- var ncw = thisDialog.row.cells[i] - ( ( ui.position.left + 6 ) / rowPreview.width() );
966
- var pcw = thisDialog.row.cells[i-1] + ( ( ui.position.left + 6 ) / rowPreview.width() );
967
-
968
- var helperLeft = ui.helper.offset().left - rowPreview.offset().left - 6;
969
-
970
- $(this).data('newCellClone').css('width', rowPreview.width() * ncw )
971
- .find('.preview-cell-weight').html( Math.round(ncw*1000)/10 );
972
-
973
- $(this).data('prevCellClone').css('width', rowPreview.width() * pcw )
974
- .find('.preview-cell-weight').html( Math.round(pcw*1000)/10 );
975
- },
976
- stop: function(e, ui){
977
- // Remove the clones
978
- $(this).data('newCellClone').remove();
979
- $(this).data('prevCellClone').remove();
980
-
981
- // Reshow the main cells
982
- newCell.find('.preview-cell-in').css('visibility', 'visible');
983
- prevCell.find('.preview-cell-in').css('visibility', 'visible');
984
-
985
- // Calculate the new cell weights
986
- var offset = ui.position.left + 6;
987
- var percent = offset / rowPreview.width();
988
-
989
- // Ignore this if any of the cells are below 2% in width.
990
- if( thisDialog.row.cells[i] - percent > 0.02 && thisDialog.row.cells[i-1] + percent > 0.02 ) {
991
- thisDialog.row.cells[i] -= percent;
992
- thisDialog.row.cells[i-1] += percent;
993
- }
994
-
995
- thisDialog.scaleRowWidths();
996
- ui.helper.css('left', -6);
997
- }
998
- });
999
- }
1000
-
1001
- // Make this row weight click editable
1002
- newCell.find('.preview-cell-weight').click(function(ci){
1003
-
1004
- // Disable the draggable while entering values
1005
- thisDialog.$('.resize-handle').css('pointer-event', 'none').draggable('disable');
1006
-
1007
- rowPreview.find('.preview-cell-weight').each( function(){
1008
- var $$ = jQuery(this).hide();
1009
- $('<input type="text" class="preview-cell-weight-input no-user-interacted" />')
1010
- .val( parseFloat( $$.html() ) ).insertAfter( $$ )
1011
- .focus( function(){
1012
- clearTimeout( timeout );
1013
- } )
1014
- .keyup(function(e){
1015
- if(e.keyCode !== 9) {
1016
- // Only register the interaction if the user didn't press tab
1017
- $(this).removeClass('no-user-interacted');
1018
- }
1019
-
1020
- // Enter is clicked
1021
- if(e.keyCode === 13){
1022
- e.preventDefault();
1023
- $(this).blur();
1024
- }
1025
- })
1026
- .keydown(function(e){
1027
- if(e.keyCode === 9){
1028
- e.preventDefault();
1029
-
1030
- // Tab will always cycle around the row inputs
1031
- var inputs = rowPreview.find( '.preview-cell-weight-input');
1032
- var i = inputs.index( $(this) );
1033
- if( i === inputs.length - 1 ) {
1034
- inputs.eq(0).focus().select();
1035
- }
1036
- else {
1037
- inputs.eq(i+1).focus().select();
1038
- }
1039
- }
1040
- })
1041
- .blur( function(){
1042
- rowPreview.find( '.preview-cell-weight-input' ).each(function(i, el){
1043
- if( isNaN( parseFloat( $(el).val() ) ) ) {
1044
- $(el).val( Math.floor(thisDialog.row.cells[i] * 1000)/10 );
1045
- }
1046
- });
1047
-
1048
- timeout = setTimeout( function(){
1049
- // If there are no weight inputs, then skip this
1050
- if( rowPreview.find( '.preview-cell-weight-input').length === 0 ) {
1051
- return false;
1052
- }
1053
-
1054
- // Go through all the inputs
1055
- var rowWeights = [],
1056
- rowChanged = [],
1057
- changedSum = 0,
1058
- unchangedSum = 0;
1059
-
1060
- rowPreview.find( '.preview-cell-weight-input' ).each(function(i, el){
1061
- var val = parseFloat( $(el).val() );
1062
- if( isNaN(val) ) {
1063
- val = 1 / thisDialog.row.cells.length;
1064
- }
1065
- else {
1066
- val = Math.round(val*10) / 1000;
1067
- }
1068
-
1069
- // Check within 3 decimal points
1070
- var changed = ! $(el).hasClass('no-user-interacted');
1071
-
1072
- rowWeights.push( val );
1073
- rowChanged.push( changed );
1074
-
1075
- if( changed ) {
1076
- changedSum += val;
1077
- }
1078
- else{
1079
- unchangedSum += val;
1080
- }
1081
- } );
1082
-
1083
- if ( changedSum > 0 && unchangedSum > 0 && ( 1 - changedSum ) > 0 ) {
1084
- // Balance out the unchanged rows to occupy the weight left over by the changed sum
1085
- for( var i = 0; i < rowWeights.length; i++ ) {
1086
- if( !rowChanged[i] ) {
1087
- rowWeights[i] = ( rowWeights[i] / unchangedSum ) * ( 1 - changedSum );
1088
- }
1089
- }
1090
- }
1091
-
1092
- // Last check to ensure total weight is 1
1093
- var sum = _.reduce( rowWeights, function(memo, num){ return memo + num; } );
1094
- rowWeights = rowWeights.map( function(w){ return w/sum; } );
1095
-
1096
- // Set the new cell weights and regenerate the preview.
1097
- if( Math.min.apply(Math, rowWeights) > 0.01 ) {
1098
- thisDialog.row.cells = rowWeights;
1099
- }
1100
-
1101
- // Now lets animate the cells into their new widths
1102
- rowPreview.find( '.preview-cell').each(function(i, el){
1103
- $(el).animate({ 'width': Math.round(thisDialog.row.cells[i]*1000)/10 + "%"}, 250 );
1104
- $(el).find('.preview-cell-weight-input').val( Math.round(thisDialog.row.cells[i]*1000)/10 );
1105
- });
1106
-
1107
- // So the draggable handle is not hidden.
1108
- rowPreview.find( '.preview-cell').css('overflow', 'visible');
1109
-
1110
- setTimeout(function(){
1111
- thisDialog.regenerateRowPreview();
1112
- }, 260);
1113
-
1114
- }, 100 );
1115
- } )
1116
- .click( function(){
1117
- $(this).select();
1118
- } );
1119
- } );
1120
-
1121
- $(this).siblings('.preview-cell-weight-input').select();
1122
-
1123
- });
1124
-
1125
- }, this);
1126
- },
1127
-
1128
- /**
1129
- * Visually scale the row widths based on the cell weights
1130
- */
1131
- scaleRowWidths: function(){
1132
- var thisDialog = this;
1133
- this.$('.row-preview .preview-cell').each(function(i, el){
1134
- $(el)
1135
- .css('width', thisDialog.row.cells[i] * 100 + "%")
1136
- .find('.preview-cell-weight').html( Math.round( thisDialog.row.cells[i] * 1000 )/10 );
1137
- });
1138
- },
1139
-
1140
- /**
1141
- * Get the weights from the
1142
- */
1143
- setCellsFromForm: function(){
1144
- var f = {
1145
- 'cells' : parseInt( this.$el.find('.row-set-form input[name="cells"]').val() ),
1146
- 'ratio' : parseFloat( this.$el.find('.row-set-form select[name="ratio"]').val() ),
1147
- 'direction' : this.$el.find('.row-set-form select[name="ratio_direction"]').val()
1148
- };
1149
- var cells = [];
1150
-
1151
- // Ignore this if the ratio or cell count is NaN
1152
- if( isNaN(f.cells) || isNaN(f.ratio) ) {
1153
- return false;
1154
- }
1155
-
1156
- var cellCountChanged = ( this.row.cells.length !== f.cells );
1157
-
1158
- if( f.cells < 1 ) {
1159
- this.$el.find('.row-set-form input[name="cells"]').val(1);
1160
- f.cells = 1;
1161
- }
1162
- else if (f.cells > 20) {
1163
- this.$el.find('.row-set-form input[name="cells"]').val(20);
1164
- f.cells = 20;
1165
- }
1166
-
1167
- // Now, lets create some cells
1168
- var currentWeight = 1;
1169
- for( var i = 0; i < f.cells; i++ ) {
1170
- cells.push (currentWeight);
1171
- currentWeight *= f.ratio;
1172
- }
1173
-
1174
- // Now lets make sure that the row weights add up to 1
1175
-
1176
- var totalRowWeight = _.reduce( cells, function(memo, weight){ return memo + weight; });
1177
- cells = _.map(cells, function(cell){
1178
- return cell/totalRowWeight;
1179
- });
1180
-
1181
- // Don't return cells that are too small
1182
- cells = _.filter(cells, function(cell){
1183
- return cell > 0.01;
1184
- });
1185
-
1186
- if(f.direction === 'left') {
1187
- cells = cells.reverse();
1188
- }
1189
-
1190
- this.row.cells = cells;
1191
-
1192
- if( cellCountChanged ) {
1193
- this.regenerateRowPreview();
1194
- }
1195
- else {
1196
- var thisDialog = this;
1197
-
1198
- // Now lets animate the cells into their new widths
1199
- this.$el.find( '.preview-cell').each(function(i, el){
1200
- $(el).animate({ 'width': Math.round(thisDialog.row.cells[i]*1000)/10 + "%"}, 250 );
1201
- $(el).find('.preview-cell-weight').html( Math.round(thisDialog.row.cells[i]*1000)/10 );
1202
- });
1203
-
1204
- // So the draggable handle is not hidden.
1205
- this.$el.find( '.preview-cell').css('overflow', 'visible');
1206
-
1207
- setTimeout(function(){
1208
- thisDialog.regenerateRowPreview();
1209
- }, 260);
1210
- }
1211
-
1212
-
1213
- // Remove the button primary class
1214
- this.$el.find('.row-set-form .so-button-row-set').removeClass('button-primary');
1215
- },
1216
-
1217
- /**
1218
- * Handle a click on the dialog left bar tab
1219
- */
1220
- tabClickHandler : function($t){
1221
- if($t.attr('href') === '#row-layout') {
1222
- this.$('.so-panels-dialog').addClass('so-panels-dialog-has-right-sidebar');
1223
- }
1224
- else {
1225
- this.$('.so-panels-dialog').removeClass('so-panels-dialog-has-right-sidebar');
1226
- }
1227
- },
1228
-
1229
- /**
1230
- * Update the current model with what we have in the dialog
1231
- */
1232
- updateModel: function(){
1233
- // Set the cells
1234
- this.model.setCells( this.row.cells );
1235
-
1236
- // Update the styles if they've loaded
1237
- if ( typeof this.styles !== 'undefined' && this.styles.stylesLoaded ) {
1238
- // This is an edit dialog, so there are styles
1239
- var style = {};
1240
- try {
1241
- style = this.getFormValues('.so-sidebar .so-visual-styles').style;
1242
- }
1243
- catch( e ) { }
1244
-
1245
- this.model.set('style', style);
1246
- }
1247
- },
1248
-
1249
- /**
1250
- * Insert the new row
1251
- */
1252
- insertHandler: function(){
1253
- this.builder.addHistoryEntry('row_added');
1254
-
1255
- this.model = new panels.model.row();
1256
- this.updateModel();
1257
-
1258
- var activeCell = this.builder.getActiveCell({
1259
- createCell: false,
1260
- defaultPosition: 'last'
1261
- });
1262
-
1263
- var options = {};
1264
- if( activeCell !== null ) {
1265
- options.at = this.builder.model.rows.indexOf( activeCell.row ) + 1;
1266
- }
1267
-
1268
- // Set up the model and add it to the builder
1269
- this.model.collection = this.builder.model.rows;
1270
- this.builder.model.rows.add( this.model, options );
1271
-
1272
- this.closeDialog();
1273
-
1274
- return false;
1275
- },
1276
-
1277
- /**
1278
- * We'll just save this model and close the dialog
1279
- */
1280
- saveHandler: function(){
1281
- this.builder.addHistoryEntry('row_edited');
1282
- this.updateModel();
1283
- this.closeDialog();
1284
-
1285
- return false;
1286
- },
1287
-
1288
- /**
1289
- * The user clicks delete, so trigger deletion on the row model
1290
- */
1291
- deleteHandler: function(){
1292
- // Trigger a destroy on the model that will happen with a visual indication to the user
1293
- this.model.trigger('visual_destroy');
1294
- this.closeDialog();
1295
-
1296
- return false;
1297
- },
1298
-
1299
- /**
1300
- * Duplicate this row
1301
- */
1302
- duplicateHandler: function(){
1303
- this.builder.addHistoryEntry('row_duplicated');
1304
-
1305
- var duplicateRow = this.model.clone( this.builder.model );
1306
-
1307
- this.builder.model.rows.add( duplicateRow, {
1308
- at: this.builder.model.rows.indexOf( this.model ) + 1
1309
- } );
1310
-
1311
- this.closeDialog();
1312
-
1313
- return false;
1314
- }
1315
-
1316
- } );
1317
- },{}],9:[function(require,module,exports){
1318
- var panels = window.panels, $ = jQuery;
1319
-
1320
- module.exports = panels.view.dialog.extend( {
1321
-
1322
- builder: null,
1323
- sidebarWidgetTemplate: _.template( $('#siteorigin-panels-dialog-widget-sidebar-widget').html().panelsProcessTemplate() ),
1324
- dialogClass : 'so-panels-dialog-edit-widget',
1325
- widgetView : false,
1326
- savingWidget: false,
1327
-
1328
- events: {
1329
- 'click .so-close': 'saveHistory',
1330
- 'click .so-nav.so-previous': 'navToPrevious',
1331
- 'click .so-nav.so-next': 'navToNext',
1332
-
1333
- // Action handlers
1334
- 'click .so-toolbar .so-delete': 'deleteHandler',
1335
- 'click .so-toolbar .so-duplicate': 'duplicateHandler'
1336
- },
1337
-
1338
- initializeDialog: function(){
1339
- this.model.on( 'change:values', this.handleChangeValues, this );
1340
- this.model.on( 'destroy', this.remove, this );
1341
- },
1342
-
1343
- /**
1344
- * Render the widget dialog.
1345
- */
1346
- render: function() {
1347
- // Render the dialog and attach it to the builder interface
1348
- this.renderDialog( this.parseDialogContent( $('#siteorigin-panels-dialog-widget').html(), {} ) );
1349
- this.loadForm();
1350
-
1351
- if( typeof panelsOptions.widgets[ this.model.get('class') ] !== 'undefined') {
1352
- this.$('.so-title .widget-name').html( panelsOptions.widgets[ this.model.get('class')].title );
1353
- }
1354
- else {
1355
- this.$('.so-title .widget-name').html( panelsOptions.loc.missing_widget.title );
1356
- }
1357
-
1358
- // Now we need to attach the style window
1359
- this.styles = new panels.view.styles();
1360
- this.styles.model = this.model;
1361
- this.styles.render( 'widget', $('#post_ID').val(), {
1362
- builderType : this.builder.builderType
1363
- } );
1364
- this.styles.attach( this.$('.so-sidebar.so-right-sidebar') );
1365
-
1366
- // Handle the loading class
1367
- this.styles.on('styles_loaded', function(){
1368
- this.$('.so-sidebar.so-right-sidebar').removeClass('so-panels-loading');
1369
- }, this);
1370
- this.$('.so-sidebar.so-right-sidebar').addClass('so-panels-loading');
1371
- },
1372
-
1373
- /**
1374
- * Get the previous widget editing dialog by looking at the dom.
1375
- * @returns {*}
1376
- */
1377
- getPrevDialog: function(){
1378
- var widgets = this.builder.$('.so-cells .cell .so-widget');
1379
- if(widgets.length <= 1) {
1380
- return false;
1381
- }
1382
- var currentIndex = widgets.index( this.widgetView.$el );
1383
-
1384
- if( currentIndex === 0 ) {
1385
- return false;
1386
- }
1387
- else {
1388
- var widgetView = widgets.eq(currentIndex - 1).data('view');
1389
- if(typeof widgetView === 'undefined') {
1390
- return false;
1391
- }
1392
-
1393
- return widgetView.getEditDialog();
1394
- }
1395
- },
1396
-
1397
- /**
1398
- * Get the next widget editing dialog by looking at the dom.
1399
- * @returns {*}
1400
- */
1401
- getNextDialog: function(){
1402
- var widgets = this.builder.$('.so-cells .cell .so-widget');
1403
- if(widgets.length <= 1) {
1404
- return false;
1405
- }
1406
- var currentIndex = widgets.index( this.widgetView.$el );
1407
-
1408
- if( currentIndex === widgets.length - 1 ) {
1409
- return false;
1410
- }
1411
- else {
1412
- var widgetView = widgets.eq(currentIndex + 1).data('view');
1413
- if(typeof widgetView === 'undefined') {
1414
- return false;
1415
- }
1416
-
1417
- return widgetView.getEditDialog();
1418
- }
1419
- },
1420
-
1421
- /**
1422
- * Load the widget form from the server.
1423
- * This is called when rendering the dialog for the first time.
1424
- */
1425
- loadForm: function(){
1426
- // don't load the form if this dialog hasn't been rendered yet
1427
- if( !this.$el.find('> *').length ) {
1428
- return;
1429
- }
1430
-
1431
- var thisView = this;
1432
- this.$el.find('.so-content').addClass('so-panels-loading');
1433
-
1434
- var data = {
1435
- 'action' : 'so_panels_widget_form',
1436
- 'widget' : this.model.get('class'),
1437
- 'instance' : JSON.stringify( this.model.get('values') ),
1438
- 'raw' : this.model.get('raw')
1439
- };
1440
-
1441
- $.post(
1442
- panelsOptions.ajaxurl,
1443
- data,
1444
- function(result){
1445
- // Add in the CID of the widget model
1446
- var html = result.replace( /{\$id}/g, thisView.model.cid );
1447
-
1448
- // Load this content into the form
1449
- thisView.$el.find('.so-content')
1450
- .removeClass('so-panels-loading')
1451
- .html(html);
1452
-
1453
- // Trigger all the necessary events
1454
- thisView.trigger('form_loaded', thisView);
1455
-
1456
- // For legacy compatibility, trigger a panelsopen event
1457
- thisView.$el.find('.panel-dialog').trigger('panelsopen');
1458
-
1459
- // If the main dialog is closed from this point on, save the widget content
1460
- thisView.on('close_dialog', thisView.saveWidget, thisView);
1461
- },
1462
- 'html'
1463
- );
1464
- },
1465
-
1466
- /**
1467
- * Save the widget from the form to the model
1468
- */
1469
- saveWidget: function(){
1470
- // Get the values from the form and assign the new values to the model
1471
- this.savingWidget = true;
1472
-
1473
- if( !this.model.get('missing') ) {
1474
- // Only get the values for non missing widgets.
1475
- var values = this.getFormValues();
1476
- if (typeof values.widgets === 'undefined') {
1477
- values = {};
1478
- }
1479
- else {
1480
- values = values.widgets;
1481
- values = values[Object.keys(values)[0]];
1482
- }
1483
-
1484
- this.model.setValues(values);
1485
- this.model.set('raw', true); // We've saved from the widget form, so this is now raw
1486
- }
1487
-
1488
- if( this.styles.stylesLoaded ) {
1489
- // If the styles view has loaded
1490
- var style = {};
1491
- try {
1492
- style = this.getFormValues('.so-sidebar .so-visual-styles').style;
1493
- }
1494
- catch (e) {
1495
- }
1496
- this.model.set('style', style);
1497
- }
1498
-
1499
- this.savingWidget = false;
1500
- },
1501
-
1502
- /**
1503
- *
1504
- */
1505
- handleChangeValues: function(){
1506
- if( !this.savingWidget ) {
1507
- // Reload the form when we've changed the model and we're not currently saving from the form
1508
- this.loadForm();
1509
- }
1510
- },
1511
-
1512
- /**
1513
- * Save a history entry for this widget. Called when the dialog is closed.
1514
- */
1515
- saveHistory: function(){
1516
- this.builder.addHistoryEntry('widget_edited');
1517
- this.closeDialog();
1518
- },
1519
-
1520
- /**
1521
- * When the user clicks delete.
1522
- *
1523
- * @returns {boolean}
1524
- */
1525
- deleteHandler: function(){
1526
-
1527
- if(this.builder.liveEditor.displayed) {
1528
- // We need to instantly destroy the widget
1529
- this.model.destroy();
1530
- this.builder.liveEditor.refreshWidgets();
1531
- }
1532
- else {
1533
- this.model.trigger('visual_destroy');
1534
- }
1535
-
1536
- this.closeDialog();
1537
-
1538
- return false;
1539
- },
1540
-
1541
- duplicateHandler: function(){
1542
- this.model.trigger('user_duplicate');
1543
-
1544
- if(this.builder.liveEditor.displayed) {
1545
- this.builder.liveEditor.refreshWidgets();
1546
- }
1547
-
1548
- this.closeDialog();
1549
-
1550
- return false;
1551
- }
1552
-
1553
- } );
1554
- },{}],10:[function(require,module,exports){
1555
- var panels = window.panels, $ = jQuery;
1556
-
1557
- module.exports = panels.view.dialog.extend( {
1558
-
1559
- builder: null,
1560
- widgetTemplate: _.template( $('#siteorigin-panels-dialog-widgets-widget').html().panelsProcessTemplate() ),
1561
- filter: {},
1562
-
1563
- dialogClass : 'so-panels-dialog-add-widget',
1564
-
1565
- events: {
1566
- 'click .so-close': 'closeDialog',
1567
- 'click .widget-type' : 'widgetClickHandler',
1568
- 'keyup .so-sidebar-search' : 'searchHandler'
1569
- },
1570
-
1571
- /**
1572
- * Initialize the widget adding dialog
1573
- */
1574
- initializeDialog: function(){
1575
-
1576
- this.on('open_dialog', function(){
1577
- this.filter.search = '';
1578
- this.filterWidgets( this.filter );
1579
- }, this);
1580
-
1581
- this.on('open_dialog_complete', function(){
1582
- // Clear the search and re-filter the widgets when we open the dialog
1583
- this.$('.so-sidebar-search').val('').focus();
1584
- this.balanceWidgetHeights();
1585
- });
1586
-
1587
- // We'll implement a custom tab click handler
1588
- this.on('tab_click', this.tabClickHandler, this);
1589
- },
1590
-
1591
- render: function(){
1592
- // Render the dialog and attach it to the builder interface
1593
- this.renderDialog( this.parseDialogContent( $('#siteorigin-panels-dialog-widgets').html(), {} ) );
1594
-
1595
- // Add all the widgets
1596
- _.each( panelsOptions.widgets, function( widget ){
1597
- var $w = $( this.widgetTemplate( {
1598
- title : widget.title,
1599
- description : widget.description
1600
- } ) ) ;
1601
-
1602
- if(typeof widget.icon === 'undefined') {
1603
- widget.icon = 'dashicons dashicons-admin-generic';
1604
- }
1605
-
1606
- if( typeof widget.icon !== 'undefined' ){
1607
- $('<span class="widget-icon" />').addClass( widget.icon ).prependTo( $w.find('.widget-type-wrapper') );
1608
- }
1609
-
1610
- $w.data('class', widget.class).appendTo( this.$el.find('.widget-type-list') );
1611
- }, this );
1612
-
1613
- // Add the sidebar tabs
1614
- var tabs = this.$el.find('.so-sidebar-tabs');
1615
- _.each(panelsOptions.widget_dialog_tabs, function(tab){
1616
- $( this.dialogTabTemplate( { 'title' : tab.title } )).data({
1617
- 'message' : tab.message,
1618
- 'filter' : tab.filter
1619
- }).appendTo( tabs );
1620
- }, this);
1621
-
1622
- // We'll be using tabs, so initialize them
1623
- this.initTabs();
1624
-
1625
- var thisDialog = this;
1626
- $(window).resize(function(){
1627
- thisDialog.balanceWidgetHeights();
1628
- });
1629
- },
1630
-
1631
- /**
1632
- * Handle a tab being clicked
1633
- */
1634
- tabClickHandler: function($t){
1635
- // Get the filter from the tab, and filter the widgets
1636
- this.filter = $t.parent().data('filter');
1637
- this.filter.search = this.$el.find('.so-sidebar-search').val();
1638
-
1639
- var message = $t.parent().data('message');
1640
- if( _.isEmpty( message ) ) {
1641
- message = '';
1642
- }
1643
-
1644
- this.$('.so-toolbar .so-status').html( message );
1645
-
1646
- this.filterWidgets(this.filter);
1647
-
1648
- return false;
1649
- },
1650
-
1651
- /**
1652
- * Handle changes to the search value
1653
- */
1654
- searchHandler: function(e){
1655
- this.filter.search = $(e.target).val();
1656
- this.filterWidgets(this.filter);
1657
- },
1658
-
1659
- /**
1660
- * Filter the widgets that we're displaying
1661
- * @param filter
1662
- */
1663
- filterWidgets: function(filter) {
1664
- if (typeof filter === 'undefined') {
1665
- filter = {};
1666
- }
1667
-
1668
- if(typeof filter.groups === 'undefined') {
1669
- filter.groups = '';
1670
- }
1671
-
1672
- this.$el.find('.widget-type-list .widget-type').each(function(){
1673
- var $$ = jQuery(this), showWidget;
1674
- var widgetClass = $$.data('class');
1675
-
1676
- var widgetData = ( typeof panelsOptions.widgets[widgetClass] !== 'undefined' ) ? panelsOptions.widgets[widgetClass] : null;
1677
-
1678
- if( filter.groups.length === 0 ) {
1679
- // This filter doesn't specify groups, so show all
1680
- showWidget = true;
1681
- }
1682
- else if( widgetData !== null && _.intersection(filter.groups, panelsOptions.widgets[widgetClass].groups).length ) {
1683
- // This widget is in the filter group
1684
- showWidget = true;
1685
- }
1686
- else {
1687
- // This widget is not in the filter group
1688
- showWidget = false;
1689
- }
1690
-
1691
- // This can probably be done with a more intelligent operator
1692
- if( showWidget ) {
1693
-
1694
- if( typeof filter.search !== 'undefined' && filter.search !== '' ) {
1695
- // Check if the widget title contains the search term
1696
- if( widgetData.title.toLowerCase().indexOf( filter.search.toLowerCase() ) === -1 ) {
1697
- showWidget = false;
1698
- }
1699
- }
1700
-
1701
- }
1702
-
1703
- if(showWidget) {
1704
- $$.show();
1705
- }
1706
- else {
1707
- $$.hide();
1708
- }
1709
- });
1710
-
1711
- // Balance the tags after filtering
1712
- this.balanceWidgetHeights();
1713
- },
1714
-
1715
- /**
1716
- * Add the widget to the current builder
1717
- *
1718
- * @param e
1719
- */
1720
- widgetClickHandler : function(e){
1721
- // Add the history entry
1722
- this.builder.addHistoryEntry('widget_added');
1723
-
1724
- var $w = $(e.currentTarget);
1725
-
1726
- var widget = new panels.model.widget( {
1727
- class: $w.data('class')
1728
- } );
1729
-
1730
- // Add the widget to the cell model
1731
- widget.cell = this.builder.getActiveCell();
1732
- widget.cell.widgets.add( widget );
1733
-
1734
- this.closeDialog();
1735
- },
1736
-
1737
- /**
1738
- * Balance widgets in a given row so they have enqual height.
1739
- * @param e
1740
- */
1741
- balanceWidgetHeights : function(e) {
1742
- var widgetRows = [ [] ];
1743
- var previousWidget = null;
1744
-
1745
- // Work out how many widgets there are per row
1746
- var perRow = Math.round( this.$('.widget-type').parent().width() / this.$('.widget-type').width() );
1747
-
1748
- // Add clears to create balanced rows
1749
- this.$('.widget-type')
1750
- .css('clear', 'none')
1751
- .filter(':visible')
1752
- .each( function(i, el) {
1753
- if( i % perRow === 0 && i !== 0 ) {
1754
- $(el).css('clear', 'both');
1755
- }
1756
- } );
1757
-
1758
- // Group the widgets into rows
1759
- this.$('.widget-type-wrapper')
1760
- .css( 'height', 'auto' )
1761
- .filter(':visible')
1762
- .each(function(i, el) {
1763
- var $el = $(el);
1764
- if( previousWidget !== null && previousWidget.position().top !== $el.position().top ) {
1765
- widgetRows[widgetRows.length] = [];
1766
- }
1767
- previousWidget = $el;
1768
- widgetRows[widgetRows.length - 1].push( $el );
1769
- });
1770
-
1771
- // Balance the height of the widgets within the row.
1772
- _.each( widgetRows, function(row, i){
1773
- var maxHeight = _.max( row.map( function(el){ return el.height(); } ) );
1774
- // Set the height of each widget in the row
1775
- _.each(row, function(el){
1776
- el.height(maxHeight);
1777
- });
1778
-
1779
- } );
1780
- }
1781
- } );
1782
-
1783
- },{}],11:[function(require,module,exports){
1784
- var panels = window.panels, $ = jQuery;
1785
-
1786
- module.exports = function () {
1787
-
1788
- return this.each(function(){
1789
- var $$ = jQuery(this);
1790
- var widgetId = $$.closest('form').find('.widget-id').val();
1791
-
1792
- // Exit if this isn't a real widget
1793
- if( typeof widgetId !== 'undefined' && widgetId.indexOf('__i__') > -1 ) {
1794
- return;
1795
- }
1796
-
1797
- // Create the main builder model
1798
- var builderModel = new panels.model.builder();
1799
-
1800
- // Now for the view to display the builder
1801
- var builderView = new panels.view.builder( {
1802
- model: builderModel
1803
- } );
1804
-
1805
- // Save panels data when we close the dialog, if we're in a dialog
1806
- var dialog = $$.closest('.so-panels-dialog-wrapper').data('view');
1807
- if( typeof dialog !== 'undefined' ) {
1808
- dialog.on('close_dialog', function(){
1809
- builderModel.refreshPanelsData();
1810
- } );
1811
-
1812
- dialog.on('open_dialog_complete', function(){
1813
- // Make sure the new layout widget is always properly setup
1814
- builderView.trigger('builder_resize');
1815
- });
1816
-
1817
- dialog.model.on('destroy', function(){
1818
- // Destroy the builder
1819
- builderModel.emptyRows().destroy();
1820
- } );
1821
-
1822
- // Set the parent for all the sub dialogs
1823
- builderView.setDialogParents(panelsOptions.loc.layout_widget, dialog);
1824
- }
1825
-
1826
- // Basic setup for the builder
1827
- var isWidget = Boolean( $$.closest('.widget-content').length );
1828
- builderView
1829
- .render()
1830
- .attach( {
1831
- container: $$,
1832
- dialog: isWidget,
1833
- type: $$.data('type')
1834
- } )
1835
- .setDataField( $$.find('input.panels-data') );
1836
-
1837
- if( isWidget ) {
1838
- // Set up the dialog opening
1839
- builderView.setDialogParents(panelsOptions.loc.layout_widget, builderView.dialog);
1840
- $$.find( '.siteorigin-panels-display-builder').click(function(){
1841
- builderView.dialog.openDialog();
1842
- });
1843
- }
1844
- else {
1845
- // Remove the dialog opener button, this is already being displayed in a page builder dialog.
1846
- $$.find( '.siteorigin-panels-display-builder').parent().remove();
1847
- }
1848
-
1849
- // Trigger a global jQuery event after we've setup the builder view
1850
- $(document).trigger( 'panels_setup', builderView );
1851
- });
1852
- };
1853
- },{}],12:[function(require,module,exports){
1854
- /**
1855
- * Everything we need for SiteOrigin Page Builder.
1856
- *
1857
- * @copyright Greg Priday 2013 - 2014 - <https://siteorigin.com/>
1858
- * @license GPL 3.0 http://www.gnu.org/licenses/gpl.html
1859
- */
1860
-
1861
- /* global Backbone, _, jQuery, tinyMCE, panelsOptions, plupload, confirm, console */
1862
-
1863
- /**
1864
- * Convert template into something compatible with Underscore.js templates
1865
- *
1866
- * @param s
1867
- * @return {*}
1868
- */
1869
- String.prototype.panelsProcessTemplate = function(){
1870
- var s = this;
1871
- s = s.replace(/{{%/g, '<%');
1872
- s = s.replace(/%}}/g, '%>');
1873
- s = s.trim();
1874
- return s;
1875
- };
1876
-
1877
- var panels = {};
1878
-
1879
- // Store everything globally
1880
- window.panels = panels;
1881
- window.siteoriginPanels = panels;
1882
-
1883
- // The models
1884
- panels.model = {};
1885
- panels.model.widget = require('./model/widget');
1886
- panels.model.cell = require('./model/cell');
1887
- panels.model.row = require('./model/row');
1888
- panels.model.builder = require('./model/builder');
1889
- panels.model.historyEntry = require('./model/history-entry');
1890
-
1891
- // The collections
1892
- panels.collection = {};
1893
- panels.collection.widgets = require('./collection/widgets');
1894
- panels.collection.cells = require('./collection/cells');
1895
- panels.collection.rows = require('./collection/rows');
1896
- panels.collection.historyEntries = require('./collection/history-entries');
1897
-
1898
- // The views
1899
- panels.view = {};
1900
- panels.view.widget = require('./view/widget');
1901
- panels.view.cell = require('./view/cell');
1902
- panels.view.row = require('./view/row');
1903
- panels.view.builder = require('./view/builder');
1904
- panels.view.dialog = require('./view/dialog');
1905
- panels.view.styles = require('./view/styles');
1906
- panels.view.liveEditor = require('./view/live-editor');
1907
-
1908
- // The dialogs
1909
- panels.dialog = {};
1910
- panels.dialog.builder = require('./dialog/builder');
1911
- panels.dialog.widgets = require('./dialog/widgets');
1912
- panels.dialog.widget = require('./dialog/widget');
1913
- panels.dialog.prebuilt = require('./dialog/prebuilt');
1914
- panels.dialog.row = require('./dialog/row');
1915
- panels.dialog.history = require('./dialog/history');
1916
-
1917
- // The utils
1918
- panels.utils = {}
1919
- panels.utils.menu = require('./utils/menu');
1920
-
1921
- // jQuery Plugins
1922
- jQuery.fn.soPanelsSetupBuilderWidget = require('./jquery/setup-builder-widget');
1923
-
1924
-
1925
- // Set up Page Builder if we're on the main interface
1926
- jQuery( function($){
1927
-
1928
- var container = false, field = false, form = false, postId = false, builderType = '';
1929
-
1930
- if( $('#siteorigin-panels-metabox').length && $('form#post').length ) {
1931
- // This is usually the case when we're in the post edit interface
1932
- container = $( '#siteorigin-panels-metabox' );
1933
- field = $( '#siteorigin-panels-metabox .siteorigin-panels-data-field' );
1934
- form = $('form#post');
1935
- postId = $('#post_ID').val();
1936
- builderType = 'editor_attached';
1937
- }
1938
- else if( $('.siteorigin-panels-builder-form').length ) {
1939
- // We're dealing with another interface like the custom home page interface
1940
- var $$ = jQuery('.siteorigin-panels-builder-form');
1941
- container = $$.find('.siteorigin-panels-builder');
1942
- field = $$.find('input[name="panels_data"]');
1943
- form = $$;
1944
- postId = $('#panels-home-page').data('post-id');
1945
- builderType = $$.data('type');
1946
- }
1947
-
1948
- if( container !== false ) {
1949
- // If we have a container, then set up the main builder
1950
- var panels = window.siteoriginPanels;
1951
-
1952
- // Create the main builder model
1953
- var builderModel = new panels.model.builder();
1954
-
1955
- // Now for the view to display the builder
1956
- var builderView = new panels.view.builder( {
1957
- model: builderModel
1958
- } );
1959
-
1960
- // Set up the builder view
1961
- builderView
1962
- .render()
1963
- .attach( {
1964
- container: container,
1965
- type : builderType
1966
- } )
1967
- .setDataField( field )
1968
- .attachToEditor()
1969
- .addLiveEditor( postId )
1970
- .addHistoryBrowser();
1971
-
1972
- // Refresh the live editor view
1973
- builderView.liveEditor.refreshPreview();
1974
-
1975
- // When the form is submitted, update the panels data
1976
- form.submit( function(e){
1977
- // Refresh the data
1978
- builderModel.refreshPanelsData();
1979
- } );
1980
-
1981
- container.removeClass('so-panels-loading');
1982
-
1983
- // Trigger a global jQuery event after we've setup the builder view. Everything is accessible form there
1984
- $(document).trigger( 'panels_setup', builderView, window.panels );
1985
- }
1986
-
1987
- // Setup new widgets when they're added in the standard widget interface
1988
- $(document).on( 'widget-added', function(e, widget) {
1989
- $(widget).find('.siteorigin-page-builder-widget').soPanelsSetupBuilderWidget();
1990
- } );
1991
-
1992
- // Setup existing widgets on the page (for the widgets interface)
1993
- if( !$('body').hasClass( 'wp-customizer' ) ) {
1994
- $( function(){
1995
- $('.siteorigin-page-builder-widget').soPanelsSetupBuilderWidget();
1996
- } );
1997
- }
1998
- } );
1999
- },{"./collection/cells":1,"./collection/history-entries":2,"./collection/rows":3,"./collection/widgets":4,"./dialog/builder":5,"./dialog/history":6,"./dialog/prebuilt":7,"./dialog/row":8,"./dialog/widget":9,"./dialog/widgets":10,"./jquery/setup-builder-widget":11,"./model/builder":13,"./model/cell":14,"./model/history-entry":15,"./model/row":16,"./model/widget":17,"./utils/menu":18,"./view/builder":19,"./view/cell":20,"./view/dialog":21,"./view/live-editor":22,"./view/row":23,"./view/styles":24,"./view/widget":25}],13:[function(require,module,exports){
2000
- module.exports = Backbone.Model.extend( {
2001
- rows: {},
2002
-
2003
- defaults : {
2004
- 'data' : {
2005
- 'widgets' : [],
2006
- 'grids' : [],
2007
- 'grid_cells' : []
2008
- }
2009
- },
2010
-
2011
- initialize: function(){
2012
- // These are the main rows in the interface
2013
- this.rows = new panels.collection.rows();
2014
- },
2015
-
2016
- /**
2017
- * Add a new row to this builder.
2018
- *
2019
- * @param weights
2020
- */
2021
- addRow: function( weights, options ){
2022
- options = _.extend({
2023
- noAnimate : false
2024
- }, options);
2025
- // Create the actual row
2026
- var row = new panels.model.row( {
2027
- collection: this.rows
2028
- } );
2029
-
2030
- row.setCells( weights );
2031
- row.builder = this;
2032
-
2033
- this.rows.add(row, options);
2034
-
2035
- return row;
2036
- },
2037
-
2038
- /**
2039
- * Load the panels data into the builder
2040
- *
2041
- * @param data
2042
- */
2043
- loadPanelsData: function(data){
2044
- // Start by destroying any rows that currently exist. This will in turn destroy cells, widgets and all the associated views
2045
- this.emptyRows();
2046
-
2047
- // This will empty out the current rows and reload the builder data.
2048
- this.set( 'data', data, {silent: true} );
2049
-
2050
- var cit = 0;
2051
- var rows = [];
2052
-
2053
- if( typeof data.grid_cells === 'undefined' ) {
2054
- this.trigger('load_panels_data');
2055
- return;
2056
- }
2057
-
2058
- var gi;
2059
- for(var ci = 0; ci < data.grid_cells.length; ci++) {
2060
- gi = parseInt(data.grid_cells[ci].grid);
2061
- if(typeof rows[gi] === 'undefined') {
2062
- rows[gi] = [];
2063
- }
2064
-
2065
- rows[gi].push( parseFloat( data.grid_cells[ci].weight ) );
2066
- }
2067
-
2068
- var builderModel = this;
2069
- _.each( rows, function(row, i){
2070
- // This will create and add the row model and its cells
2071
- var newRow = builderModel.addRow( row, { noAnimate: true } );
2072
-
2073
- if( typeof data.grids[i].style !== 'undefined' ) {
2074
- newRow.set( 'style', data.grids[i].style );
2075
- }
2076
- } );
2077
-
2078
-
2079
- if( typeof data.widgets === 'undefined' ) { return; }
2080
-
2081
- // Add the widgets
2082
- _.each(data.widgets, function(widgetData){
2083
- try {
2084
- var panels_info = null;
2085
- if (typeof widgetData.panels_info !== 'undefined') {
2086
- panels_info = widgetData.panels_info;
2087
- delete widgetData.panels_info;
2088
- }
2089
- else {
2090
- panels_info = widgetData.info;
2091
- delete widgetData.info;
2092
- }
2093
-
2094
- var row = builderModel.rows.at( parseInt(panels_info.grid) );
2095
- var cell = row.cells.at(parseInt(panels_info.cell));
2096
-
2097
- var newWidget = new panels.model.widget({
2098
- class: panels_info.class,
2099
- values: widgetData
2100
- });
2101
-
2102
- if( typeof panels_info.style !== 'undefined' ) {
2103
- newWidget.set('style', panels_info.style );
2104
- }
2105
-
2106
- newWidget.cell = cell;
2107
- cell.widgets.add(newWidget, {noAnimate: true});
2108
- }
2109
- catch (err) {
2110
- }
2111
- } );
2112
-
2113
- this.trigger('load_panels_data');
2114
- },
2115
-
2116
- /**
2117
- * Convert the content of the builder into a object that represents the page builder data
2118
- */
2119
- getPanelsData: function(){
2120
-
2121
- var data = {
2122
- 'widgets' : [],
2123
- 'grids' : [],
2124
- 'grid_cells' : []
2125
- };
2126
- var widgetId = 0;
2127
-
2128
- this.rows.each(function(row, ri){
2129
-
2130
- row.cells.each(function(cell, ci){
2131
-
2132
- cell.widgets.each(function(widget, wi){
2133
- // Add the data for the widget, including the panels_info field.
2134
- var values = _.extend( _.clone( widget.get('values') ), {
2135
- panels_info : {
2136
- class: widget.get('class'),
2137
- raw: widget.get('raw'),
2138
- grid: ri,
2139
- cell: ci,
2140
- id: widgetId++,
2141
- style: widget.get('style')
2142
- }
2143
- } );
2144
- data.widgets.push( values );
2145
- });
2146
-
2147
- // Add the cell info
2148
- data.grid_cells.push( {
2149
- grid: ri,
2150
- weight: cell.get('weight')
2151
- } );
2152
-
2153
- });
2154
-
2155
- data.grids.push( {
2156
- cells: row.cells.length,
2157
- style: row.get('style')
2158
- } );
2159
-
2160
- } );
2161
-
2162
- return data;
2163
-
2164
- },
2165
-
2166
- /**
2167
- * This will check all the current entries and refresh the panels data
2168
- */
2169
- refreshPanelsData: function(){
2170
- var oldData = JSON.stringify( this.get('data') );
2171
- var newData = this.getPanelsData();
2172
- this.set( 'data', newData, { silent: true } );
2173
-
2174
- if( JSON.stringify( newData ) !== oldData ) {
2175
- // The default change event doesn't trigger on deep changes, so we'll trigger our own
2176
- this.trigger('change');
2177
- this.trigger('change:data');
2178
- }
2179
- },
2180
-
2181
- /**
2182
- * Empty all the rows and the cells/widgets they contain.
2183
- */
2184
- emptyRows: function(){
2185
- _.invoke(this.rows.toArray(), 'destroy');
2186
- this.rows.reset();
2187
-
2188
- return this;
2189
- }
2190
-
2191
- } );
2192
- },{}],14:[function(require,module,exports){
2193
- module.exports = Backbone.Model.extend( {
2194
- /* A collection of widgets */
2195
- widgets: {},
2196
-
2197
- /* The row this model belongs to */
2198
- row: null,
2199
-
2200
- defaults: {
2201
- weight : 0
2202
- },
2203
-
2204
- /**
2205
- * Set up the cell model
2206
- */
2207
- initialize: function(){
2208
- this.widgets = new panels.collection.widgets();
2209
- this.on('destroy', this.onDestroy, this);
2210
- },
2211
-
2212
- /**
2213
- * Triggered when we destroy a cell
2214
- */
2215
- onDestroy: function(){
2216
- _.invoke(this.widgets.toArray(), 'destroy');
2217
- this.widgets.reset();
2218
- },
2219
-
2220
- /**
2221
- * Create a clone of the cell, along with all its widgets
2222
- */
2223
- clone: function(row, cloneOptions){
2224
- if( typeof row === 'undefined' ) {
2225
- row = this.row;
2226
- }
2227
- cloneOptions = _.extend({ cloneWidgets: true }, cloneOptions);
2228
-
2229
- var clone = new this.constructor( this.attributes );
2230
- clone.set('collection', row.cells, {silent: true});
2231
- clone.row = row;
2232
-
2233
- if( cloneOptions.cloneWidgets ) {
2234
- // Now we're going add all the widgets that belong to this, to the clone
2235
- this.widgets.each(function(widget){
2236
- clone.widgets.add( widget.clone( clone, cloneOptions ), {silent: true} );
2237
- });
2238
- }
2239
-
2240
- return clone;
2241
- }
2242
-
2243
- } );
2244
- },{}],15:[function(require,module,exports){
2245
- module.exports = Backbone.Model.extend( {
2246
- defaults: {
2247
- text : '',
2248
- data : '',
2249
- time: null,
2250
- count: 1
2251
- }
2252
- } );
2253
- },{}],16:[function(require,module,exports){
2254
- module.exports = Backbone.Model.extend( {
2255
- /* A collection of the cells in this row */
2256
- cells: {},
2257
-
2258
- /* The builder model */
2259
- builder: null,
2260
-
2261
- defaults :{
2262
- style: {}
2263
- },
2264
-
2265
- /**
2266
- * Initialize the row model
2267
- */
2268
- initialize: function(){
2269
- this.cells = new panels.collection.cells();
2270
- this.on('destroy', this.onDestroy, this);
2271
- },
2272
-
2273
- /**
2274
- * Add cells to the model row
2275
- *
2276
- * @param cells an array of cells, where each object in the array has a weight value
2277
- */
2278
- setCells: function(cells){
2279
- var thisModel = this;
2280
-
2281
- if( this.cells.length === 0 ) {
2282
- // We're adding the initial cells
2283
- _.each(cells, function (cellWeight) {
2284
- // Add the new cell to the row
2285
- var cell = new panels.model.cell({
2286
- weight: cellWeight,
2287
- collection: thisModel.cells
2288
- });
2289
- cell.row = thisModel;
2290
- thisModel.cells.add(cell);
2291
- });
2292
- }
2293
- else {
2294
-
2295
- if(cells.length > this.cells.length) {
2296
- // We need to add cells
2297
- for( var i = this.cells.length; i < cells.length; i++ ) {
2298
- var cell = new panels.model.cell({
2299
- weight: cells[ cells.length + i ],
2300
- collection: thisModel.cells
2301
- });
2302
- cell.row = this;
2303
- thisModel.cells.add(cell);
2304
- }
2305
-
2306
- }
2307
- else if(cells.length < this.cells.length) {
2308
- var newParentCell = this.cells.at( cells.length - 1 );
2309
-
2310
- // We need to remove cells
2311
- _.each(this.cells.slice( cells.length, this.cells.length), function(cell){
2312
- var widgetsToMove = cell.widgets.models.slice(0);
2313
- for( var i = 0; i < widgetsToMove.length; i++ ) {
2314
- widgetsToMove[i].moveToCell( newParentCell, {silent: false} );
2315
- }
2316
-
2317
- // First move all the widgets to the new cell
2318
- cell.destroy();
2319
- });
2320
- }
2321
-
2322
- // Now we need to change the weights of all the cells
2323
- this.cells.each(function(cell, i){
2324
- cell.set('weight', cells[i]);
2325
- });
2326
- }
2327
-
2328
- // Rescale the cells when we add or remove
2329
- this.reweightCells();
2330
- },
2331
-
2332
- /**
2333
- * Make sure that all the cell weights add up to 1
2334
- */
2335
- reweightCells: function() {
2336
- var totalWeight = 0;
2337
- this.cells.each( function(cell){
2338
- totalWeight += cell.get('weight');
2339
- } );
2340
-
2341
- this.cells.each( function(cell){
2342
- cell.set( 'weight', cell.get('weight') / totalWeight );
2343
- } );
2344
-
2345
- // This is for the row view to hook into and resize
2346
- this.trigger('reweight_cells');
2347
- },
2348
-
2349
- /**
2350
- * Triggered when the model is destroyed
2351
- */
2352
- onDestroy: function(){
2353
- // Also destroy all the cells
2354
- _.invoke(this.cells.toArray(), 'destroy');
2355
- this.cells.reset();
2356
- },
2357
-
2358
- /**
2359
- * Create a clone of the row, along with all its cells
2360
- *
2361
- * @param {panels.model.builder} builder The builder model to attach this to.
2362
- *
2363
- * @return {panels.model.row} The cloned row.
2364
- */
2365
- clone: function( builder, cloneOptions ){
2366
- if(typeof builder === 'undefined') {
2367
- builder = this.builder;
2368
- }
2369
- cloneOptions = _.extend({ cloneCells: true }, cloneOptions);
2370
-
2371
- var clone = new this.constructor( this.attributes );
2372
- clone.set('collection', builder.rows, {silent: true});
2373
- clone.builder = builder;
2374
-
2375
- if( cloneOptions.cloneCells ) {
2376
- // Clone all the rows
2377
- this.cells.each(function(cell){
2378
- clone.cells.add( cell.clone( clone, cloneOptions ), {silent: true});
2379
- });
2380
- }
2381
-
2382
- return clone;
2383
- }
2384
- } );
2385
- },{}],17:[function(require,module,exports){
2386
- /**
2387
- * Model for an instance of a widget
2388
- */
2389
- module.exports = Backbone.Model.extend( {
2390
-
2391
- cell: null,
2392
-
2393
- defaults : {
2394
- // The PHP Class of the widget
2395
- class : null,
2396
-
2397
- // Is this class missing? Missing widgets are a special case.
2398
- missing : false,
2399
-
2400
- // The values of the widget
2401
- values: {},
2402
-
2403
- // Have the current values been passed through the widgets update function
2404
- raw: false,
2405
-
2406
- // Visual style fields
2407
- styles: {}
2408
- },
2409
-
2410
- initialize: function(){
2411
- var widgetClass = this.get('class');
2412
- if( typeof panelsOptions.widgets[widgetClass] === 'undefined' || !panelsOptions.widgets[widgetClass].installed ) {
2413
- this.set('missing', true);
2414
- }
2415
- },
2416
-
2417
- /**
2418
- * @param field
2419
- * @returns {*}
2420
- */
2421
- getWidgetField: function(field) {
2422
- if(typeof panelsOptions.widgets[ this.get('class') ] === 'undefined') {
2423
- if(field === 'title' || field === 'description') {
2424
- return panelsOptions.loc.missing_widget[field];
2425
- }
2426
- else {
2427
- return '';
2428
- }
2429
- }
2430
- else {
2431
- return panelsOptions.widgets[this.get('class')][field];
2432
- }
2433
- },
2434
-
2435
- /**
2436
- * Move this widget model to a new cell. Called by the views.
2437
- *
2438
- * @param panels.model.cell newCell
2439
- *
2440
- * @return bool Indicating if the widget was moved into a different cell
2441
- */
2442
- moveToCell: function(newCell, options){
2443
- options = _.extend( {
2444
- silent: true
2445
- }, options );
2446
-
2447
- if( this.cell.cid === newCell.cid ) {
2448
- return false;
2449
- }
2450
-
2451
- this.cell = newCell;
2452
- this.collection.remove(this, options );
2453
- newCell.widgets.add(this, options );
2454
-
2455
- return true;
2456
- },
2457
-
2458
- /**
2459
- * Trigger an event on the model that indicates a user wants to edit it
2460
- */
2461
- triggerEdit: function(){
2462
- this.trigger('user_edit', this);
2463
- },
2464
-
2465
- /**
2466
- * Trigger an event on the widget that indicates a user wants to duplicate it
2467
- */
2468
- triggerDuplicate: function(){
2469
- this.trigger('user_duplicate', this);
2470
- },
2471
-
2472
- /**
2473
- * This is basically a wrapper for set that checks if we need to trigger a change
2474
- */
2475
- setValues: function(values){
2476
- var hasChanged = false;
2477
- if( JSON.stringify( values ) !== JSON.stringify( this.get('values') ) ) {
2478
- hasChanged = true;
2479
- }
2480
-
2481
- this.set( 'values', values, {silent: true} );
2482
-
2483
- if( hasChanged ) {
2484
- // We'll trigger our own change events.
2485
- // NB: Must include the model being changed (i.e. `this`) as a workaround for a bug in Backbone 1.2.3
2486
- this.trigger('change', this);
2487
- this.trigger('change:values');
2488
- }
2489
- },
2490
-
2491
- /**
2492
- * Create a clone of this widget attached to the given cell.
2493
- *
2494
- * @param {panels.model.cell} cell The cell model we're attaching this widget clone to.
2495
- * @returns {panels.model.widget}
2496
- */
2497
- clone: function( cell, options ){
2498
- if( typeof cell === 'undefined' ) { cell = this.cell; }
2499
-
2500
- var clone = new this.constructor( this.attributes );
2501
-
2502
- // Create a deep clone of the original values
2503
- var cloneValues = JSON.parse( JSON.stringify( this.get('values') ) );
2504
-
2505
- // We want to exclude any fields that start with _ from the clone. Assuming these are internal.
2506
- var cleanClone = function(vals){
2507
- _.each( vals, function(el, i){
2508
- if( typeof i === 'string' && i[0] === '_' ) {
2509
- delete vals[i];
2510
- }
2511
- else if ( _.isObject( vals[i] ) ) {
2512
- cleanClone( vals[i] );
2513
- }
2514
- } );
2515
-
2516
- return vals;
2517
- };
2518
- cloneValues = cleanClone(cloneValues);
2519
-
2520
- if( this.get('class') === "SiteOrigin_Panels_Widgets_Layout" ) {
2521
- // Special case of this being a layout widget, it needs a new ID
2522
- cloneValues.builder_id = Math.random().toString(36).substr(2);
2523
- }
2524
-
2525
- clone.set( 'values', cloneValues, { silent: true } );
2526
- clone.set( 'collection', cell.widgets, { silent: true } );
2527
- clone.cell = cell;
2528
-
2529
- // This is used to force a form reload later on
2530
- clone.isDuplicate = true;
2531
-
2532
- return clone;
2533
- },
2534
-
2535
- /**
2536
- * Gets the value that makes most sense as the title.
2537
- */
2538
- getTitle: function(){
2539
- var widgetData = panelsOptions.widgets[this.get('class')];
2540
-
2541
- if( typeof widgetData === 'undefined' ) {
2542
- return this.get('class').replace(/_/g, ' ');
2543
- }
2544
- else if( typeof widgetData.panels_title !== 'undefined' ) {
2545
- // This means that the widget has told us which field it wants us to use as a title
2546
- if( widgetData.panels_title === false ) {
2547
- return panelsOptions.widgets[this.get('class')].description;
2548
- }
2549
- }
2550
-
2551
- var values = this.get('values');
2552
-
2553
- // Create a list of fields to check for a title
2554
- var titleFields = ['title', 'text'];
2555
-
2556
- for (var k in values){
2557
- if( values.hasOwnProperty(k) ) {
2558
- titleFields.push( k );
2559
- }
2560
- }
2561
-
2562
- titleFields = _.uniq(titleFields);
2563
-
2564
- for( var i in titleFields ) {
2565
- if(
2566
- typeof values[titleFields[i]] !== 'undefined' &&
2567
- typeof values[titleFields[i]] === 'string' &&
2568
- values[titleFields[i]] !== '' &&
2569
- values[titleFields[i]] !== 'on' &&
2570
- titleFields[i][0] !== '_' &&
2571
- !jQuery.isNumeric( values[titleFields[i]] )
2572
- ) {
2573
- var title = values[ titleFields[i] ];
2574
- title = title.replace(/<\/?[^>]+(>|$)/g, "");
2575
- var parts = title.split(" ");
2576
- parts = parts.slice(0, 20);
2577
- return parts.join(' ');
2578
- }
2579
- }
2580
-
2581
- // If we still have nothing, then just return the widget description
2582
- return this.getWidgetField('description');
2583
- }
2584
-
2585
- } );
2586
-
2587
- },{}],18:[function(require,module,exports){
2588
- var panels = window.panels, $ = jQuery;
2589
-
2590
- module.exports = Backbone.View.extend({
2591
- wrapperTemplate: _.template( jQuery('#siteorigin-panels-context-menu').html().panelsProcessTemplate() ),
2592
- sectionTemplate: _.template( jQuery('#siteorigin-panels-context-menu-section').html().panelsProcessTemplate() ),
2593
-
2594
- contexts: [],
2595
- active: false,
2596
-
2597
- events : {
2598
- 'keyup .so-search-wrapper input' : 'searchKeyUp'
2599
- },
2600
-
2601
- /**
2602
- * Intialize the context menu
2603
- */
2604
- initialize: function(){
2605
- this.listenContextMenu();
2606
- this.render();
2607
- this.attach();
2608
- },
2609
-
2610
- /**
2611
- * Listen for the right click context menu
2612
- */
2613
- listenContextMenu: function(){
2614
- var thisView = this;
2615
-
2616
- $(window).on('contextmenu', function(e){
2617
- if( thisView.active && !thisView.isOverEl( thisView.$el, e ) ) {
2618
- thisView.closeMenu();
2619
- thisView.active = false;
2620
- e.preventDefault();
2621
- return false;
2622
- }
2623
-
2624
- if( thisView.active ) {
2625
- // Lets not double up on the context menu
2626
- return true;
2627
- }
2628
-
2629
- thisView.active = false;
2630
-
2631
- // Other components should listen to activate_context
2632
- thisView.trigger('activate_context', e, thisView);
2633
-
2634
- if( thisView.active ) {
2635
- // We don't want the default event to happen.
2636
- e.preventDefault();
2637
-
2638
- thisView.openMenu( {
2639
- left: e.pageX,
2640
- top: e.pageY
2641
- } );
2642
- }
2643
- } );
2644
- },
2645
-
2646
- render: function(){
2647
- this.setElement( this.wrapperTemplate() );
2648
- },
2649
-
2650
- attach: function(){
2651
- this.$el.appendTo('body');
2652
- },
2653
-
2654
- /**
2655
- * Display the actual context menu.
2656
- *
2657
- * @param position
2658
- */
2659
- openMenu: function( position ){
2660
- this.trigger('open_menu');
2661
-
2662
- // Start listening for situations when we should close the menu
2663
- $(window).on('keyup', {menu: this}, this.keyboardListen);
2664
- $(window).on('click', {menu: this}, this.clickOutsideListen);
2665
-
2666
- // Correct the left position
2667
- if( position.left + this.$el.outerWidth() + 10 >= $(window).width() ) {
2668
- position.left = $(window).width() - this.$el.outerWidth() - 10;
2669
- }
2670
- if( position.left <= 0 ) {
2671
- position.left = 10;
2672
- }
2673
-
2674
- // Check top position
2675
- if( position.top + this.$el.outerHeight() - $(window).scrollTop() + 10 >= $(window).height() ) {
2676
- position.top = $(window).height() + $(window).scrollTop() - this.$el.outerHeight() - 10;
2677
- }
2678
- if( position.left <= 0 ) {
2679
- position.left = 10;
2680
- }
2681
-
2682
- // position the contextual menu
2683
- this.$el.css({
2684
- left: position.left + 1,
2685
- top: position.top + 1
2686
- }).show();
2687
- this.$('.so-search-wrapper input').focus();
2688
- },
2689
-
2690
- closeMenu: function(){
2691
- this.trigger('close_menu');
2692
-
2693
- // Stop listening for situations when we should close the menu
2694
- $(window).off('keyup', this.keyboardListen);
2695
- $(window).off('click', this.clickOutsideListen);
2696
-
2697
- this.active = false;
2698
- this.$el.empty().hide();
2699
- },
2700
-
2701
- /**
2702
- * Keyboard events handler
2703
- */
2704
- keyboardListen: function(e) {
2705
- var menu = e.data.menu;
2706
-
2707
- switch( e.which ) {
2708
- case 27:
2709
- menu.closeMenu();
2710
- break;
2711
- }
2712
- },
2713
-
2714
- /**
2715
- * Listen for a click outside the menu to close it.
2716
- * @param e
2717
- */
2718
- clickOutsideListen: function(e){
2719
- var menu = e.data.menu;
2720
- if( e.which !== 3 && menu.$el.is(':visible') && !menu.isOverEl( menu.$el, e ) ) {
2721
- menu.closeMenu();
2722
- }
2723
- },
2724
-
2725
- addSection: function( settings, items, callback ){
2726
- var thisView = this;
2727
- settings = _.extend( {
2728
- display: 5,
2729
- defaultDisplay: false,
2730
- search: true,
2731
-
2732
- // All the labels
2733
- sectionTitle : '',
2734
- searchPlaceholder : '',
2735
-
2736
- // This is the key to be used in items for the title. Makes it easier to list objects
2737
- titleKey : 'title'
2738
- }, settings );
2739
-
2740
- // Create the new section
2741
- var section = $( this.sectionTemplate( {
2742
- settings: settings,
2743
- items: items
2744
- } ) );
2745
- this.$el.append( section );
2746
-
2747
- section.find('.so-item').click( function(){
2748
- var $$ = jQuery(this);
2749
- callback( $$.data('key') );
2750
- thisView.closeMenu();
2751
- } );
2752
-
2753
- section.data('settings', settings).find( '.so-search-wrapper input').trigger('keyup');
2754
-
2755
- this.active = true;
2756
- },
2757
-
2758
- /**
2759
- * Handle searching inside a section.
2760
- *
2761
- * @param e
2762
- * @returns {boolean}
2763
- */
2764
- searchKeyUp: function(e){
2765
- var
2766
- $$ = jQuery(e.currentTarget),
2767
- section = $$.closest('.so-section'),
2768
- settings = section.data('settings');
2769
-
2770
- if( e.which === 38 || e.which === 40 ) {
2771
- // First, lets check if this is an up, down or enter press
2772
- var
2773
- items = section.find('ul li:visible'),
2774
- activeItem = items.filter('.so-active').eq(0);
2775
-
2776
- if( activeItem.length !== 0 ) {
2777
- items.removeClass('so-active');
2778
-
2779
- var activeIndex = items.index( activeItem );
2780
-
2781
- if( e.which === 38 ) {
2782
- if( activeIndex - 1 < 0 ) {
2783
- activeItem = items.last();
2784
- }
2785
- else {
2786
- activeItem = items.eq( activeIndex - 1 );
2787
- }
2788
- }
2789
- else if( e.which === 40 ) {
2790
- if( activeIndex + 1 >= items.length ) {
2791
- activeItem = items.first();
2792
- }
2793
- else {
2794
- activeItem = items.eq( activeIndex + 1 );
2795
- }
2796
- }
2797
- }
2798
- else if( e.which === 38 ) {
2799
- activeItem = items.last();
2800
- }
2801
- else if( e.which === 40 ) {
2802
- activeItem = items.first();
2803
- }
2804
-
2805
- activeItem.addClass('so-active');
2806
- return false;
2807
- }
2808
- if(e.which === 13 ) {
2809
- if( section.find('ul li:visible').length === 1 ) {
2810
- // We'll treat a single visible item as active when enter is clicked
2811
- section.find('ul li:visible').trigger('click');
2812
- return false;
2813
- }
2814
- section.find('ul li.so-active:visible').trigger('click');
2815
- return false;
2816
- }
2817
-
2818
- if( $$.val() === '' ) {
2819
- // We'll display the defaultDisplay items
2820
- if( settings.defaultDisplay ) {
2821
- section.find('.so-item').hide();
2822
- for( var i = 0; i < settings.defaultDisplay.length; i++ ) {
2823
- section.find('.so-item[data-key="' + settings.defaultDisplay[i] + '"]').show();
2824
- }
2825
- }
2826
- else {
2827
- // We'll just display all the items
2828
- section.find('.so-item').show();
2829
- }
2830
- }
2831
- else {
2832
- section.find('.so-item').hide().each( function(){
2833
- var item = $(this);
2834
- if( item.html().toLowerCase().indexOf( $$.val().toLowerCase() ) !== -1 ) {
2835
- item.show();
2836
- }
2837
- } );
2838
- }
2839
-
2840
- // Now, we'll only show the first settings.display visible items
2841
- section.find('.so-item:visible:gt(' + (settings.display - 1) + ')').hide();
2842
-
2843
-
2844
- if( section.find('.so-item:visible').length === 0 && $$.val() !== '' ) {
2845
- section.find('.so-no-results').show();
2846
- }
2847
- else {
2848
- section.find('.so-no-results').hide();
2849
- }
2850
- },
2851
-
2852
- /**
2853
- * Check if the given mouse event is over the element
2854
- * @param el
2855
- * @param event
2856
- */
2857
- isOverEl: function(el, event) {
2858
- var elPos = [
2859
- [ el.offset().left, el.offset().top ],
2860
- [ el.offset().left + el.outerWidth(), el.offset().top + el.outerHeight() ]
2861
- ];
2862
-
2863
- // Return if this event is over the given element
2864
- return (
2865
- event.pageX >= elPos[0][0] && event.pageX <= elPos[1][0] &&
2866
- event.pageY >= elPos[0][1] && event.pageY <= elPos[1][1]
2867
- );
2868
- }
2869
-
2870
- });
2871
- },{}],19:[function(require,module,exports){
2872
- var panels = window.panels, $ = jQuery;
2873
-
2874
- module.exports = Backbone.View.extend( {
2875
- template: _.template( $('#siteorigin-panels-builder').html().panelsProcessTemplate() ),
2876
- dialogs: { },
2877
- rowsSortable: null,
2878
- dataField : false,
2879
- currentData: '',
2880
-
2881
- attachedToEditor: false,
2882
- liveEditor: false,
2883
- menu: false,
2884
-
2885
- /* The builderType is sent with all requests to the server */
2886
- builderType: '',
2887
-
2888
- events: {
2889
- 'click .so-tool-button.so-widget-add': 'displayAddWidgetDialog',
2890
- 'click .so-tool-button.so-row-add': 'displayAddRowDialog',
2891
- 'click .so-tool-button.so-prebuilt-add': 'displayAddPrebuiltDialog',
2892
- 'click .so-tool-button.so-history': 'displayHistoryDialog',
2893
- 'click .so-tool-button.so-live-editor': 'displayLiveEditor'
2894
- },
2895
-
2896
- /* A row collection */
2897
- rows: null,
2898
-
2899
- /**
2900
- * Initialize the builder
2901
- */
2902
- initialize: function(){
2903
- var builder = this;
2904
-
2905
- // Now lets create all the dialog boxes that the main builder interface uses
2906
- this.dialogs = {
2907
- widgets: new panels.dialog.widgets(),
2908
- row: new panels.dialog.row(),
2909
- prebuilt: new panels.dialog.prebuilt()
2910
- };
2911
-
2912
- // Set the builder for each dialog and render it.
2913
- _.each(this.dialogs, function(p, i, d){
2914
- d[i].setBuilder( builder );
2915
- });
2916
-
2917
- this.dialogs.row.setRowDialogType('create');
2918
-
2919
- // This handles a new row being added to the collection - we'll display it in the interface
2920
- this.model.rows.on('add', this.onAddRow, this);
2921
-
2922
- // Reflow the entire builder when ever the
2923
- $(window).resize(function(e){
2924
- if(e.target === window) {
2925
- builder.trigger('builder_resize');
2926
- }
2927
- });
2928
-
2929
- // When the data changes in the model, store it in the field
2930
- this.model.on('change:data', this.storeModelData, this);
2931
-
2932
- // Handle a content change
2933
- this.on('content_change', this.handleContentChange, this);
2934
- this.on('display_builder', this.handleDisplayBuilder, this);
2935
- this.model.on('change:data load_panels_data', this.toggleWelcomeDisplay, this);
2936
-
2937
- // Create the context menu for this builder
2938
- this.menu = new panels.utils.menu({});
2939
- this.menu.on('activate_context', this.activateContextMenu, this);
2940
-
2941
- return this;
2942
- },
2943
-
2944
- /**
2945
- * Render the builder interface.
2946
- *
2947
- * @return {panels.view.builder}
2948
- */
2949
- render: function(){
2950
- this.$el.html( this.template() );
2951
- this.$el
2952
- .attr( 'id', 'siteorigin-panels-builder-' + this.cid )
2953
- .addClass('so-builder-container');
2954
-
2955
- this.trigger( 'builder_rendered' );
2956
- return this;
2957
- },
2958
-
2959
- /**
2960
- * Attach the builder to the given container
2961
- *
2962
- * @param container
2963
- * @returns {panels.view.builder}
2964
- */
2965
- attach: function(options) {
2966
-
2967
- options = _.extend({
2968
- type: '',
2969
- container: false,
2970
- dialog: false
2971
- }, options);
2972
-
2973
- if( options.dialog ) {
2974
- // We're going to add this to a dialog
2975
- this.dialog = new panels.dialog.builder();
2976
- this.dialog.builder = this;
2977
- }
2978
- else {
2979
- // Attach this in the standard way
2980
- this.$el.appendTo( options.container );
2981
- this.metabox = options.container.closest('.postbox');
2982
- this.initSortable();
2983
- this.trigger('attached_to_container', options.container);
2984
- }
2985
-
2986
- // Store the builder type
2987
- this.builderType = options.type;
2988
-
2989
- return this;
2990
- },
2991
-
2992
- /**
2993
- * This will move the Page Builder meta box into the editor
2994
- *
2995
- * @returns {panels.view.builder}
2996
- */
2997
- attachToEditor: function(){
2998
- if( typeof this.metabox === 'undefined' ) {
2999
- return this;
3000
- }
3001
-
3002
- this.attachedToEditor = true;
3003
- var metabox = this.metabox;
3004
- var thisView = this;
3005
-
3006
- // Handle switching between the page builder and other tabs
3007
- $( '#wp-content-wrap .wp-editor-tabs' )
3008
- .find( '.wp-switch-editor' )
3009
- .click(function (e) {
3010
- e.preventDefault();
3011
- $( '#wp-content-editor-container, #post-status-info' ).show();
3012
- // metabox.hide();
3013
- $( '#wp-content-wrap' ).removeClass('panels-active');
3014
- $('#content-resize-handle' ).show();
3015
- thisView.trigger('hide_builder');
3016
- } ).end()
3017
- .append(
3018
- $( '<a id="content-panels" class="hide-if-no-js wp-switch-editor switch-panels">' + metabox.find( '.hndle span' ).html() + '</a>' )
3019
- .click( function (e) {
3020
- // Switch to the Page Builder interface
3021
- e.preventDefault();
3022
-
3023
- var $$ = jQuery( this );
3024
-
3025
- // Hide the standard content editor
3026
- $( '#wp-content-wrap, #post-status-info' ).hide();
3027
-
3028
- // Show page builder and the inside div
3029
- metabox.show().find('> .inside').show();
3030
-
3031
- // Triggers full refresh
3032
- $( window ).resize();
3033
- $( document).scroll();
3034
-
3035
- thisView.trigger('display_builder');
3036
-
3037
- } )
3038
- );
3039
-
3040
- // Switch back to the standard editor
3041
- metabox.find('.so-switch-to-standard').click(function(e){
3042
- e.preventDefault();
3043
-
3044
- if( !confirm(panelsOptions.loc.confirm_stop_builder) ) {
3045
- return;
3046
- }
3047
-
3048
- // User is switching to the standard visual editor
3049
- thisView.addHistoryEntry( 'back_to_editor' );
3050
- thisView.model.loadPanelsData( false );
3051
-
3052
- // Switch back to the standard editor
3053
- $( '#wp-content-wrap, #post-status-info' ).show();
3054
- metabox.hide();
3055
-
3056
- // Resize to trigger reflow of WordPress editor stuff
3057
- $( window ).resize();
3058
- }).show();
3059
-
3060
- // Move the panels box into a tab of the content editor
3061
- metabox.insertAfter( '#wp-content-wrap').hide().addClass('attached-to-editor');
3062
-
3063
- // Switch to the Page Builder interface as soon as we load the page if there are widgets
3064
- var data = this.model.get('data');
3065
- if(
3066
- ( typeof data.widgets !== 'undefined' && _.size(data.widgets) !== 0 ) ||
3067
- ( typeof data.grids !== 'undefined' && _.size(data.grids) !== 0 )
3068
- ) {
3069
- $('#content-panels.switch-panels').click();
3070
- }
3071
-
3072
- // We will also make this sticky if its attached to an editor.
3073
- var stickToolbar = function(){
3074
- var toolbar = thisView.$('.so-builder-toolbar');
3075
- var newTop = $(window).scrollTop() - thisView.$el.offset().top;
3076
-
3077
- if( $('#wpadminbar').css('position') === 'fixed' ) {
3078
- newTop += $('#wpadminbar').outerHeight();
3079
- }
3080
-
3081
- var limits = {
3082
- top: 0,
3083
- bottom: thisView.$el.outerHeight() - toolbar.outerHeight() + 20
3084
- };
3085
-
3086
- if( newTop > limits.top && newTop < limits.bottom ) {
3087
- if( toolbar.css('position') !== 'fixed' ) {
3088
- // The toolbar needs to stick to the top, over the interface
3089
- toolbar.css({
3090
- top: $('#wpadminbar').outerHeight(),
3091
- left: thisView.$el.offset().left,
3092
- width: thisView.$el.outerWidth(),
3093
- position: 'fixed'
3094
- });
3095
- }
3096
- }
3097
- else {
3098
- // The toolbar needs to be at the top or bottom of the interface
3099
- toolbar.css({
3100
- top: Math.min( Math.max( newTop, 0 ), thisView.$el.outerHeight() - toolbar.outerHeight() + 20 ),
3101
- left: 0,
3102
- width: '100%',
3103
- position: 'absolute'
3104
- });
3105
- }
3106
-
3107
- thisView.$el.css('padding-top', toolbar.outerHeight() );
3108
- };
3109
-
3110
- $( window ).resize( stickToolbar );
3111
- $( document ).scroll( stickToolbar );
3112
- stickToolbar();
3113
-
3114
- return this;
3115
- },
3116
-
3117
- /**
3118
- * Initialize the row sortables
3119
- */
3120
- initSortable: function(){
3121
- // Create the sortable for the rows
3122
- var $el = this.$el;
3123
- var builderView = this;
3124
-
3125
- this.rowsSortable = this.$el.find('.so-rows-container').sortable( {
3126
- appendTo: '#wpwrap',
3127
- items: '.so-row-container',
3128
- handle: '.so-row-move',
3129
- axis: 'y',
3130
- tolerance: 'pointer',
3131
- scroll: false,
3132
- stop: function (e) {
3133
- builderView.addHistoryEntry('row_moved');
3134
-
3135
- // Sort the rows collection after updating all the indexes.
3136
- builderView.sortCollections();
3137
- }
3138
- } );
3139
- },
3140
-
3141
- /**
3142
- * Refresh the row sortable
3143
- */
3144
- refreshSortable: function(){
3145
- // Refresh the sortable to account for the new row
3146
- if(this.rowsSortable !== null) {
3147
- this.rowsSortable.sortable('refresh');
3148
- }
3149
- },
3150
-
3151
- /**
3152
- * Set the field that's used to store the data
3153
- * @param field
3154
- */
3155
- setDataField: function(field, options){
3156
- options = _.extend({
3157
- load: true
3158
- }, options);
3159
-
3160
- this.dataField = field;
3161
- this.dataField.data('builder', this);
3162
-
3163
- if( options.load && field.val() !== '') {
3164
- var data;
3165
- try {
3166
- data = JSON.parse( this.dataField.val( ) );
3167
- }
3168
- catch(err) {
3169
- data = '';
3170
- }
3171
-
3172
- this.model.loadPanelsData(data);
3173
- this.currentData = data;
3174
- this.toggleWelcomeDisplay();
3175
- }
3176
-
3177
- return this;
3178
- },
3179
-
3180
- /**
3181
- * Store the model data in the data html field set in this.setDataField.
3182
- */
3183
- storeModelData: function(){
3184
- var data = JSON.stringify( this.model.get('data' ) );
3185
-
3186
- if( $(this.dataField).val() !== data ) {
3187
- // If the data is different, set it and trigger a content_change event
3188
- $(this.dataField).val( data );
3189
- $(this.dataField).trigger( 'change' );
3190
- this.trigger('content_change');
3191
- }
3192
- },
3193
-
3194
- /**
3195
- * HAndle the visual side of adding a new row to the builder.
3196
- *
3197
- * @param row
3198
- * @param collection
3199
- * @param options
3200
- */
3201
- onAddRow: function(row, collection, options){
3202
- options = _.extend( {noAnimate: false}, options );
3203
- // Create a view for the row
3204
- var rowView = new panels.view.row( { model: row } );
3205
- rowView.builder = this;
3206
- rowView.render();
3207
-
3208
- // Attach the row elements to this builder
3209
- if( typeof options.at === 'undefined' || collection.length <= 1 ) {
3210
- // Insert this at the end of the widgets container
3211
- rowView.$el.appendTo( this.$( '.so-rows-container' ) );
3212
- }
3213
- else {
3214
- // We need to insert this at a specific position
3215
- rowView.$el.insertAfter(
3216
- this.$('.so-rows-container .so-row-container').eq( options.at - 1 )
3217
- );
3218
- }
3219
-
3220
- if(options.noAnimate === false) {
3221
- rowView.visualCreate();
3222
- }
3223
-
3224
- this.refreshSortable();
3225
- rowView.resize();
3226
- },
3227
-
3228
- /**
3229
- * Display the dialog to add a new widget.
3230
- *
3231
- * @returns {boolean}
3232
- */
3233
- displayAddWidgetDialog: function(){
3234
- this.dialogs.widgets.openDialog();
3235
- return false;
3236
- },
3237
-
3238
- /**
3239
- * Display the dialog to add a new row.
3240
- *
3241
- * @returns {boolean}
3242
- */
3243
- displayAddRowDialog: function(){
3244
- this.dialogs.row.openDialog();
3245
- this.dialogs.row.setRowModel(); // Set this to an empty row model
3246
- return false;
3247
- },
3248
-
3249
- /**
3250
- * Display the dialog to add prebuilt layouts.
3251
- *
3252
- * @returns {boolean}
3253
- */
3254
- displayAddPrebuiltDialog: function(){
3255
- this.dialogs.prebuilt.openDialog();
3256
- return false;
3257
- },
3258
-
3259
- /**
3260
- * Display the history dialog.
3261
- *
3262
- * @returns {boolean}
3263
- */
3264
- displayHistoryDialog: function(){
3265
- this.dialogs.history.openDialog();
3266
- return false;
3267
- },
3268
-
3269
- /**
3270
- * Get the model for the currently selected cell
3271
- */
3272
- getActiveCell: function( options ){
3273
- options = _.extend( {
3274
- createCell: true,
3275
- defaultPosition: 'first'
3276
- }, options );
3277
-
3278
- if( this.$('.so-cells .cell').length === 0 ) {
3279
-
3280
- if( options.createCell ) {
3281
- // Create a row with a single cell
3282
- this.model.addRow( [1], {noAnimate: true} );
3283
- }
3284
- else {
3285
- return null;
3286
- }
3287
-
3288
- }
3289
-
3290
- var activeCell = this.$('.so-cells .cell.cell-selected');
3291
-
3292
- if(!activeCell.length) {
3293
- if( options.defaultPosition === 'last' ){
3294
- activeCell = this.$('.so-cells .cell').first();
3295
- }
3296
- else {
3297
- activeCell = this.$('.so-cells .cell').last();
3298
- }
3299
- }
3300
-
3301
- return activeCell.data('view').model;
3302
- },
3303
-
3304
- /**
3305
- * Sort all widget and row collections based on their dom position
3306
- */
3307
- sortCollections: function(){
3308
- // Create an array that stores model indexes within the array
3309
- var indexes = {};
3310
-
3311
- this.$('.so-rows-container .so-row-container').each(function(ri, el){
3312
- var $r = $(el);
3313
- indexes[ $r.data('view').model.cid ] = ri;
3314
-
3315
- $r.find('.so-cells .cell').each(function(ci, el){
3316
- var $c = $(el);
3317
-
3318
- $c.find('.so-widget').each(function(wi, el) {
3319
- var $w = $(el);
3320
- indexes[ $w.data('view').model.cid ] = wi;
3321
- });
3322
- });
3323
- });
3324
-
3325
- // Sort everything
3326
- this.model.rows.models = this.model.rows.sortBy(function(model){
3327
- return indexes[model.cid];
3328
- });
3329
-
3330
- this.model.rows.each(function(row){
3331
- row.cells.each(function(cell){
3332
- cell.widgets.models = cell.widgets.sortBy(function(widget){
3333
- return indexes[widget.cid];
3334
- });
3335
- });
3336
- });
3337
-
3338
- // Update the builder model to reflect the newly ordered data.
3339
- this.model.refreshPanelsData();
3340
- },
3341
-
3342
- /**
3343
- * Add a live editor
3344
- *
3345
- * @returns {panels.view.builder}
3346
- */
3347
- addLiveEditor: function(postId){
3348
- if( typeof panels.view.liveEditor === 'undefined' ) {
3349
- return this;
3350
- }
3351
-
3352
- // Create the live editor and set the builder to this.
3353
- this.liveEditor = new panels.view.liveEditor();
3354
- this.liveEditor.setPostId(postId);
3355
-
3356
- this.liveEditor.builder = this;
3357
-
3358
- // Display the live editor button in the toolbar
3359
- if( this.liveEditor.hasPreviewUrl() ) {
3360
- this.$('.so-builder-toolbar .so-live-editor').show();
3361
- }
3362
-
3363
- return this;
3364
- },
3365
-
3366
- /**
3367
- * Show the current live editor
3368
- */
3369
- displayLiveEditor: function(){
3370
- if(typeof this.liveEditor === 'undefined') {
3371
- return false;
3372
- }
3373
-
3374
- this.liveEditor.open();
3375
- return false;
3376
- },
3377
-
3378
- /**
3379
- * Add the history browser.
3380
- *
3381
- * @return {panels.view.builder}
3382
- */
3383
- addHistoryBrowser: function(){
3384
- if(typeof panels.dialog.history === 'undefined') {
3385
- return this;
3386
- }
3387
-
3388
- this.dialogs.history = new panels.dialog.history();
3389
- this.dialogs.history.builder = this;
3390
- this.dialogs.history.entries.builder = this.model;
3391
-
3392
- // Set the revert entry
3393
- this.dialogs.history.setRevertEntry( this.model );
3394
-
3395
- // Display the live editor button in the toolbar
3396
- this.$('.so-builder-toolbar .so-history').show();
3397
- },
3398
-
3399
- /**
3400
- * Add an entry.
3401
- *
3402
- * @param text
3403
- * @param data
3404
- */
3405
- addHistoryEntry: function(text, data){
3406
- if(typeof data === 'undefined') {
3407
- data = null;
3408
- }
3409
-
3410
- if( typeof this.dialogs.history !== 'undefined' ) {
3411
- this.dialogs.history.entries.addEntry(text, data);
3412
- }
3413
- },
3414
-
3415
- /**
3416
- * Handle a change of the content
3417
- */
3418
- handleContentChange: function(){
3419
-
3420
- // Make sure we actually need to copy content.
3421
- if( panelsOptions.copy_content && this.attachedToEditor && this.$el.is(':visible') && this.model.rows.length > 0 ) {
3422
-
3423
- // We're going to create a copy of page builder content into the post content
3424
- $.post(
3425
- panelsOptions.ajaxurl,
3426
- {
3427
- action: 'so_panels_builder_content',
3428
- panels_data: JSON.stringify( this.model.getPanelsData() ),
3429
- post_id : $('#post_ID').val()
3430
- },
3431
- function(content){
3432
-
3433
- if( content === '' ) {
3434
- return;
3435
- }
3436
-
3437
- // Strip all the known layout divs
3438
- var t = $('<div />').html( content );
3439
- t.find( 'div').each(function() {
3440
- var c = $(this).contents();
3441
- $(this).replaceWith(c);
3442
- });
3443
- content = t.html()
3444
- .replace(/[\r\n]+/g, "\n")
3445
- .replace(/\n\s+/g, "\n")
3446
- .trim();
3447
-
3448
- this.updateEditorContent(content);
3449
- }.bind(this)
3450
- );
3451
- }
3452
-
3453
- if( this.liveEditor !== false ) {
3454
- // Refresh the content of the builder
3455
- this.liveEditor.refreshPreview();
3456
- }
3457
- },
3458
-
3459
- /**
3460
- * Update editor content with the given content.
3461
- *
3462
- * @param content
3463
- */
3464
- updateEditorContent:function ( content ) {
3465
- // Switch back to the standard editor
3466
- if( typeof tinyMCE === 'undefined' || tinyMCE.get("content") === null ) {
3467
- var contentArea = $('#content');
3468
- contentArea.val(content).trigger( 'change' ).trigger( 'keyup' );
3469
- }
3470
- else {
3471
- var contentEd = tinyMCE.get("content");
3472
-
3473
- contentEd.setContent(content);
3474
-
3475
- contentEd.fire( 'change' );
3476
- contentEd.fire( 'keyup' );
3477
- }
3478
-
3479
- this.triggerYoastSeoChange();
3480
- },
3481
-
3482
- /**
3483
- * Trigger a change on Yoast SEO
3484
- */
3485
- triggerYoastSeoChange: function(){
3486
- if( $('#yoast_wpseo_focuskw_text_input').length ) {
3487
- var element = document.getElementById( 'yoast_wpseo_focuskw_text_input'), event;
3488
-
3489
- if (document.createEvent) {
3490
- event = document.createEvent("HTMLEvents");
3491
- event.initEvent("keyup", true, true);
3492
- } else {
3493
- event = document.createEventObject();
3494
- event.eventType = "keyup";
3495
- }
3496
-
3497
- event.eventName = "keyup";
3498
-
3499
- if (document.createEvent) {
3500
- element.dispatchEvent(event);
3501
- } else {
3502
- element.fireEvent("on" + event.eventType, event);
3503
- }
3504
- }
3505
- },
3506
-
3507
- /**
3508
- * Handle displaying the builder
3509
- */
3510
- handleDisplayBuilder: function(){
3511
- var editorContent = '';
3512
- var editor;
3513
-
3514
- if ( typeof tinyMCE !== 'undefined' ) {
3515
- editor = tinyMCE.get( 'content' );
3516
- }
3517
- if( editor && typeof( editor.getContent ) === "function" ) {
3518
- editorContent = editor.getContent();
3519
- }
3520
- else {
3521
- editorContent = $('textarea#content').val();
3522
- }
3523
-
3524
- if( _.isEmpty( this.model.get('data') ) && editorContent !== '') {
3525
- // Confirm that the user wants to copy their content to Page Builder.
3526
- if( !confirm( panelsOptions.loc.confirm_use_builder ) ) { return; }
3527
-
3528
- var widgetClass = '';
3529
- // There is a small chance a theme will have removed this, so check
3530
- if( typeof panelsOptions.widgets.SiteOrigin_Widget_Editor_Widget !== 'undefined' ) {
3531
- widgetClass = 'SiteOrigin_Widget_Editor_Widget';
3532
- }
3533
- else if( typeof panelsOptions.widgets.WP_Widget_Text !== 'undefined' ) {
3534
- widgetClass = 'WP_Widget_Text';
3535
- }
3536
-
3537
- if( widgetClass === '' ) { return; }
3538
-
3539
- // Create the existing page content in a single widget
3540
- this.model.loadPanelsData( {
3541
- grid_cells : [ { grid: 0, weight: 1 } ],
3542
- grids: [ { cells: 1 } ],
3543
- widgets: [{
3544
- filter: "1",
3545
- text: editorContent,
3546
- title: "",
3547
- type: "visual",
3548
- panels_info: {
3549
- class: widgetClass,
3550
- raw: false,
3551
- grid: 0,
3552
- cell: 0
3553
- }
3554
- }]
3555
- } );
3556
- this.model.trigger('change');
3557
- this.model.trigger('change:data');
3558
- }
3559
- },
3560
-
3561
- /**
3562
- * Set the parent dialog for all the dialogs in this builder.
3563
- *
3564
- * @param text
3565
- * @param dialog
3566
- */
3567
- setDialogParents: function(text, dialog){
3568
- _.each(this.dialogs, function(p, i, d){
3569
- d[i].setParent(text, dialog );
3570
- });
3571
-
3572
- // For any future dialogs
3573
- this.on('add_dialog', function(newDialog){
3574
- newDialog.setParent(text, dialog);
3575
- }, this);
3576
- },
3577
-
3578
- /**
3579
- * This shows or hides the welcome display depending on whether there are any rows in the collection.
3580
- */
3581
- toggleWelcomeDisplay: function(){
3582
- if( this.model.rows.length ) {
3583
- this.$('.so-panels-welcome-message').hide();
3584
- }
3585
- else {
3586
- this.$('.so-panels-welcome-message').show();
3587
- }
3588
- },
3589
-
3590
- activateContextMenu: function( e, menu ){
3591
- var builder = this;
3592
-
3593
- // Skip this if any of the dialogs are open. They can handle their own contexts.
3594
- if( typeof window.panelsDialogOpen === 'undefined' || !window.panelsDialogOpen ) {
3595
- // Check if any of the widgets get the contextual menu
3596
- var overItem = false, overItemType = false;
3597
-
3598
- var over = $([])
3599
- .add( builder.$('.so-rows-container > .so-row-container') )
3600
- .add( builder.$('.so-cells > .cell') )
3601
- .add( builder.$('.cell-wrapper > .so-widget') )
3602
- .filter( function(i){
3603
- return menu.isOverEl( $(this), e );
3604
- } );
3605
-
3606
- var activeView = over.last().data('view');
3607
- if( activeView !== undefined && activeView.buildContextualMenu !== undefined ) {
3608
- // We'll pass this to the current active view so it can popular the contextual menu
3609
- activeView.buildContextualMenu( e, menu );
3610
- }
3611
- }
3612
- }
3613
-
3614
- } );
3615
- },{}],20:[function(require,module,exports){
3616
- var panels = window.panels, $ = jQuery;
3617
-
3618
- module.exports = Backbone.View.extend( {
3619
- template: _.template( $('#siteorigin-panels-builder-cell').html().panelsProcessTemplate() ),
3620
- events : {
3621
- 'click .cell-wrapper' : 'handleCellClick'
3622
- },
3623
-
3624
- /* The row view that this cell is a part of */
3625
- row: null,
3626
- widgetSortable: null,
3627
-
3628
- initialize: function(){
3629
- this.model.widgets.on('add', this.onAddWidget, this);
3630
- },
3631
-
3632
- /**
3633
- * Render the actual cell
3634
- */
3635
- render: function(){
3636
- var templateArgs = {
3637
- weight: this.model.get('weight'),
3638
- totalWeight: this.row.model.cells.totalWeight()
3639
- };
3640
-
3641
- this.setElement( this.template(templateArgs) );
3642
- this.$el.data('view', this);
3643
-
3644
- // Now lets render any widgets that are currently in the row
3645
- var thisView = this;
3646
- this.model.widgets.each(function(widget){
3647
- var widgetView = new panels.view.widget( { model: widget } );
3648
- widgetView.cell = thisView;
3649
- widgetView.render();
3650
-
3651
- widgetView.$el.appendTo( thisView.$('.widgets-container') );
3652
- });
3653
-
3654
- this.initSortable();
3655
- this.initResizable();
3656
- },
3657
-
3658
- /**
3659
- * Initialize the widget sortable
3660
- */
3661
- initSortable: function(){
3662
- var cellView = this;
3663
-
3664
- // Go up the view heirarchy until we find the ID attribute
3665
- var builderID = cellView.row.builder.$el.attr('id');
3666
-
3667
- // Create a widget sortable that's connected with all other cells
3668
- this.widgetSortable = this.$el.find('.widgets-container').sortable( {
3669
- placeholder: "so-widget-sortable-highlight",
3670
- connectWith: '#' + builderID + ' .so-cells .cell .widgets-container',
3671
- tolerance:'pointer',
3672
- scroll: false,
3673
- over: function(e, ui){
3674
- // This will make all the rows in the current builder resize
3675
- cellView.row.builder.trigger('widget_sortable_move');
3676
- },
3677
- stop: function(e, ui){
3678
- cellView.row.builder.addHistoryEntry('widget_moved');
3679
-
3680
- var widget = $(ui.item).data('view');
3681
- var targetCell = $(ui.item).closest('.cell').data('view');
3682
-
3683
- // Move the model and the view to the new cell
3684
- widget.model.moveToCell( targetCell.model );
3685
- widget.cell = targetCell;
3686
-
3687
- cellView.row.builder.sortCollections();
3688
- },
3689
- helper: function(e, el){
3690
- var helper = el.clone()
3691
- .css({
3692
- 'width': el.outerWidth(),
3693
- 'z-index' : 10000,
3694
- 'position' :'fixed'
3695
- })
3696
- .addClass('widget-being-dragged').appendTo( 'body' );
3697
-
3698
- // Center the helper to the mouse cursor.
3699
- if( el.outerWidth() > 720 ) {
3700
- helper.animate({
3701
- 'margin-left': e.pageX - el.offset().left - (480 / 2),
3702
- 'width': 480
3703
- }, 'fast');
3704
- }
3705
-
3706
- return helper;
3707
- }
3708
- } );
3709
- },
3710
-
3711
- /**
3712
- * Refresh the widget sortable when a new widget is added
3713
- */
3714
- refreshSortable: function(){
3715
- this.widgetSortable.sortable('refresh');
3716
- },
3717
-
3718
- /**
3719
- * This will make the cell resizble
3720
- */
3721
- initResizable: function(){
3722
- // var neighbor = this.$el.previous().data('view');
3723
- var handle = this.$('.resize-handle').css('position', 'absolute');
3724
- var container = this.row.$el;
3725
- var cellView = this;
3726
-
3727
- // The view of the cell to the left is stored when dragging starts.
3728
- var previousCell;
3729
-
3730
- handle.draggable({
3731
- axis: 'x',
3732
- containment: container,
3733
- start: function(e, ui){
3734
- // Set the containment to the cell parent
3735
- previousCell = cellView.$el.prev().data('view');
3736
- if( typeof previousCell === 'undefined' ) { return false; }
3737
-
3738
- // Create the clone for the current cell
3739
- var newCellClone = cellView.$el.clone().appendTo(ui.helper).css({
3740
- position : 'absolute',
3741
- top : '0',
3742
- width : cellView.$el.outerWidth(),
3743
- left : 5,
3744
- height: cellView.$el.outerHeight()
3745
- });
3746
- newCellClone.find('.resize-handle').remove();
3747
-
3748
- // Create the clone for the previous cell
3749
- var prevCellClone = previousCell.$el.clone().appendTo(ui.helper).css({
3750
- position : 'absolute',
3751
- top : '0',
3752
- width : previousCell.$el.outerWidth(),
3753
- right : 5,
3754
- height: previousCell.$el.outerHeight()
3755
- });
3756
- prevCellClone.find('.resize-handle').remove();
3757
-
3758
- $(this).data({
3759
- 'newCellClone' : newCellClone,
3760
- 'prevCellClone' : prevCellClone
3761
- });
3762
- },
3763
- drag: function(e, ui){
3764
- // Calculate the new cell and previous cell widths as a percent
3765
- var containerWidth = cellView.row.$el.width() + 10;
3766
- var ncw = cellView.model.get('weight') - ( ( ui.position.left + handle.outerWidth()/2 ) / containerWidth );
3767
- var pcw = previousCell.model.get('weight') + ( ( ui.position.left + handle.outerWidth()/2 ) / containerWidth );
3768
-
3769
- $(this).data('newCellClone').css('width', containerWidth * ncw )
3770
- .find('.preview-cell-weight').html( Math.round(ncw*1000)/10 );
3771
-
3772
- $(this).data('prevCellClone').css('width', containerWidth * pcw )
3773
- .find('.preview-cell-weight').html( Math.round(pcw*1000)/10 );
3774
- },
3775
- stop: function(e, ui){
3776
- // Remove the clones
3777
- $(this).data('newCellClone').remove();
3778
- $(this).data('prevCellClone').remove();
3779
-
3780
- var containerWidth = cellView.row.$el.width() + 10;
3781
- var ncw = cellView.model.get('weight') - ( ( ui.position.left + handle.outerWidth()/2 ) / containerWidth );
3782
- var pcw = previousCell.model.get('weight') + ( ( ui.position.left + handle.outerWidth()/2 ) / containerWidth );
3783
-
3784
- if( ncw > 0.02 && pcw > 0.02 ) {
3785
- cellView.row.builder.addHistoryEntry('cell_resized');
3786
- cellView.model.set('weight', ncw);
3787
- previousCell.model.set('weight', pcw);
3788
- cellView.row.resize();
3789
- }
3790
-
3791
- ui.helper.css('left', -handle.outerWidth()/2);
3792
- }
3793
- });
3794
-
3795
- },
3796
-
3797
- /**
3798
- * This is triggered when ever a widget is added to the row collection.
3799
- *
3800
- * @param widget
3801
- */
3802
- onAddWidget: function(widget, collection, options){
3803
- options = _.extend({noAnimate : false}, options);
3804
-
3805
- // Create the view for the widget
3806
- var view = new panels.view.widget( {
3807
- model: widget
3808
- } );
3809
- view.cell = this;
3810
-
3811
- if( typeof widget.isDuplicate === 'undefined' ) {
3812
- widget.isDuplicate = false;
3813
- }
3814
-
3815
- // Render and load the form if this is a duplicate
3816
- view.render({
3817
- 'loadForm': widget.isDuplicate
3818
- });
3819
-
3820
- if( typeof options.at === 'undefined' || collection.length <= 1 ) {
3821
- // Insert this at the end of the widgets container
3822
- view.$el.appendTo( this.$( '.widgets-container' ) );
3823
- }
3824
- else {
3825
- // We need to insert this at a specific position
3826
- view.$el.insertAfter(
3827
- this.$('.widgets-container .so-widget').eq( options.at - 1 )
3828
- );
3829
- }
3830
-
3831
- if( options.noAnimate === false ) {
3832
- // We need an animation
3833
- view.visualCreate();
3834
- }
3835
-
3836
- this.refreshSortable();
3837
- this.row.resize();
3838
- },
3839
-
3840
- /**
3841
- * Handle this cell being clicked on
3842
- *
3843
- * @param e
3844
- * @returns {boolean}
3845
- */
3846
- handleCellClick : function(e){
3847
- var cells = this.$el.closest('.so-rows-container').find('.so-cells .cell').removeClass('cell-selected');
3848
- $(e.target).parent().addClass('cell-selected');
3849
- return false;
3850
- },
3851
-
3852
- /**
3853
- * Build up the contextual menu for a cell
3854
- *
3855
- * @param e
3856
- * @param menu
3857
- */
3858
- buildContextualMenu: function( e, menu ) {
3859
- var thisView = this;
3860
- menu.addSection(
3861
- {
3862
- sectionTitle: panelsOptions.loc.contextual.add_widget_cell,
3863
- searchPlaceholder: panelsOptions.loc.contextual.search_widgets,
3864
- defaultDisplay: panelsOptions.contextual.default_widgets
3865
- },
3866
- panelsOptions.widgets,
3867
- function(c){
3868
- thisView.row.builder.addHistoryEntry('widget_added');
3869
-
3870
- var widget = new panels.model.widget( {
3871
- class: c
3872
- } );
3873
-
3874
- // Add the widget to the cell model
3875
- widget.cell = thisView.model;
3876
- widget.cell.widgets.add( widget );
3877
- }
3878
- );
3879
-
3880
- this.row.buildContextualMenu( e, menu );
3881
- }
3882
- } );
3883
- },{}],21:[function(require,module,exports){
3884
- var panels = window.panels, $ = jQuery;
3885
-
3886
- module.exports = Backbone.View.extend( {
3887
- dialogTemplate: _.template( $('#siteorigin-panels-dialog').html().panelsProcessTemplate() ),
3888
- dialogTabTemplate: _.template( $('#siteorigin-panels-dialog-tab').html().panelsProcessTemplate() ),
3889
-
3890
- tabbed: false,
3891
- rendered: false,
3892
- builder: false,
3893
- className: 'so-panels-dialog-wrapper',
3894
- dialogClass: '',
3895
- parentDialog: false,
3896
- dialogOpen: false,
3897
-
3898
- events : {
3899
- 'click .so-close': 'closeDialog',
3900
- 'click .so-nav.so-previous': 'navToPrevious',
3901
- 'click .so-nav.so-next': 'navToNext'
3902
- },
3903
-
3904
- initialize: function(){
3905
- // The first time this dialog is opened, render it
3906
- this.once('open_dialog', this.render);
3907
- this.once('open_dialog', this.attach);
3908
- this.once('open_dialog', this.setDialogClass);
3909
-
3910
- this.trigger('initialize_dialog', this);
3911
-
3912
- if(typeof this.initializeDialog !== 'undefined') {
3913
- this.initializeDialog();
3914
- }
3915
- },
3916
-
3917
- /**
3918
- * Returns the next dialog in the sequence. Should be overwritten by a child dialog.
3919
- * @returns {null}
3920
- */
3921
- getNextDialog: function(){
3922
- return null;
3923
- },
3924
-
3925
- /**
3926
- * Returns the previous dialog in this sequence. Should be overwritten by child dialog.
3927
- * @returns {null}
3928
- */
3929
- getPrevDialog: function(){
3930
- return null;
3931
- },
3932
-
3933
- /**
3934
- * Adds a dialog class to uniquely identify this dialog type
3935
- */
3936
- setDialogClass: function(){
3937
- if(this.dialogClass !== ''){
3938
- this.$('.so-panels-dialog').addClass(this.dialogClass);
3939
- }
3940
- },
3941
-
3942
- /**
3943
- * Set the builder that controls this dialog.
3944
- * @param {panels.view.builder} builder
3945
- */
3946
- setBuilder: function(builder){
3947
- this.builder = builder;
3948
-
3949
- // Trigger an add dialog event on the builder so it can modify the dialog in any way
3950
- builder.trigger('add_dialog', this, this.builder);
3951
-
3952
- return this;
3953
- },
3954
-
3955
- /**
3956
- * Attach the dialog to the window
3957
- */
3958
- attach: function(){
3959
- this.$el.appendTo( 'body' );
3960
-
3961
- return this;
3962
- },
3963
-
3964
- /**
3965
- * Converts an HTML representation of the dialog into arguments for a dialog box
3966
- * @param html HTML for the dialog
3967
- * @param args Arguments passed to the template
3968
- * @returns {}
3969
- */
3970
- parseDialogContent: function(html, args){
3971
- // Add a CID
3972
- args = _.extend({cid: this.cid}, args);
3973
-
3974
-
3975
- var c = $( ( _.template( html.panelsProcessTemplate() ) )( args ) );
3976
- var r = {
3977
- title : c.find('.title').html(),
3978
- buttons : c.find('.buttons').html(),
3979
- content : c.find('.content').html()
3980
- };
3981
-
3982
- if( c.has('.left-sidebar') ){
3983
- r.left_sidebar = c.find('.left-sidebar').html();
3984
- }
3985
-
3986
- if( c.has('.right-sidebar') ){
3987
- r.right_sidebar = c.find('.right-sidebar').html();
3988
- }
3989
-
3990
- return r;
3991
-
3992
- },
3993
-
3994
- /**
3995
- * Render the dialog and initialize the tabs
3996
- *
3997
- * @param attributes
3998
- * @returns {panels.view.dialog}
3999
- */
4000
- renderDialog: function(attributes){
4001
- this.$el.html( this.dialogTemplate( attributes ) ).hide();
4002
- this.$el.data('view', this);
4003
- this.$el.addClass('so-panels-dialog-wrapper');
4004
-
4005
- if( this.parentDialog !== false ) {
4006
- // Add a link to the parent dialog as a sort of crumbtrail.
4007
- var thisDialog = this;
4008
- var dialogParent = $('<h3 class="so-parent-link"></h3>').html( this.parentDialog.text + '<div class="so-separator"></div>' );
4009
- dialogParent.click(function(e){
4010
- e.preventDefault();
4011
- thisDialog.closeDialog();
4012
- thisDialog.parentDialog.openDialog();
4013
- });
4014
- this.$('.so-title-bar').prepend( dialogParent );
4015
- }
4016
-
4017
- return this;
4018
- },
4019
-
4020
- /**
4021
- * Initialize the sidebar tabs
4022
- */
4023
- initTabs: function(){
4024
- var tabs = this.$el.find('.so-sidebar-tabs li a');
4025
-
4026
- if(tabs.length === 0) {
4027
- return this;
4028
- }
4029
-
4030
- var thisDialog = this;
4031
- tabs.click(function(e){
4032
- e.preventDefault();
4033
- var $$ = jQuery(this);
4034
-
4035
- thisDialog.$('.so-sidebar-tabs li').removeClass('tab-active');
4036
- thisDialog.$('.so-content .so-content-tabs > *').hide();
4037
-
4038
- $$.parent().addClass('tab-active');
4039
-
4040
- var url = $$.attr('href');
4041
- if(typeof url !== 'undefined' && url.charAt(0) === '#') {
4042
- // Display the new tab
4043
- var tabName = url.split('#')[1];
4044
- thisDialog.$('.so-content .so-content-tabs .tab-' + tabName).show();
4045
- }
4046
-
4047
- // This lets other dialogs implement their own custom handlers
4048
- thisDialog.trigger('tab_click', $$);
4049
-
4050
- });
4051
-
4052
- // Trigger a click on the first tab
4053
- this.$el.find('.so-sidebar-tabs li a').first().click();
4054
- return this;
4055
- },
4056
-
4057
- /**
4058
- * Quickly setup the dialog by opening and closing it.
4059
- */
4060
- setupDialog: function(){
4061
- this.openDialog();
4062
- this.closeDialog();
4063
- },
4064
-
4065
- /**
4066
- * Refresh the next and previous buttons.
4067
- */
4068
- refreshDialogNav: function(){
4069
- this.$('.so-title-bar .so-nav').show().removeClass('so-disabled');
4070
-
4071
- // Lets also hide the next and previous if we don't have a next and previous dialog
4072
- var nextDialog = this.getNextDialog();
4073
- var nextButton = this.$('.so-title-bar .so-next');
4074
-
4075
- var prevDialog = this.getPrevDialog();
4076
- var prevButton = this.$('.so-title-bar .so-previous');
4077
-
4078
- if(nextDialog === null) {
4079
- nextButton.hide();
4080
- }
4081
- else if(nextDialog === false) {
4082
- nextButton.addClass('so-disabled');
4083
- }
4084
-
4085
- if(prevDialog === null) {
4086
- prevButton.hide();
4087
- }
4088
- else if(prevDialog === false) {
4089
- prevButton.addClass('so-disabled');
4090
- }
4091
- },
4092
-
4093
- /**
4094
- * Open the dialog
4095
- */
4096
- openDialog: function(){
4097
- this.trigger('open_dialog');
4098
-
4099
- this.dialogOpen = true;
4100
- window.panelsDialogOpen = true;
4101
-
4102
- this.refreshDialogNav();
4103
-
4104
- // Stop scrolling for the main body
4105
- this.bodyScrollTop = $('body').scrollTop();
4106
- $('body').css({'overflow':'hidden'});
4107
-
4108
- // Start listen for keyboard keypresses.
4109
- $(window).on('keyup', this.keyboardListen);
4110
-
4111
- this.$el.show();
4112
-
4113
- // This triggers once everything is visible
4114
- this.trigger('open_dialog_complete');
4115
- },
4116
-
4117
- /**
4118
- * Close the dialog
4119
- *
4120
- * @param e
4121
- * @returns {boolean}
4122
- */
4123
- closeDialog: function(e){
4124
- this.trigger('close_dialog');
4125
-
4126
- this.dialogOpen = false;
4127
- window.panelsDialogOpen = false;
4128
-
4129
- // In the builder, trigger an update
4130
- if(typeof this.builder !== 'undefined') {
4131
- // Store the model data when a dialog is closed.
4132
- this.builder.model.refreshPanelsData();
4133
- }
4134
-
4135
- this.$el.hide();
4136
-
4137
- if( !$('.so-panels-dialog-wrapper').is(':visible') ){
4138
- // Restore scrolling to the main body if there are no more dialogs
4139
- $('body').css({'overflow':'auto'});
4140
- $('body').scrollTop( this.bodyScrollTop );
4141
- }
4142
-
4143
- // Stop listen for keyboard keypresses.
4144
- $(window).off('keyup', this.keyboardListen);
4145
-
4146
- // This triggers once everything is hidden
4147
- this.trigger('close_dialog_complete');
4148
-
4149
- return false;
4150
- },
4151
-
4152
- /**
4153
- * Keyboard events handler
4154
- */
4155
- keyboardListen: function(e) {
4156
- // [Esc] to close
4157
- if (e.which === 27) {
4158
- $('.so-panels-dialog-wrapper .so-close').trigger('click');
4159
- }
4160
- },
4161
-
4162
- /**
4163
- * Navigate to the previous dialog
4164
- */
4165
- navToPrevious: function(){
4166
- this.closeDialog(null);
4167
-
4168
- var prev = this.getPrevDialog();
4169
- if(prev !== null && prev !== false){
4170
- prev.openDialog();
4171
- }
4172
- },
4173
-
4174
- /**
4175
- * Navigate to the next dialog
4176
- */
4177
- navToNext: function(){
4178
- this.closeDialog(null);
4179
-
4180
- var next = this.getNextDialog();
4181
- if(next !== null && next !== false){
4182
- next.openDialog();
4183
- }
4184
- },
4185
-
4186
- /**
4187
- * Get the values from the form and convert them into a data array
4188
- */
4189
- getFormValues: function(formSelector){
4190
- if(typeof formSelector === 'undefined') {
4191
- formSelector = '.so-content';
4192
- }
4193
-
4194
- var $f = this.$(formSelector);
4195
-
4196
- var data = {}, parts;
4197
-
4198
- // Find all the named fields in the form
4199
- $f.find('[name]').each( function(){
4200
- var $$ = jQuery(this);
4201
-
4202
- var name = /([A-Za-z_]+)\[(.*)\]/.exec( $$.attr('name') );
4203
- if( name === undefined ) {
4204
- return true;
4205
- }
4206
-
4207
- // Create an array with the parts of the name
4208
- if(typeof name[2] === 'undefined') {
4209
- parts = $$.attr('name');
4210
- }
4211
- else {
4212
- parts = name[2].split('][');
4213
- parts.unshift( name[1] );
4214
- }
4215
-
4216
- parts = parts.map(function(e){
4217
- if( !isNaN(parseFloat(e)) && isFinite(e) ) {
4218
- return parseInt(e);
4219
- }
4220
- else {
4221
- return e;
4222
- }
4223
- });
4224
-
4225
- var sub = data;
4226
- var fieldValue = null;
4227
-
4228
- var fieldType = ( typeof $$.attr('type') === 'string' ? $$.attr('type').toLowerCase() : false );
4229
-
4230
- // First we need to get the value from the field
4231
- if( fieldType === 'checkbox' ){
4232
- if ( $$.is(':checked') ) {
4233
- fieldValue = $$.val() !== '' ? $$.val() : true;
4234
- }
4235
- else {
4236
- fieldValue = null;
4237
- }
4238
- }
4239
- else if( fieldType === 'radio' ){
4240
- if ( $$.is(':checked') ) {
4241
- fieldValue = $$.val();
4242
- }
4243
- else {
4244
- //skip over unchecked radios
4245
- return;
4246
- }
4247
- }
4248
- else if( $$.prop('tagName') === 'TEXTAREA' && $$.hasClass('wp-editor-area') ){
4249
- // This is a TinyMCE editor, so we'll use the tinyMCE object to get the content
4250
- var editor = null;
4251
- if ( typeof tinyMCE !== 'undefined' ) {
4252
- editor = tinyMCE.get( $$.attr('id') );
4253
- }
4254
-
4255
- if( editor !== null && typeof( editor.getContent ) === "function" && !editor.isHidden() ) {
4256
- fieldValue = editor.getContent();
4257
- }
4258
- else {
4259
- fieldValue = $$.val();
4260
- }
4261
- }
4262
- else if ( $$.prop('tagName') === 'SELECT' ) {
4263
- var selected = $$.find('option:selected');
4264
-
4265
- if( selected.length === 1 ) {
4266
- fieldValue = $$.find('option:selected').val();
4267
- }
4268
- else if( selected.length > 1 ) {
4269
- // This is a mutli-select field
4270
- fieldValue = _.map( $$.find('option:selected'), function(n ,i){
4271
- return $(n).val();
4272
- } );
4273
- }
4274
-
4275
- }
4276
- else {
4277
- // This is a fallback that will work for most fields
4278
- fieldValue = $$.val();
4279
- }
4280
-
4281
- // Now, we need to filter this value if necessary
4282
- if( typeof $$.data('panels-filter') !== 'undefined' ) {
4283
- switch( $$.data('panels-filter') ) {
4284
- case 'json_parse':
4285
- // Attempt to parse the JSON value of this field
4286
- try {
4287
- fieldValue = JSON.parse( fieldValue );
4288
- }
4289
- catch(err) {
4290
- fieldValue = '';
4291
- }
4292
- break;
4293
- }
4294
- }
4295
-
4296
- // Now convert this into an array
4297
- if(fieldValue !== null) {
4298
- for (var i = 0; i < parts.length; i++) {
4299
- if (i === parts.length - 1) {
4300
- if( parts[i] === '' ) {
4301
- // This needs to be an array
4302
- sub.push(fieldValue);
4303
- }
4304
- else {
4305
- sub[parts[i]] = fieldValue;
4306
- }
4307
- }
4308
- else {
4309
- if (typeof sub[parts[i]] === 'undefined') {
4310
- if ( parts[i+1] === '' ) {
4311
- sub[parts[i]] = [];
4312
- }
4313
- else {
4314
- sub[parts[i]] = {};
4315
- }
4316
- }
4317
- sub = sub[parts[i]];
4318
- }
4319
- }
4320
- }
4321
-
4322
- } ); // End of each through input fields
4323
-
4324
- return data;
4325
- },
4326
-
4327
- /**
4328
- * Set a status message for the dialog
4329
- */
4330
- setStatusMessage: function(message, loading){
4331
- this.$('.so-toolbar .so-status').html( message );
4332
- if( typeof loading !== 'undefined' && loading ) {
4333
- this.$('.so-toolbar .so-status').addClass('so-panels-loading');
4334
- }
4335
- },
4336
-
4337
- /**
4338
- * Set the parent after.
4339
- */
4340
- setParent: function(text, dialog){
4341
- this.parentDialog = {
4342
- text: text,
4343
- dialog: dialog
4344
- };
4345
- }
4346
- } );
4347
- },{}],22:[function(require,module,exports){
4348
- var panels = window.panels, $ = jQuery;
4349
-
4350
- module.exports = Backbone.View.extend( {
4351
- template: _.template( $('#siteorigin-panels-live-editor').html().panelsProcessTemplate() ),
4352
-
4353
- sectionTemplate: _.template( $('#siteorigin-panels-live-editor-sidebar-section').html().panelsProcessTemplate() ),
4354
-
4355
- postId: false,
4356
- bodyScrollTop : null,
4357
- displayed: false,
4358
-
4359
- events: {
4360
- 'click .live-editor-close': 'close'
4361
- },
4362
- frameScrollTop: 0,
4363
-
4364
- initialize: function(){
4365
- },
4366
-
4367
- /**
4368
- * Render the live editor
4369
- */
4370
- render: function(){
4371
- this.setElement( this.template() );
4372
- this.$el.html( this.template() );
4373
-
4374
- var thisView = this;
4375
-
4376
- // Prevent clicks inside the iframe
4377
- this.$('iframe#siteorigin-panels-live-editor-iframe')
4378
- .load(function(){
4379
- $(this).show();
4380
-
4381
- var ifc = $(this).contents();
4382
-
4383
- // Lets find all the first level grids. This is to account for the Page Builder layout widget.
4384
- ifc.find('.panel-grid .panel-grid-cell .so-panel')
4385
- .filter(function(){
4386
- // Filter to only include non nested
4387
- return $(this).parents('.widget_siteorigin-panels-builder').length == 0;
4388
- })
4389
- .each(function(i, el){
4390
- var $$ = jQuery(el);
4391
- var widgetEdit = thisView.$('.page-widgets .so-widget').eq(i);
4392
- var overlay;
4393
-
4394
- $$
4395
- .css({
4396
- 'cursor' : 'pointer'
4397
- })
4398
- .mouseenter(function(){
4399
- widgetEdit.addClass('so-hovered');
4400
- overlay = thisView.createPreviewOverlay( $(this) );
4401
- })
4402
- .mouseleave( function(){
4403
- widgetEdit.removeClass('so-hovered');
4404
- overlay.fadeOut('fast', function(){ $(this).remove(); });
4405
- } )
4406
- .click(function(e){
4407
- e.preventDefault();
4408
- // When we click a widget, send that click to the form
4409
- widgetEdit.click();
4410
- });
4411
- });
4412
-
4413
- // Prevent default clicks
4414
- ifc.find( "a").css({'pointer-events' : 'none'}).click(function(e){
4415
- return false;
4416
- });
4417
-
4418
- });
4419
- },
4420
-
4421
- /**
4422
- * Attach the live editor to the document
4423
- */
4424
- attach: function(){
4425
- this.$el.appendTo('body');
4426
- },
4427
-
4428
- setPostId: function(postId){
4429
- this.postId = postId;
4430
- },
4431
-
4432
- /**
4433
- * Display the live editor
4434
- */
4435
- open: function(){
4436
- if( this.$el.html() === '' ) {
4437
- this.render();
4438
- }
4439
- if( this.$el.closest('body').length === 0 ) {
4440
- this.attach();
4441
- }
4442
-
4443
- // Refresh the preview display
4444
- this.refreshWidgets();
4445
- this.$el.show();
4446
-
4447
- // Refresh the preview after we show the editor
4448
- this.refreshPreview();
4449
-
4450
- // Disable page scrolling
4451
- this.bodyScrollTop = $('body').scrollTop();
4452
- $('body').css( {overflow:'hidden'} );
4453
-
4454
- this.displayed = true;
4455
- },
4456
-
4457
- close: function(){
4458
- this.$el.hide();
4459
- $('body').css( {overflow:'auto'} );
4460
- $('body').scrollTop( this.bodyScrollTop );
4461
-
4462
- this.displayed = false;
4463
-
4464
- return false;
4465
- },
4466
-
4467
- /**
4468
- * Refresh the preview display
4469
- */
4470
- refreshPreview: function(){
4471
- if( !this.$el.is(':visible') ) {
4472
- return false;
4473
- }
4474
-
4475
- this.$('iframe#siteorigin-panels-live-editor-iframe').hide();
4476
-
4477
- this.frameScrollTop = this.$('iframe#siteorigin-panels-live-editor-iframe').contents().find('body').scrollTop();
4478
-
4479
- this.$('form.live-editor-form input[name="siteorigin_panels_data"]').val( JSON.stringify( this.builder.model.getPanelsData() ) );
4480
- this.$('form.live-editor-form').submit();
4481
- },
4482
-
4483
- /**
4484
- * Create an overlay in the preview.
4485
- *
4486
- * @param over
4487
- * @return {*|Object} The item we're hovering over.
4488
- */
4489
- createPreviewOverlay: function(over) {
4490
- var previewFrame = this.$('iframe#siteorigin-panels-live-editor-iframe');
4491
-
4492
- // Remove any old overlays
4493
- var body = previewFrame.contents().find('body').css('position', 'relative');
4494
-
4495
- previewFrame.contents().find('.panels-live-editor-overlay').remove();
4496
-
4497
- // Create the new overlay
4498
- var overlayContainer = $('<div />').addClass('panels-live-editor-overlay').css( {
4499
- 'pointer-events' : 'none'
4500
- } );
4501
-
4502
- // The overlay item used to highlight the current element
4503
- var overlay = $('<div />').css({
4504
- 'position' : 'absolute',
4505
- 'background' : '#000000',
4506
- 'z-index' : 10000,
4507
- 'opacity' : 0.25
4508
- });
4509
-
4510
- var spacing = 15;
4511
-
4512
- overlayContainer
4513
- .append(
4514
- // The top overlay
4515
- overlay.clone().css({
4516
- 'top' : -body.offset().top,
4517
- 'left' : 0,
4518
- 'right' : 0,
4519
- 'height' : over.offset().top - spacing
4520
- })
4521
- )
4522
- .append(
4523
- // The bottom overlay
4524
- overlay.clone().css({
4525
- 'bottom' : 0,
4526
- 'left' : 0,
4527
- 'right' : 0,
4528
- 'height' : Math.round( body.height() - over.offset().top - over.outerHeight() - spacing + body.offset().top - 0.01 )
4529
- })
4530
- )
4531
- .append(
4532
- // The left overlay
4533
- overlay.clone().css({
4534
- 'top' : over.offset().top - spacing - body.offset().top,
4535
- 'left' : 0,
4536
- 'width' : over.offset().left - spacing,
4537
- 'height' : Math.ceil(over.outerHeight() + spacing*2)
4538
- })
4539
- )
4540
- .append(
4541
- // The right overlay
4542
- overlay.clone().css({
4543
- 'top' : over.offset().top - spacing - body.offset().top,
4544
- 'right' : 0,
4545
- 'left' : over.offset().left + over.outerWidth() + spacing,
4546
- 'height' : Math.ceil(over.outerHeight() + spacing*2)
4547
- })
4548
- );
4549
-
4550
- // Create a new overlay
4551
- previewFrame.contents().find('body').append(overlayContainer);
4552
- return overlayContainer;
4553
- },
4554
-
4555
- /**
4556
- * Refresh the widgets in the left sidebar.
4557
- */
4558
- refreshWidgets: function(){
4559
- // Empty all the current widgets
4560
- this.$('.so-sidebar .page-widgets').empty();
4561
- var previewFrame = this.$('iframe#siteorigin-panels-live-editor-iframe');
4562
-
4563
- // Now lets move all the widgets to the sidebar
4564
- var thisView = this;
4565
- var widgetIndex = 0;
4566
-
4567
- this.builder.$('.so-row-container').each(function(ri, el) {
4568
- var row = $(el);
4569
- var widgets = row.find('.so-cells .cell .so-widget');
4570
-
4571
- var sectionWrapper = $( thisView.sectionTemplate({ title: 'Row ' + (ri+1) }) )
4572
- .appendTo( thisView.$('.so-sidebar .page-widgets') );
4573
-
4574
- sectionWrapper.find('.section-header').click(function(){
4575
- row.data('view').editSettingsHandler();
4576
- });
4577
-
4578
- var widgetsWrapper = sectionWrapper.find('.section-widgets');
4579
-
4580
- widgets.each(function(i, el){
4581
- var widget = $(this);
4582
- var widgetClone = widget.clone().show().css({
4583
- opacity : 1
4584
- });
4585
-
4586
- // Remove all the action buttons from the clone
4587
- widgetClone.find('.actions').remove();
4588
- widgetClone.find('.widget-icon').remove();
4589
-
4590
- var thisWidgetIndex = (widgetIndex++);
4591
- var getHoverWidget = function(){
4592
- return previewFrame.contents()
4593
- .find('#pl-' + thisView.postId + ' .panel-grid .panel-grid-cell .so-panel')
4594
- .filter(function(){
4595
- // Filter to only include non nested
4596
- return $(this).parents('.widget_siteorigin-panels-builder').length === 0;
4597
- })
4598
- .not('panel-hover-widget')
4599
- .eq(thisWidgetIndex);
4600
- };
4601
-
4602
- var overlay = null, hoverWidget = null;
4603
-
4604
- widgetClone
4605
- .click(function(e){
4606
- e.preventDefault();
4607
- widget.data('view').editHandler();
4608
- return false;
4609
- })
4610
- .mouseenter(function(){
4611
- var hoverWidget = getHoverWidget();
4612
-
4613
- // Center the iframe on the over item
4614
- if(hoverWidget && hoverWidget.offset()) {
4615
- previewFrame.contents()
4616
- .find('html,body')
4617
- .clearQueue()
4618
- .animate( {
4619
- scrollTop: hoverWidget.offset().top - Math.max(30, ( Math.min( previewFrame.contents().height(), previewFrame.height() ) - hoverWidget.outerHeight() ) /2 )
4620
- }, 750);
4621
-
4622
- // Create the overlay
4623
- overlay = thisView.createPreviewOverlay( hoverWidget );
4624
- }
4625
-
4626
- })
4627
- .mouseleave(function(){
4628
- // Stop any scroll animations that are currently happening
4629
- previewFrame.contents()
4630
- .find('html,body')
4631
- .clearQueue();
4632
-
4633
- if(overlay !== null) {
4634
- overlay.fadeOut('fast', function(){
4635
- $(this).remove();
4636
- });
4637
- overlay = null;
4638
- }
4639
- if(hoverWidget !== null) {
4640
- hoverWidget.remove();
4641
- hoverWidget = null;
4642
- }
4643
- })
4644
- .appendTo( widgetsWrapper );
4645
- });
4646
- });
4647
- },
4648
-
4649
- /**
4650
- * Return true if the live editor has a valid preview URL.
4651
- * @return {boolean}
4652
- */
4653
- hasPreviewUrl: function(){
4654
- return this.$('form.live-editor-form').attr('action') !== '';
4655
- }
4656
- } );
4657
- },{}],23:[function(require,module,exports){
4658
- var panels = window.panels, $ = jQuery;
4659
-
4660
- module.exports = Backbone.View.extend( {
4661
- template: _.template( $('#siteorigin-panels-builder-row').html().panelsProcessTemplate() ),
4662
-
4663
- events: {
4664
- 'click .so-row-settings' : 'editSettingsHandler',
4665
- 'click .so-row-duplicate' : 'duplicateHandler',
4666
- 'click .so-row-delete' : 'confirmedDeleteHandler'
4667
- },
4668
-
4669
- builder: null,
4670
- dialog: null,
4671
-
4672
- /**
4673
- * Initialize the row view
4674
- */
4675
- initialize: function(){
4676
-
4677
- this.model.cells.on('add', this.handleCellAdd, this);
4678
- this.model.cells.on('remove', this.handleCellRemove, this);
4679
- this.model.on('reweight_cells', this.resize, this);
4680
-
4681
- this.model.on('destroy', this.onModelDestroy, this);
4682
- this.model.on('visual_destroy', this.visualDestroyModel, this);
4683
-
4684
- var thisView = this;
4685
- this.model.cells.each(function(cell){
4686
- thisView.listenTo(cell.widgets, 'add', thisView.resize);
4687
- });
4688
-
4689
- // When ever a new cell is added, listen to it for new widgets
4690
- this.model.cells.on('add', function(cell){
4691
- thisView.listenTo(cell.widgets, 'add', thisView.resize);
4692
- }, this);
4693
-
4694
- },
4695
-
4696
- /**
4697
- * Render the row.
4698
- *
4699
- * @returns {panels.view.row}
4700
- */
4701
- render: function(){
4702
- this.setElement( this.template() );
4703
- this.$el.data('view', this);
4704
-
4705
- // Create views for the cells in this row
4706
- var thisView = this;
4707
- this.model.cells.each( function(cell){
4708
- var cellView = new panels.view.cell({
4709
- model: cell
4710
- });
4711
- cellView.row = thisView;
4712
- cellView.render();
4713
- cellView.$el.appendTo( thisView.$('.so-cells') );
4714
- } );
4715
-
4716
- // Resize the rows when ever the widget sortable moves
4717
- this.builder.on('widget_sortable_move', this.resize, this);
4718
- this.builder.on('builder_resize', this.resize, this);
4719
-
4720
- this.resize();
4721
-
4722
- return this;
4723
- },
4724
-
4725
- /**
4726
- * Give a visual indication of the creation of this row
4727
- */
4728
- visualCreate: function(){
4729
- this.$el.hide().fadeIn('fast');
4730
- },
4731
-
4732
- /**
4733
- * Visually resize the row so that all cell heights are the same and the widths so that they balance to 100%
4734
- *
4735
- * @param e
4736
- */
4737
- resize: function(e){
4738
- // Don't resize this
4739
- if( !this.$el.is(':visible') ) {
4740
- return false;
4741
- }
4742
-
4743
- // Reset everything to have an automatic height
4744
- this.$el.find( '.so-cells .cell-wrapper' ).css( 'min-height', 0 );
4745
-
4746
- // We'll tie the values to the row view, to prevent issue with values going to different rows
4747
- var height = 0;
4748
- this.$el.find('.so-cells .cell').each( function () {
4749
- height = Math.max(
4750
- height,
4751
- $(this ).height()
4752
- );
4753
-
4754
- $( this ).css( 'width', ( $(this).data('view').model.get('weight') * 100 ) + "%" );
4755
- } );
4756
-
4757
- // Resize all the grids and cell wrappers
4758
- this.$el.find( '.so-cells .cell-wrapper' ).css( 'min-height', Math.max( height, 70 ) );
4759
- },
4760
-
4761
- /**
4762
- * Remove the view from the dom.
4763
- */
4764
- onModelDestroy: function() {
4765
- this.remove();
4766
- },
4767
-
4768
- /**
4769
- * Fade out the view and destroy the model
4770
- */
4771
- visualDestroyModel: function(){
4772
- this.builder.addHistoryEntry('row_deleted');
4773
- var thisView = this;
4774
- this.$el.fadeOut('normal', function(){
4775
- thisView.model.destroy();
4776
- thisView.builder.model.refreshPanelsData();
4777
-
4778
- if(thisView.builder.liveEditor.displayed) {
4779
- thisView.builder.liveEditor.refreshWidgets();
4780
- }
4781
- });
4782
- },
4783
-
4784
- /**
4785
- * Duplicate this row.
4786
- *
4787
- * @return {boolean}
4788
- */
4789
- duplicateHandler: function(){
4790
- this.builder.addHistoryEntry('row_duplicated');
4791
-
4792
- var duplicateRow = this.model.clone( this.builder.model );
4793
-
4794
- this.builder.model.rows.add( duplicateRow, {
4795
- at: this.builder.model.rows.indexOf( this.model ) + 1
4796
- } );
4797
-
4798
- return false;
4799
- },
4800
-
4801
- /**
4802
- * Handles deleting the row with a confirmation.
4803
- */
4804
- confirmedDeleteHandler: function(e){
4805
- var $$ = jQuery(e.target);
4806
-
4807
- // The user clicked on the dashicon
4808
- if( $$.hasClass('dashicons') ) {
4809
- $$ = jQuery$.parent();
4810
- }
4811
-
4812
- if( $$.hasClass('so-confirmed') ) {
4813
- this.visualDestroyModel();
4814
- }
4815
- else {
4816
- var originalText = $$.html();
4817
-
4818
- $$.addClass('so-confirmed').html(
4819
- '<span class="dashicons dashicons-yes"></span>' + panelsOptions.loc.dropdown_confirm
4820
- );
4821
-
4822
- setTimeout(function(){
4823
- $$.removeClass('so-confirmed').html(originalText);
4824
- }, 2500);
4825
- }
4826
-
4827
- return false;
4828
- },
4829
-
4830
- /**
4831
- * Handle displaying the settings dialog
4832
- */
4833
- editSettingsHandler: function(){
4834
- // Lets open up an instance of the settings dialog
4835
- if( this.dialog === null ) {
4836
- // Create the dialog
4837
- this.dialog = new panels.dialog.row();
4838
- this.dialog.setBuilder( this.builder).setRowModel( this.model );
4839
- }
4840
-
4841
- this.dialog.openDialog();
4842
-
4843
- return false;
4844
- },
4845
-
4846
- /**
4847
- * Handle deleting this entire row.
4848
- */
4849
- deleteHandler: function(){
4850
- this.model.destroy();
4851
- return false;
4852
- },
4853
-
4854
- /**
4855
- * Handle a new cell being added to this row view. For now we'll assume the new cell is always last
4856
- */
4857
- handleCellAdd: function(cell){
4858
- var cellView = new panels.view.cell({
4859
- model: cell
4860
- });
4861
- cellView.row = this;
4862
- cellView.render();
4863
- cellView.$el.appendTo( this.$('.so-cells') );
4864
- },
4865
-
4866
- /**
4867
- * Handle a cell being removed from this row view
4868
- */
4869
- handleCellRemove: function(cell){
4870
- // Find the view that ties in to the cell we're removing
4871
- this.$el.find('.so-cells > .cell').each( function(){
4872
- var view = $(this).data('view');
4873
- if(typeof view === 'undefined') {
4874
- return false;
4875
- }
4876
-
4877
- if( view.model.cid === cell.cid ) {
4878
- // Remove this view
4879
- view.remove();
4880
- }
4881
- } );
4882
- },
4883
-
4884
- /**
4885
- * Build up the contextual menu for a row
4886
- *
4887
- * @param e
4888
- * @param menu
4889
- */
4890
- buildContextualMenu: function( e, menu ) {
4891
- var thisView = this;
4892
-
4893
- var options = [];
4894
- for( var i = 1; i < 5; i++ ) {
4895
- options.push({
4896
- title: i + ' ' + panelsOptions.loc.contextual.column
4897
- });
4898
- }
4899
-
4900
- menu.addSection(
4901
- {
4902
- sectionTitle: panelsOptions.loc.contextual.add_row,
4903
- search: false
4904
- },
4905
- options,
4906
- function(c){
4907
- thisView.builder.addHistoryEntry('row_added');
4908
-
4909
- var columns = Number(c) + 1;
4910
- var weights = [];
4911
- for( var i = 0; i < columns; i++ ) {
4912
- weights.push( 100/columns );
4913
- }
4914
-
4915
- // Create the actual row
4916
- var newRow = new panels.model.row( {
4917
- collection: thisView.collection
4918
- } );
4919
-
4920
- newRow.setCells( weights );
4921
- newRow.builder = thisView.builder;
4922
-
4923
- thisView.builder.model.rows.add( newRow, {
4924
- at: thisView.builder.model.rows.indexOf( thisView.model ) + 1
4925
- } );
4926
-
4927
-
4928
- }
4929
- );
4930
- }
4931
-
4932
- } );
4933
- },{}],24:[function(require,module,exports){
4934
- var panels = window.panels, $ = jQuery;
4935
-
4936
- module.exports = Backbone.View.extend( {
4937
-
4938
- stylesLoaded: false,
4939
-
4940
- initialize: function(){
4941
-
4942
- },
4943
-
4944
- /**
4945
- * Render the visual styles object.
4946
- *
4947
- * @param type
4948
- * @param postId
4949
- */
4950
- render: function( stylesType, postId, args ){
4951
- if( typeof stylesType === 'undefined' ) {
4952
- return false;
4953
- }
4954
-
4955
- // Add in the default args
4956
- args = _.extend( {
4957
- builderType : ''
4958
- }, args );
4959
-
4960
- this.$el.addClass('so-visual-styles');
4961
-
4962
- // Load the form
4963
- var thisView = this;
4964
- $.post(
4965
- panelsOptions.ajaxurl,
4966
- {
4967
- action: 'so_panels_style_form',
4968
- type: stylesType,
4969
- style: this.model.get('style'),
4970
- args : JSON.stringify( args ),
4971
- postId: postId
4972
- },
4973
- function( response ){
4974
- thisView.$el.html( response );
4975
- thisView.setupFields();
4976
- thisView.stylesLoaded = true;
4977
- thisView.trigger('styles_loaded');
4978
- }
4979
- );
4980
- },
4981
-
4982
- /**
4983
- * Attach the style view to the DOM.
4984
- *
4985
- * @param wrapper
4986
- */
4987
- attach: function( wrapper ){
4988
- wrapper.append( this.$el );
4989
- },
4990
-
4991
- /**
4992
- * Detach the styles view from the DOM
4993
- */
4994
- detach: function(){
4995
- this.$el.detach();
4996
- },
4997
-
4998
- /**
4999
- * Setup all the fields
5000
- */
5001
- setupFields: function(){
5002
-
5003
- // Set up the sections as collapsible
5004
- this.$('.style-section-wrapper').each(function(){
5005
- var $s = $(this);
5006
-
5007
- $s.find('.style-section-head').click( function(e){
5008
- e.preventDefault();
5009
- $s.find('.style-section-fields').slideToggle('fast');
5010
- } );
5011
- });
5012
-
5013
- // Set up the color fields
5014
- if(typeof $.fn.wpColorPicker !== 'undefined') {
5015
- if (typeof(panelsOptions.wpColorPickerOptions.palettes) == 'object' && !$.isArray(panelsOptions.wpColorPickerOptions.palettes)) {
5016
- panelsOptions.wpColorPickerOptions.palettes = $.map(panelsOptions.wpColorPickerOptions.palettes, function(el) { return el; });
5017
- }
5018
- this.$('.so-wp-color-field').wpColorPicker(panelsOptions.wpColorPickerOptions);
5019
- }
5020
-
5021
- // Set up the image select fields
5022
- this.$('.style-field-image').each( function(){
5023
- var frame = null;
5024
- var $s = $(this);
5025
-
5026
- $s.find('.so-image-selector').click( function( e ){
5027
- e.preventDefault();
5028
-
5029
- if( frame === null ) {
5030
- // Create the media frame.
5031
- frame = wp.media({
5032
- // Set the title of the modal.
5033
- title: 'choose',
5034
-
5035
- // Tell the modal to show only images.
5036
- library: {
5037
- type: 'image'
5038
- },
5039
-
5040
- // Customize the submit button.
5041
- button: {
5042
- // Set the text of the button.
5043
- text: 'Done',
5044
- close: true
5045
- }
5046
- });
5047
-
5048
- frame.on( 'select', function(){
5049
- var attachment = frame.state().get('selection').first().attributes;
5050
-
5051
- var url = attachment.url;
5052
- if(!_.isUndefined(attachment.sizes)) {
5053
- try {
5054
- url = attachment.sizes.thumbnail.url;
5055
- }
5056
- catch(e) {
5057
- // We'll use the full image instead
5058
- url = attachment.sizes.full.url;
5059
- }
5060
- }
5061
- $s.find( '.current-image' ).css( 'background-image', 'url(' + url + ')' );
5062
-
5063
- // Store the ID
5064
- $s.find('input').val( attachment.id )
5065
- } );
5066
- }
5067
-
5068
- frame.open();
5069
-
5070
- } );
5071
-
5072
- // Handle clicking on remove
5073
- $s.find('.remove-image').click(function(e){
5074
- e.preventDefault();
5075
- $s.find( '.current-image').css('background-image', 'none');
5076
- $s.find('input').val( '' );
5077
- });
5078
- } );
5079
-
5080
- // Set up all the measurement fields
5081
- this.$('.style-field-measurement').each(function(){
5082
- var $$ = jQuery(this);
5083
-
5084
- var text = $$.find('input[type="text"]');
5085
- var unit = $$.find('select');
5086
- var hidden = $$.find('input[type="hidden"]');
5087
-
5088
- // Load the value from the hidden field
5089
- if( hidden.val() !== '' ) {
5090
- var re = /(?:([0-9\.,]+)(.*))+/;
5091
- var valueList = hidden.val().split(' ');
5092
- var valueListValue = [];
5093
- for (var i in valueList) {
5094
- var match = re.exec(valueList[i]);
5095
- if (match != null && typeof match[1] !== 'undefined' && typeof match[2] !== 'undefined') {
5096
- valueListValue.push(match[1]);
5097
- unit.val(match[2]);
5098
- }
5099
- }
5100
- text.val(valueListValue.join(' '));
5101
- }
5102
-
5103
- var setVal = function(){
5104
- var fullString = text
5105
- .val()
5106
- .split(' ')
5107
- .filter(function(value) { return value !== '' })
5108
- .map(function(value) { return value + unit.val(); })
5109
- .join(' ');
5110
- hidden.val( fullString );
5111
- };
5112
-
5113
- // Set the value when ever anything changes
5114
- text.keyup(setVal).change(setVal);
5115
- unit.change(setVal);
5116
- } );
5117
- }
5118
-
5119
- } );
5120
- },{}],25:[function(require,module,exports){
5121
- var panels = window.panels, $ = jQuery;
5122
-
5123
- module.exports = Backbone.View.extend({
5124
- template: _.template( $('#siteorigin-panels-builder-widget').html().panelsProcessTemplate() ),
5125
-
5126
- // The cell view that this widget belongs to
5127
- cell: null,
5128
-
5129
- // The edit dialog
5130
- dialog: null,
5131
-
5132
- events: {
5133
- 'click .widget-edit' : 'editHandler',
5134
- 'click .title h4' : 'editHandler',
5135
- 'click .actions .widget-duplicate' : 'duplicateHandler',
5136
- 'click .actions .widget-delete' : 'deleteHandler'
5137
- },
5138
-
5139
- /**
5140
- * Initialize the widget
5141
- */
5142
- initialize: function(){
5143
- // The 2 user actions on the model that this view will handle.
5144
- this.model.on('user_edit', this.editHandler, this); // When a user wants to edit the widget model
5145
- this.model.on('user_duplicate', this.duplicateHandler, this); // When a user wants to duplicate the widget model
5146
- this.model.on('destroy', this.onModelDestroy, this);
5147
- this.model.on('visual_destroy', this.visualDestroyModel, this);
5148
-
5149
- this.model.on('change:values', this.onModelChange, this);
5150
- },
5151
-
5152
- /**
5153
- * Render the widget
5154
- */
5155
- render: function(options){
5156
- options = _.extend({'loadForm': false}, options);
5157
-
5158
- this.setElement( this.template( {
5159
- title : this.model.getWidgetField('title'),
5160
- description : this.model.getTitle()
5161
- } ) );
5162
-
5163
- this.$el.data( 'view', this );
5164
-
5165
- if( _.size( this.model.get('values') ) === 0 || options.loadForm) {
5166
- // If this widget doesn't have a value, create a form and save it
5167
- var dialog = this.getEditDialog();
5168
-
5169
- // Save the widget as soon as the form is loaded
5170
- dialog.once('form_loaded', dialog.saveWidget, dialog);
5171
-
5172
- // Setup the dialog to load the form
5173
- dialog.setupDialog();
5174
- }
5175
- },
5176
-
5177
- /**
5178
- * Display an animation that implies creation using a visual animation
5179
- */
5180
- visualCreate: function(){
5181
- this.$el.hide().fadeIn( 'fast' );
5182
- },
5183
-
5184
- /**
5185
- * Get the dialog view of the form that edits this widget
5186
- *
5187
- * @returns {null}
5188
- */
5189
- getEditDialog: function(){
5190
- if(this.dialog === null){
5191
- this.dialog = new panels.dialog.widget({
5192
- model: this.model
5193
- });
5194
- this.dialog.setBuilder(this.cell.row.builder);
5195
-
5196
- // Store the widget view
5197
- this.dialog.widgetView = this;
5198
- }
5199
- return this.dialog;
5200
- },
5201
-
5202
- /**
5203
- * Handle clicking on edit widget.
5204
- *
5205
- * @returns {boolean}
5206
- */
5207
- editHandler: function(){
5208
- // Create a new dialog for editing this
5209
- this.getEditDialog().openDialog();
5210
- return false;
5211
- },
5212
-
5213
- /**
5214
- * Handle clicking on duplicate.
5215
- *
5216
- * @returns {boolean}
5217
- */
5218
- duplicateHandler: function(){
5219
- // Add the history entry
5220
- this.cell.row.builder.addHistoryEntry('widget_duplicated');
5221
-
5222
- // Create the new widget and connect it to the widget collection for the current row
5223
- var newWidget = this.model.clone( this.model.cell );
5224
-
5225
- this.cell.model.widgets.add(newWidget, {
5226
- // Add this after the existing model
5227
- at: this.model.collection.indexOf( this.model ) + 1
5228
- });
5229
-
5230
- return false;
5231
- },
5232
-
5233
- /**
5234
- * Handle clicking on delete.
5235
- *
5236
- * @returns {boolean}
5237
- */
5238
- deleteHandler: function(){
5239
- this.model.trigger('visual_destroy');
5240
- return false;
5241
- },
5242
-
5243
- onModelChange: function(){
5244
- // Update the description when ever the model changes
5245
- this.$('.description').html( this.model.getTitle() );
5246
- },
5247
-
5248
- /**
5249
- * When the model is destroyed, fade it out
5250
- */
5251
- onModelDestroy: function(){
5252
- this.remove();
5253
- },
5254
-
5255
- /**
5256
- * Visually destroy a model
5257
- */
5258
- visualDestroyModel: function(){
5259
- // Add the history entry
5260
- this.cell.row.builder.addHistoryEntry('widget_deleted');
5261
-
5262
- var thisView = this;
5263
- this.$el.fadeOut('fast', function(){
5264
- thisView.cell.row.resize();
5265
- thisView.model.destroy();
5266
- thisView.remove();
5267
- } );
5268
- },
5269
-
5270
- /**
5271
- * Build up the contextual menu for a widget
5272
- *
5273
- * @param e
5274
- * @param menu
5275
- */
5276
- buildContextualMenu: function( e, menu ) {
5277
- var thisView = this;
5278
- menu.addSection(
5279
- {
5280
- sectionTitle: panelsOptions.loc.contextual.add_widget_below,
5281
- searchPlaceholder: panelsOptions.loc.contextual.search_widgets,
5282
- defaultDisplay: panelsOptions.contextual.default_widgets
5283
- },
5284
- panelsOptions.widgets,
5285
- function(c){
5286
- thisView.cell.row.builder.addHistoryEntry('widget_added');
5287
-
5288
- var widget = new panels.model.widget( {
5289
- class: c
5290
- } );
5291
- widget.cell = thisView.cell.model;
5292
-
5293
- // Insert the new widget below
5294
- thisView.cell.model.widgets.add(widget, {
5295
- // Add this after the existing model
5296
- at: thisView.model.collection.indexOf( thisView.model ) + 1
5297
- });
5298
- }
5299
- );
5300
-
5301
- // Lets also add the contextual menu for the entire row
5302
- this.cell.row.buildContextualMenu( e, menu );
5303
- }
5304
-
5305
- });
5306
- },{}]},{},[12]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
js/siteorigin-panels-23.min.js DELETED
@@ -1,3 +0,0 @@
1
- !function e(t,i,s){function o(n,a){if(!i[n]){if(!t[n]){var r="function"==typeof require&&require;if(!a&&r)return r(n,!0);if(l)return l(n,!0);var d=new Error("Cannot find module '"+n+"'");throw d.code="MODULE_NOT_FOUND",d}var c=i[n]={exports:{}};t[n][0].call(c.exports,function(e){var i=t[n][1][e];return o(i?i:e)},c,c.exports,e,t,i,s)}return i[n].exports}for(var l="function"==typeof require&&require,n=0;n<s.length;n++)o(s[n]);return o}({1:[function(e,t,i){var s=window.panels;t.exports=Backbone.Collection.extend({model:s.model.cell,initialize:function(){},totalWeight:function(){var e=0;return this.each(function(t){e+=t.get("weight")}),e}})},{}],2:[function(e,t,i){var s=window.panels;t.exports=Backbone.Collection.extend({model:s.model.historyEntry,builder:null,maxSize:12,initialize:function(){this.on("add",this.onAddEntry,this)},addEntry:function(e,t){("undefined"==typeof t||null===t)&&(t=this.builder.getPanelsData());var i=new s.model.historyEntry({text:e,data:JSON.stringify(t),time:parseInt((new Date).getTime()/1e3),collection:this});this.add(i)},onAddEntry:function(e){if(this.models.length>1){var t=this.at(this.models.length-2);(e.get("text")===t.get("text")&&e.get("time")-t.get("time")<15||e.get("data")===t.get("data"))&&(this.remove(e),t.set("count",t.get("count")+1))}for(;this.models.length>this.maxSize;)this.shift()}})},{}],3:[function(e,t,i){var s=window.panels;t.exports=Backbone.Collection.extend({model:s.model.row,empty:function(){for(var e;;){if(e=this.collection.first(),!e)break;e.destroy()}}})},{}],4:[function(e,t,i){var s=window.panels;t.exports=Backbone.Collection.extend({model:s.model.widget,initialize:function(){}})},{}],5:[function(e,t,i){var s=window.panels,o=jQuery;t.exports=s.view.dialog.extend({dialogClass:"so-panels-dialog-add-builder",render:function(){this.renderDialog(this.parseDialogContent(o("#siteorigin-panels-dialog-builder").html(),{})),this.$(".so-content .siteorigin-panels-builder").append(this.builder.$el)},initializeDialog:function(){var e=this;this.once("open_dialog_complete",function(){e.builder.initSortable()}),this.on("open_dialog_complete",function(){e.builder.trigger("builder_resize")})}})},{}],6:[function(e,t,i){var s=window.panels,o=jQuery;t.exports=s.view.dialog.extend({historyEntryTemplate:_.template(o("#siteorigin-panels-dialog-history-entry").html().panelsProcessTemplate()),entries:{},currentEntry:null,revertEntry:null,selectedEntry:null,dialogClass:"so-panels-dialog-history",events:{"click .so-close":"closeDialog","click .so-restore":"restoreSelectedEntry"},initializeDialog:function(){this.entries=new s.collection.historyEntries,this.on("open_dialog",this.setCurrentEntry,this),this.on("open_dialog",this.renderHistoryEntries,this)},render:function(){this.renderDialog(this.parseDialogContent(o("#siteorigin-panels-dialog-history").html(),{})),this.$("iframe.siteorigin-panels-history-iframe").load(function(){o(this).show()})},setRevertEntry:function(e){this.revertEntry=new s.model.historyEntry({data:JSON.stringify(e.getPanelsData()),time:parseInt((new Date).getTime()/1e3)})},setCurrentEntry:function(){this.currentEntry=new s.model.historyEntry({data:JSON.stringify(this.builder.model.getPanelsData()),time:parseInt((new Date).getTime()/1e3)}),this.selectedEntry=this.currentEntry,this.previewEntry(this.currentEntry),this.$(".so-buttons .so-restore").addClass("disabled")},renderHistoryEntries:function(){var e=this,t=this.$(".history-entries").empty();(this.currentEntry.get("data")!==this.revertEntry.get("data")||this.entries.models.length>0)&&o(this.historyEntryTemplate({title:panelsOptions.loc.history.revert,count:1})).data("historyEntry",this.revertEntry).prependTo(t),this.entries.each(function(i){var s=e.historyEntryTemplate({title:panelsOptions.loc.history[i.get("text")],count:i.get("count")});o(s).data("historyEntry",i).prependTo(t)}),o(this.historyEntryTemplate({title:panelsOptions.loc.history.current,count:1})).data("historyEntry",this.currentEntry).addClass("so-selected").prependTo(t),t.find(".history-entry").click(function(){var i=jQuery(this);t.find(".history-entry").not(i).removeClass("so-selected"),i.addClass("so-selected");var s=i.data("historyEntry");e.selectedEntry=s,e.selectedEntry.cid!==e.currentEntry.cid?e.$(".so-buttons .so-restore").removeClass("disabled"):e.$(".so-buttons .so-restore").addClass("disabled"),e.previewEntry(s)}),this.updateEntryTimes()},previewEntry:function(e){this.$("iframe.siteorigin-panels-history-iframe").hide(),this.$('form.history-form input[name="siteorigin_panels_data"]').val(e.get("data")),this.$("form.history-form").submit()},restoreSelectedEntry:function(){return this.$(".so-buttons .so-restore").hasClass("disabled")?!1:this.currentEntry.get("data")===this.selectedEntry.get("data")?(this.closeDialog(),!1):("restore"!==this.selectedEntry.get("text")&&this.entries.addEntry("restore",this.builder.model.getPanelsData()),this.builder.model.loadPanelsData(JSON.parse(this.selectedEntry.get("data"))),this.closeDialog(),!1)},updateEntryTimes:function(){var e=this;this.$(".history-entries .history-entry").each(function(){var t=jQuery(this),i=t.find(".timesince"),s=t.data("historyEntry");i.html(e.timeSince(s.get("time")))})},timeSince:function(e){var t,i=parseInt((new Date).getTime()/1e3)-e,s=[];return i>3600&&(t=Math.floor(i/3600),1===t?s.push(panelsOptions.loc.time.hour.replace("%d",t)):s.push(panelsOptions.loc.time.hours.replace("%d",t)),i-=3600*t),i>60&&(t=Math.floor(i/60),1===t?s.push(panelsOptions.loc.time.minute.replace("%d",t)):s.push(panelsOptions.loc.time.minutes.replace("%d",t)),i-=60*t),i>0&&(1===i?s.push(panelsOptions.loc.time.second.replace("%d",i)):s.push(panelsOptions.loc.time.seconds.replace("%d",i))),0===s.length?panelsOptions.loc.time.now:panelsOptions.loc.time.ago.replace("%s",s.slice(0,2).join(", "))}})},{}],7:[function(e,t,i){var s=window.panels,o=jQuery;t.exports=s.view.dialog.extend({entryTemplate:_.template(o("#siteorigin-panels-dialog-prebuilt-entry").html().panelsProcessTemplate()),directoryTemplate:_.template(o("#siteorigin-panels-directory-items").html().panelsProcessTemplate()),builder:null,dialogClass:"so-panels-dialog-prebuilt-layouts",layoutCache:{},currentTab:!1,directoryPage:1,events:{"click .so-close":"closeDialog","click .so-sidebar-tabs li a":"tabClickHandler","click .so-content .layout":"layoutClickHandler","keyup .so-sidebar-search":"searchHandler","click .so-content .so-directory-item .so-button-use":"directoryClickHandler"},initializeDialog:function(){var e=this;this.on("open_dialog",function(){e.$(".so-sidebar-tabs li a").first().click(),e.$(".so-status").removeClass("so-panels-loading")})},render:function(){this.renderDialog(this.parseDialogContent(o("#siteorigin-panels-dialog-prebuilt").html(),{}))},tabClickHandler:function(e){this.$(".so-sidebar-tabs li").removeClass("tab-active");var t=jQuery(e.target),i=t.attr("href").split("#")[1];t.parent().addClass("tab-active");var s=this;return this.$(".so-content").empty(),s.currentTab=i,"directory"===i?this.displayLayoutDirectory():"import"===i?this.displayImportExport():"undefined"==typeof this.layoutCache[i]?(this.$(".so-content").addClass("so-panels-loading"),o.get(panelsOptions.ajaxurl,{action:"so_panels_prebuilt_layouts",type:i},function(e){s.layoutCache[i]=e,s.currentTab===i&&(s.$(".so-content").removeClass("so-panels-loading"),s.displayLayouts(i,e))})):s.displayLayouts(i,this.layoutCache[i]),s.$(".so-sidebar-search").val(""),!1},displayLayouts:function(e,t){var i=this.$(".so-content").empty(),s=this.$(".so-sidebar-search").val().toLowerCase();if("undefined"!=typeof t.error_message)return void this.$(".so-content").append(o('<div class="so-error-message">').html(t.error_message));if(_.size(t))for(var l in t)if(t.hasOwnProperty(l)){if("prebuilt"!==e&&l===o("#post_ID").val())continue;if(""!==s&&-1===t[l].name.toLowerCase().indexOf(s))continue;var n=o(this.entryTemplate({name:t[l].name,description:t[l].description}));n.appendTo(i).data({type:e,lid:l})}},layoutClickHandler:function(e){var t=o(e.target).closest(".layout");return this.loadLayout(t.data("type"),t.data("lid")),!1},loadLayout:function(e,t){var i=this;return confirm(panelsOptions.loc.prebuilt_confirm)?(this.setStatusMessage(panelsOptions.loc.prebuilt_loading,!0),void o.post(panelsOptions.ajaxurl,{action:"so_panels_get_prebuilt_layout",type:e,lid:t},function(e){i.setStatusMessage("",!1),i.builder.addHistoryEntry("prebuilt_loaded"),i.builder.model.loadPanelsData(e),i.closeDialog()})):!1},displayImportExport:function(){var e=this.$(".so-content").empty().removeClass("so-panels-loading");e.html(o("#siteorigin-panels-dialog-prebuilt-importexport").html());var t=this,i=t.$(".import-upload-ui").hide(),s=new plupload.Uploader({runtimes:"html5,silverlight,flash,html4",browse_button:i.find(".file-browse-button").get(0),container:i.get(0),drop_element:i.find(".drag-upload-area").get(0),file_data_name:"panels_import_data",multiple_queues:!1,max_file_size:panelsOptions.plupload.max_file_size,url:panelsOptions.plupload.url,flash_swf_url:panelsOptions.plupload.flash_swf_url,silverlight_xap_url:panelsOptions.plupload.silverlight_xap_url,filters:[{title:panelsOptions.plupload.filter_title,extensions:"json"}],multipart_params:{action:"so_panels_import_layout"},init:{PostInit:function(e){e.features.dragdrop&&i.addClass("has-drag-drop"),i.show().find(".progress-precent").css("width","0%")},FilesAdded:function(e){i.find(".file-browse-button").blur(),i.find(".drag-upload-area").removeClass("file-dragover"),i.find(".progress-bar").fadeIn("fast"),e.start()},UploadProgress:function(e,t){i.find(".progress-precent").css("width",t.percent+"%")},FileUploaded:function(e,i,s){var o=JSON.parse(s.response);"undefined"!=typeof o.widgets?(t.builder.addHistoryEntry("prebuilt_loaded"),t.builder.model.loadPanelsData(o),t.closeDialog()):alert(panelsOptions.plupload.error_message)},Error:function(){alert(panelsOptions.plupload.error_message)}}});s.init(),i.find(".drag-upload-area").on("dragover",function(){o(this).addClass("file-dragover")}).on("dragleave",function(){o(this).removeClass("file-dragover")}),e.find(".so-export").submit(function(e){var i=jQuery(this);i.find('input[name="panels_export_data"]').val(JSON.stringify(t.builder.model.getPanelsData()))})},displayLayoutDirectory:function(e,t){var i=this,s=this.$(".so-content").empty().addClass("so-panels-loading");return void 0===e&&(e=""),void 0===t&&(t=1),panelsOptions.directory_enabled?void o.get(panelsOptions.ajaxurl,{action:"so_panels_directory_query",search:e,page:t},function(l){if("directory"===i.currentTab){s.removeClass("so-panels-loading").html(i.directoryTemplate(l));var n=s.find(".so-previous"),a=s.find(".so-next");1>=t?n.addClass("button-disabled"):n.click(function(s){s.preventDefault(),i.displayLayoutDirectory(e,t-1)}),t===l.max_num_pages||0==l.max_num_pages?a.addClass("button-disabled"):a.click(function(s){s.preventDefault(),i.displayLayoutDirectory(e,t+1)}),""!==e&&s.find(".so-directory-browse").html(panelsOptions.loc.search_results_header+'"<em>'+_.escape(e)+'</em>"'),s.find(".so-screenshot").each(function(){var e=jQuery(this),t=e.find("a");t.css("height",t.width()/4*3+"px").addClass("so-loading");var i=o("<img/>").attr("src",e.data("src")).load(function(){t.removeClass("so-loading").css("height","auto"),i.appendTo(t).hide().fadeIn("fast")})})}},"json"):(s.removeClass("so-panels-loading").html(o("#siteorigin-panels-directory-enable").html()),void s.find(".so-panels-enable-directory").click(function(l){l.preventDefault(),o.get(panelsOptions.ajaxurl,{action:"so_panels_directory_enable"},function(){}),panelsOptions.directory_enabled=!0,s.addClass("so-panels-loading"),i.displayLayoutDirectory(e,t)}))},directoryClickHandler:function(e){e.preventDefault();var t=jQuery(e.currentTarget),i=this;return confirm(panelsOptions.loc.prebuilt_confirm)?(this.setStatusMessage(panelsOptions.loc.prebuilt_loading,!0),void o.get(panelsOptions.ajaxurl,{action:"so_panels_directory_item",layout_slug:t.data("layout-slug")},function(e){void 0!==e.error?alert(e.error):(i.setStatusMessage("",!1),i.builder.addHistoryEntry("prebuilt_loaded"),i.builder.model.loadPanelsData(e),i.closeDialog())})):!1},searchHandler:function(e){if("directory"!==this.currentTab){if(this.currentTab===!1||"undefined"==typeof this.layoutCache[this.currentTab])return!1;this.displayLayouts(this.currentTab,this.layoutCache[this.currentTab])}else 13===e.keyCode&&this.displayLayoutDirectory(o(e.currentTarget).val(),1)}})},{}],8:[function(e,t,i){var s=window.panels,o=jQuery;t.exports=s.view.dialog.extend({cellPreviewTemplate:_.template(o("#siteorigin-panels-dialog-row-cell-preview").html().panelsProcessTemplate()),events:{"click .so-close":"closeDialog","click .so-toolbar .so-save":"saveHandler","click .so-toolbar .so-insert":"insertHandler","click .so-toolbar .so-delete":"deleteHandler","click .so-toolbar .so-duplicate":"duplicateHandler","change .row-set-form > *":"setCellsFromForm","click .row-set-form button.set-row":"setCellsFromForm"},dialogClass:"so-panels-dialog-row-edit",styleType:"row",dialogType:"edit",row:{cells:[],style:{}},initializeDialog:function(){this.on("open_dialog",function(){"undefined"!=typeof this.model&&0!==this.model.cells.length?this.setRowModel(this.model):this.setRowModel(null),this.regenerateRowPreview()},this),this.row={cells:[.5,.5],style:{}}},setRowDialogType:function(e){this.dialogType=e},render:function(e){this.renderDialog(this.parseDialogContent(o("#siteorigin-panels-dialog-row").html(),{dialogType:this.dialogType})),"edit"===this.dialogType&&(this.styles=new s.view.styles,this.styles.model=this.model,this.styles.render("row",o("#post_ID").val(),{builderType:this.builder.builderType}),this.styles.attach(this.$(".so-sidebar.so-right-sidebar")),this.styles.on("styles_loaded",function(){this.$(".so-sidebar.so-right-sidebar").removeClass("so-panels-loading")},this),this.$(".so-sidebar.so-right-sidebar").addClass("so-panels-loading")),"undefined"!=typeof this.model&&this.$("input.so-row-field").val(this.model.cells.length);return this.$("input.so-row-field").keyup(function(){o(this).trigger("change")}),this},setRowModel:function(e){return this.model=e,_.isEmpty(this.model)?this:(this.row={cells:this.model.cells.map(function(e){return e.get("weight")}),style:{}},this.$("input.so-row-field").val(this.model.cells.length),this)},regenerateRowPreview:function(){var e=this,t=this.$(".row-preview");t.empty();var i;_.each(this.row.cells,function(s,l){var n=o(this.cellPreviewTemplate({weight:s}));t.append(n);var a,r=n.prev();0!==r.length&&(a=o('<div class="resize-handle"></div>'),a.appendTo(n).dblclick(function(){var t=e.row.cells[l]+e.row.cells[l-1];e.row.cells[l]=e.row.cells[l-1]=t/2,e.scaleRowWidths()}),a.draggable({axis:"x",containment:t,start:function(e,t){var i=n.clone().appendTo(t.helper).css({position:"absolute",top:"0",width:n.outerWidth(),left:6,height:n.outerHeight()});i.find(".resize-handle").remove();var s=r.clone().appendTo(t.helper).css({position:"absolute",top:"0",width:r.outerWidth(),right:6,height:r.outerHeight()});s.find(".resize-handle").remove(),o(this).data({newCellClone:i,prevCellClone:s}),n.find("> .preview-cell-in").css("visibility","hidden"),r.find("> .preview-cell-in").css("visibility","hidden")},drag:function(i,s){var n=e.row.cells[l]-(s.position.left+6)/t.width(),a=e.row.cells[l-1]+(s.position.left+6)/t.width();s.helper.offset().left-t.offset().left-6;o(this).data("newCellClone").css("width",t.width()*n).find(".preview-cell-weight").html(Math.round(1e3*n)/10),o(this).data("prevCellClone").css("width",t.width()*a).find(".preview-cell-weight").html(Math.round(1e3*a)/10)},stop:function(i,s){o(this).data("newCellClone").remove(),o(this).data("prevCellClone").remove(),n.find(".preview-cell-in").css("visibility","visible"),r.find(".preview-cell-in").css("visibility","visible");var a=s.position.left+6,d=a/t.width();e.row.cells[l]-d>.02&&e.row.cells[l-1]+d>.02&&(e.row.cells[l]-=d,e.row.cells[l-1]+=d),e.scaleRowWidths(),s.helper.css("left",-6)}})),n.find(".preview-cell-weight").click(function(s){e.$(".resize-handle").css("pointer-event","none").draggable("disable"),t.find(".preview-cell-weight").each(function(){var s=jQuery(this).hide();o('<input type="text" class="preview-cell-weight-input no-user-interacted" />').val(parseFloat(s.html())).insertAfter(s).focus(function(){clearTimeout(i)}).keyup(function(e){9!==e.keyCode&&o(this).removeClass("no-user-interacted"),13===e.keyCode&&(e.preventDefault(),o(this).blur())}).keydown(function(e){if(9===e.keyCode){e.preventDefault();var i=t.find(".preview-cell-weight-input"),s=i.index(o(this));s===i.length-1?i.eq(0).focus().select():i.eq(s+1).focus().select()}}).blur(function(){t.find(".preview-cell-weight-input").each(function(t,i){isNaN(parseFloat(o(i).val()))&&o(i).val(Math.floor(1e3*e.row.cells[t])/10)}),i=setTimeout(function(){if(0===t.find(".preview-cell-weight-input").length)return!1;var i=[],s=[],l=0,n=0;if(t.find(".preview-cell-weight-input").each(function(t,a){var r=parseFloat(o(a).val());r=isNaN(r)?1/e.row.cells.length:Math.round(10*r)/1e3;var d=!o(a).hasClass("no-user-interacted");i.push(r),s.push(d),d?l+=r:n+=r}),l>0&&n>0&&1-l>0)for(var a=0;a<i.length;a++)s[a]||(i[a]=i[a]/n*(1-l));var r=_.reduce(i,function(e,t){return e+t});i=i.map(function(e){return e/r}),Math.min.apply(Math,i)>.01&&(e.row.cells=i),t.find(".preview-cell").each(function(t,i){o(i).animate({width:Math.round(1e3*e.row.cells[t])/10+"%"},250),o(i).find(".preview-cell-weight-input").val(Math.round(1e3*e.row.cells[t])/10)}),t.find(".preview-cell").css("overflow","visible"),setTimeout(function(){e.regenerateRowPreview()},260)},100)}).click(function(){o(this).select()})}),o(this).siblings(".preview-cell-weight-input").select()})},this)},scaleRowWidths:function(){var e=this;this.$(".row-preview .preview-cell").each(function(t,i){o(i).css("width",100*e.row.cells[t]+"%").find(".preview-cell-weight").html(Math.round(1e3*e.row.cells[t])/10)})},setCellsFromForm:function(){var e={cells:parseInt(this.$el.find('.row-set-form input[name="cells"]').val()),ratio:parseFloat(this.$el.find('.row-set-form select[name="ratio"]').val()),direction:this.$el.find('.row-set-form select[name="ratio_direction"]').val()},t=[];if(isNaN(e.cells)||isNaN(e.ratio))return!1;var i=this.row.cells.length!==e.cells;e.cells<1?(this.$el.find('.row-set-form input[name="cells"]').val(1),e.cells=1):e.cells>20&&(this.$el.find('.row-set-form input[name="cells"]').val(20),e.cells=20);for(var s=1,l=0;l<e.cells;l++)t.push(s),s*=e.ratio;var n=_.reduce(t,function(e,t){return e+t});if(t=_.map(t,function(e){return e/n}),t=_.filter(t,function(e){return e>.01}),"left"===e.direction&&(t=t.reverse()),this.row.cells=t,i)this.regenerateRowPreview();else{var a=this;this.$el.find(".preview-cell").each(function(e,t){o(t).animate({width:Math.round(1e3*a.row.cells[e])/10+"%"},250),o(t).find(".preview-cell-weight").html(Math.round(1e3*a.row.cells[e])/10)}),this.$el.find(".preview-cell").css("overflow","visible"),setTimeout(function(){a.regenerateRowPreview()},260)}this.$el.find(".row-set-form .so-button-row-set").removeClass("button-primary")},tabClickHandler:function(e){"#row-layout"===e.attr("href")?this.$(".so-panels-dialog").addClass("so-panels-dialog-has-right-sidebar"):this.$(".so-panels-dialog").removeClass("so-panels-dialog-has-right-sidebar")},updateModel:function(){if(this.model.setCells(this.row.cells),"undefined"!=typeof this.styles&&this.styles.stylesLoaded){var e={};try{e=this.getFormValues(".so-sidebar .so-visual-styles").style}catch(t){}this.model.set("style",e)}},insertHandler:function(){this.builder.addHistoryEntry("row_added"),this.model=new s.model.row,this.updateModel();var e=this.builder.getActiveCell({createCell:!1,defaultPosition:"last"}),t={};return null!==e&&(t.at=this.builder.model.rows.indexOf(e.row)+1),this.model.collection=this.builder.model.rows,this.builder.model.rows.add(this.model,t),this.closeDialog(),!1},saveHandler:function(){return this.builder.addHistoryEntry("row_edited"),this.updateModel(),this.closeDialog(),!1},deleteHandler:function(){return this.model.trigger("visual_destroy"),this.closeDialog(),!1},duplicateHandler:function(){this.builder.addHistoryEntry("row_duplicated");var e=this.model.clone(this.builder.model);return this.builder.model.rows.add(e,{at:this.builder.model.rows.indexOf(this.model)+1}),this.closeDialog(),!1}})},{}],9:[function(e,t,i){var s=window.panels,o=jQuery;t.exports=s.view.dialog.extend({builder:null,sidebarWidgetTemplate:_.template(o("#siteorigin-panels-dialog-widget-sidebar-widget").html().panelsProcessTemplate()),dialogClass:"so-panels-dialog-edit-widget",widgetView:!1,savingWidget:!1,events:{"click .so-close":"saveHistory","click .so-nav.so-previous":"navToPrevious","click .so-nav.so-next":"navToNext","click .so-toolbar .so-delete":"deleteHandler","click .so-toolbar .so-duplicate":"duplicateHandler"},initializeDialog:function(){this.model.on("change:values",this.handleChangeValues,this),this.model.on("destroy",this.remove,this)},render:function(){this.renderDialog(this.parseDialogContent(o("#siteorigin-panels-dialog-widget").html(),{})),this.loadForm(),"undefined"!=typeof panelsOptions.widgets[this.model.get("class")]?this.$(".so-title .widget-name").html(panelsOptions.widgets[this.model.get("class")].title):this.$(".so-title .widget-name").html(panelsOptions.loc.missing_widget.title),this.styles=new s.view.styles,this.styles.model=this.model,this.styles.render("widget",o("#post_ID").val(),{builderType:this.builder.builderType}),this.styles.attach(this.$(".so-sidebar.so-right-sidebar")),this.styles.on("styles_loaded",function(){this.$(".so-sidebar.so-right-sidebar").removeClass("so-panels-loading")},this),this.$(".so-sidebar.so-right-sidebar").addClass("so-panels-loading")},getPrevDialog:function(){var e=this.builder.$(".so-cells .cell .so-widget");if(e.length<=1)return!1;var t=e.index(this.widgetView.$el);if(0===t)return!1;var i=e.eq(t-1).data("view");return"undefined"==typeof i?!1:i.getEditDialog()},getNextDialog:function(){var e=this.builder.$(".so-cells .cell .so-widget");if(e.length<=1)return!1;var t=e.index(this.widgetView.$el);if(t===e.length-1)return!1;var i=e.eq(t+1).data("view");return"undefined"==typeof i?!1:i.getEditDialog()},loadForm:function(){if(this.$el.find("> *").length){var e=this;this.$el.find(".so-content").addClass("so-panels-loading");var t={action:"so_panels_widget_form",widget:this.model.get("class"),instance:JSON.stringify(this.model.get("values")),raw:this.model.get("raw")};o.post(panelsOptions.ajaxurl,t,function(t){var i=t.replace(/{\$id}/g,e.model.cid);e.$el.find(".so-content").removeClass("so-panels-loading").html(i),e.trigger("form_loaded",e),e.$el.find(".panel-dialog").trigger("panelsopen"),e.on("close_dialog",e.saveWidget,e)},"html")}},saveWidget:function(){if(this.savingWidget=!0,!this.model.get("missing")){var e=this.getFormValues();"undefined"==typeof e.widgets?e={}:(e=e.widgets,e=e[Object.keys(e)[0]]),this.model.setValues(e),this.model.set("raw",!0)}if(this.styles.stylesLoaded){var t={};try{t=this.getFormValues(".so-sidebar .so-visual-styles").style}catch(i){}this.model.set("style",t)}this.savingWidget=!1},handleChangeValues:function(){this.savingWidget||this.loadForm()},saveHistory:function(){this.builder.addHistoryEntry("widget_edited"),this.closeDialog()},deleteHandler:function(){return this.builder.liveEditor.displayed?(this.model.destroy(),this.builder.liveEditor.refreshWidgets()):this.model.trigger("visual_destroy"),this.closeDialog(),!1},duplicateHandler:function(){return this.model.trigger("user_duplicate"),this.builder.liveEditor.displayed&&this.builder.liveEditor.refreshWidgets(),this.closeDialog(),!1}})},{}],10:[function(e,t,i){var s=window.panels,o=jQuery;t.exports=s.view.dialog.extend({builder:null,widgetTemplate:_.template(o("#siteorigin-panels-dialog-widgets-widget").html().panelsProcessTemplate()),filter:{},dialogClass:"so-panels-dialog-add-widget",events:{"click .so-close":"closeDialog","click .widget-type":"widgetClickHandler","keyup .so-sidebar-search":"searchHandler"},initializeDialog:function(){this.on("open_dialog",function(){this.filter.search="",this.filterWidgets(this.filter)},this),this.on("open_dialog_complete",function(){this.$(".so-sidebar-search").val("").focus(),this.balanceWidgetHeights()}),this.on("tab_click",this.tabClickHandler,this)},render:function(){this.renderDialog(this.parseDialogContent(o("#siteorigin-panels-dialog-widgets").html(),{})),_.each(panelsOptions.widgets,function(e){var t=o(this.widgetTemplate({title:e.title,description:e.description}));"undefined"==typeof e.icon&&(e.icon="dashicons dashicons-admin-generic"),"undefined"!=typeof e.icon&&o('<span class="widget-icon" />').addClass(e.icon).prependTo(t.find(".widget-type-wrapper")),t.data("class",e["class"]).appendTo(this.$el.find(".widget-type-list"))},this);var e=this.$el.find(".so-sidebar-tabs");_.each(panelsOptions.widget_dialog_tabs,function(t){o(this.dialogTabTemplate({title:t.title})).data({message:t.message,filter:t.filter}).appendTo(e)},this),this.initTabs();var t=this;o(window).resize(function(){t.balanceWidgetHeights()})},tabClickHandler:function(e){this.filter=e.parent().data("filter"),this.filter.search=this.$el.find(".so-sidebar-search").val();var t=e.parent().data("message");return _.isEmpty(t)&&(t=""),this.$(".so-toolbar .so-status").html(t),this.filterWidgets(this.filter),!1},searchHandler:function(e){this.filter.search=o(e.target).val(),this.filterWidgets(this.filter)},filterWidgets:function(e){"undefined"==typeof e&&(e={}),"undefined"==typeof e.groups&&(e.groups=""),this.$el.find(".widget-type-list .widget-type").each(function(){var t,i=jQuery(this),s=i.data("class"),o="undefined"!=typeof panelsOptions.widgets[s]?panelsOptions.widgets[s]:null;t=0===e.groups.length?!0:null!==o&&_.intersection(e.groups,panelsOptions.widgets[s].groups).length?!0:!1,t&&"undefined"!=typeof e.search&&""!==e.search&&-1===o.title.toLowerCase().indexOf(e.search.toLowerCase())&&(t=!1),t?i.show():i.hide()}),this.balanceWidgetHeights()},widgetClickHandler:function(e){this.builder.addHistoryEntry("widget_added");var t=o(e.currentTarget),i=new s.model.widget({"class":t.data("class")});i.cell=this.builder.getActiveCell(),i.cell.widgets.add(i),this.closeDialog()},balanceWidgetHeights:function(e){var t=[[]],i=null,s=Math.round(this.$(".widget-type").parent().width()/this.$(".widget-type").width());this.$(".widget-type").css("clear","none").filter(":visible").each(function(e,t){e%s===0&&0!==e&&o(t).css("clear","both")}),this.$(".widget-type-wrapper").css("height","auto").filter(":visible").each(function(e,s){var l=o(s);null!==i&&i.position().top!==l.position().top&&(t[t.length]=[]),i=l,t[t.length-1].push(l)}),_.each(t,function(e,t){var i=_.max(e.map(function(e){return e.height()}));_.each(e,function(e){e.height(i)})})}})},{}],11:[function(e,t,i){var s=window.panels,o=jQuery;t.exports=function(){return this.each(function(){var e=jQuery(this),t=e.closest("form").find(".widget-id").val();if(!("undefined"!=typeof t&&t.indexOf("__i__")>-1)){var i=new s.model.builder,l=new s.view.builder({model:i}),n=e.closest(".so-panels-dialog-wrapper").data("view");"undefined"!=typeof n&&(n.on("close_dialog",function(){i.refreshPanelsData()}),n.on("open_dialog_complete",function(){l.trigger("builder_resize")}),n.model.on("destroy",function(){i.emptyRows().destroy()}),l.setDialogParents(panelsOptions.loc.layout_widget,n));var a=Boolean(e.closest(".widget-content").length);l.render().attach({container:e,dialog:a,type:e.data("type")}).setDataField(e.find("input.panels-data")),a?(l.setDialogParents(panelsOptions.loc.layout_widget,l.dialog),e.find(".siteorigin-panels-display-builder").click(function(){l.dialog.openDialog()})):e.find(".siteorigin-panels-display-builder").parent().remove(),o(document).trigger("panels_setup",l)}})}},{}],12:[function(e,t,i){String.prototype.panelsProcessTemplate=function(){var e=this;return e=e.replace(/{{%/g,"<%"),e=e.replace(/%}}/g,"%>"),e=e.trim()};var s={};window.panels=s,window.siteoriginPanels=s,s.model={},s.model.widget=e("./model/widget"),s.model.cell=e("./model/cell"),s.model.row=e("./model/row"),s.model.builder=e("./model/builder"),s.model.historyEntry=e("./model/history-entry"),s.collection={},s.collection.widgets=e("./collection/widgets"),s.collection.cells=e("./collection/cells"),s.collection.rows=e("./collection/rows"),s.collection.historyEntries=e("./collection/history-entries"),s.view={},s.view.widget=e("./view/widget"),s.view.cell=e("./view/cell"),s.view.row=e("./view/row"),s.view.builder=e("./view/builder"),s.view.dialog=e("./view/dialog"),s.view.styles=e("./view/styles"),s.view.liveEditor=e("./view/live-editor"),s.dialog={},s.dialog.builder=e("./dialog/builder"),s.dialog.widgets=e("./dialog/widgets"),s.dialog.widget=e("./dialog/widget"),s.dialog.prebuilt=e("./dialog/prebuilt"),s.dialog.row=e("./dialog/row"),s.dialog.history=e("./dialog/history"),s.utils={},s.utils.menu=e("./utils/menu"),jQuery.fn.soPanelsSetupBuilderWidget=e("./jquery/setup-builder-widget"),jQuery(function(e){var t=!1,i=!1,s=!1,o=!1,l="";if(e("#siteorigin-panels-metabox").length&&e("form#post").length)t=e("#siteorigin-panels-metabox"),i=e("#siteorigin-panels-metabox .siteorigin-panels-data-field"),s=e("form#post"),o=e("#post_ID").val(),l="editor_attached";else if(e(".siteorigin-panels-builder-form").length){var n=jQuery(".siteorigin-panels-builder-form");t=n.find(".siteorigin-panels-builder"),i=n.find('input[name="panels_data"]'),s=n,o=e("#panels-home-page").data("post-id"),l=n.data("type")}if(t!==!1){var a=window.siteoriginPanels,r=new a.model.builder,d=new a.view.builder({model:r});d.render().attach({container:t,type:l}).setDataField(i).attachToEditor().addLiveEditor(o).addHistoryBrowser(),d.liveEditor.refreshPreview(),s.submit(function(e){r.refreshPanelsData()}),t.removeClass("so-panels-loading"),e(document).trigger("panels_setup",d,window.panels)}e(document).on("widget-added",function(t,i){e(i).find(".siteorigin-page-builder-widget").soPanelsSetupBuilderWidget()}),e("body").hasClass("wp-customizer")||e(function(){e(".siteorigin-page-builder-widget").soPanelsSetupBuilderWidget()})})},{"./collection/cells":1,"./collection/history-entries":2,"./collection/rows":3,"./collection/widgets":4,"./dialog/builder":5,"./dialog/history":6,"./dialog/prebuilt":7,"./dialog/row":8,"./dialog/widget":9,"./dialog/widgets":10,"./jquery/setup-builder-widget":11,"./model/builder":13,"./model/cell":14,"./model/history-entry":15,"./model/row":16,"./model/widget":17,"./utils/menu":18,"./view/builder":19,"./view/cell":20,"./view/dialog":21,"./view/live-editor":22,"./view/row":23,"./view/styles":24,"./view/widget":25}],13:[function(e,t,i){t.exports=Backbone.Model.extend({rows:{},defaults:{data:{widgets:[],grids:[],grid_cells:[]}},initialize:function(){this.rows=new panels.collection.rows},addRow:function(e,t){t=_.extend({noAnimate:!1},t);var i=new panels.model.row({collection:this.rows});return i.setCells(e),i.builder=this,this.rows.add(i,t),i},loadPanelsData:function(e){this.emptyRows(),this.set("data",e,{silent:!0});var t=[];if("undefined"==typeof e.grid_cells)return void this.trigger("load_panels_data");for(var i,s=0;s<e.grid_cells.length;s++)i=parseInt(e.grid_cells[s].grid),"undefined"==typeof t[i]&&(t[i]=[]),t[i].push(parseFloat(e.grid_cells[s].weight));var o=this;_.each(t,function(t,i){var s=o.addRow(t,{noAnimate:!0});"undefined"!=typeof e.grids[i].style&&s.set("style",e.grids[i].style)}),"undefined"!=typeof e.widgets&&(_.each(e.widgets,function(e){try{var t=null;"undefined"!=typeof e.panels_info?(t=e.panels_info,delete e.panels_info):(t=e.info,delete e.info);var i=o.rows.at(parseInt(t.grid)),s=i.cells.at(parseInt(t.cell)),l=new panels.model.widget({"class":t["class"],values:e});"undefined"!=typeof t.style&&l.set("style",t.style),l.cell=s,s.widgets.add(l,{noAnimate:!0})}catch(n){}}),this.trigger("load_panels_data"))},getPanelsData:function(){var e={widgets:[],grids:[],grid_cells:[]},t=0;return this.rows.each(function(i,s){i.cells.each(function(i,o){
2
- i.widgets.each(function(i,l){var n=_.extend(_.clone(i.get("values")),{panels_info:{"class":i.get("class"),raw:i.get("raw"),grid:s,cell:o,id:t++,style:i.get("style")}});e.widgets.push(n)}),e.grid_cells.push({grid:s,weight:i.get("weight")})}),e.grids.push({cells:i.cells.length,style:i.get("style")})}),e},refreshPanelsData:function(){var e=JSON.stringify(this.get("data")),t=this.getPanelsData();this.set("data",t,{silent:!0}),JSON.stringify(t)!==e&&(this.trigger("change"),this.trigger("change:data"))},emptyRows:function(){return _.invoke(this.rows.toArray(),"destroy"),this.rows.reset(),this}})},{}],14:[function(e,t,i){t.exports=Backbone.Model.extend({widgets:{},row:null,defaults:{weight:0},initialize:function(){this.widgets=new panels.collection.widgets,this.on("destroy",this.onDestroy,this)},onDestroy:function(){_.invoke(this.widgets.toArray(),"destroy"),this.widgets.reset()},clone:function(e,t){"undefined"==typeof e&&(e=this.row),t=_.extend({cloneWidgets:!0},t);var i=new this.constructor(this.attributes);return i.set("collection",e.cells,{silent:!0}),i.row=e,t.cloneWidgets&&this.widgets.each(function(e){i.widgets.add(e.clone(i,t),{silent:!0})}),i}})},{}],15:[function(e,t,i){t.exports=Backbone.Model.extend({defaults:{text:"",data:"",time:null,count:1}})},{}],16:[function(e,t,i){t.exports=Backbone.Model.extend({cells:{},builder:null,defaults:{style:{}},initialize:function(){this.cells=new panels.collection.cells,this.on("destroy",this.onDestroy,this)},setCells:function(e){var t=this;if(0===this.cells.length)_.each(e,function(e){var i=new panels.model.cell({weight:e,collection:t.cells});i.row=t,t.cells.add(i)});else{if(e.length>this.cells.length)for(var i=this.cells.length;i<e.length;i++){var s=new panels.model.cell({weight:e[e.length+i],collection:t.cells});s.row=this,t.cells.add(s)}else if(e.length<this.cells.length){var o=this.cells.at(e.length-1);_.each(this.cells.slice(e.length,this.cells.length),function(e){for(var t=e.widgets.models.slice(0),i=0;i<t.length;i++)t[i].moveToCell(o,{silent:!1});e.destroy()})}this.cells.each(function(t,i){t.set("weight",e[i])})}this.reweightCells()},reweightCells:function(){var e=0;this.cells.each(function(t){e+=t.get("weight")}),this.cells.each(function(t){t.set("weight",t.get("weight")/e)}),this.trigger("reweight_cells")},onDestroy:function(){_.invoke(this.cells.toArray(),"destroy"),this.cells.reset()},clone:function(e,t){"undefined"==typeof e&&(e=this.builder),t=_.extend({cloneCells:!0},t);var i=new this.constructor(this.attributes);return i.set("collection",e.rows,{silent:!0}),i.builder=e,t.cloneCells&&this.cells.each(function(e){i.cells.add(e.clone(i,t),{silent:!0})}),i}})},{}],17:[function(e,t,i){t.exports=Backbone.Model.extend({cell:null,defaults:{"class":null,missing:!1,values:{},raw:!1,styles:{}},initialize:function(){var e=this.get("class");"undefined"!=typeof panelsOptions.widgets[e]&&panelsOptions.widgets[e].installed||this.set("missing",!0)},getWidgetField:function(e){return"undefined"==typeof panelsOptions.widgets[this.get("class")]?"title"===e||"description"===e?panelsOptions.loc.missing_widget[e]:"":panelsOptions.widgets[this.get("class")][e]},moveToCell:function(e,t){return t=_.extend({silent:!0},t),this.cell.cid===e.cid?!1:(this.cell=e,this.collection.remove(this,t),e.widgets.add(this,t),!0)},triggerEdit:function(){this.trigger("user_edit",this)},triggerDuplicate:function(){this.trigger("user_duplicate",this)},setValues:function(e){var t=!1;JSON.stringify(e)!==JSON.stringify(this.get("values"))&&(t=!0),this.set("values",e,{silent:!0}),t&&(this.trigger("change",this),this.trigger("change:values"))},clone:function(e,t){"undefined"==typeof e&&(e=this.cell);var i=new this.constructor(this.attributes),s=JSON.parse(JSON.stringify(this.get("values"))),o=function(e){return _.each(e,function(t,i){"string"==typeof i&&"_"===i[0]?delete e[i]:_.isObject(e[i])&&o(e[i])}),e};return s=o(s),"SiteOrigin_Panels_Widgets_Layout"===this.get("class")&&(s.builder_id=Math.random().toString(36).substr(2)),i.set("values",s,{silent:!0}),i.set("collection",e.widgets,{silent:!0}),i.cell=e,i.isDuplicate=!0,i},getTitle:function(){var e=panelsOptions.widgets[this.get("class")];if("undefined"==typeof e)return this.get("class").replace(/_/g," ");if("undefined"!=typeof e.panels_title&&e.panels_title===!1)return panelsOptions.widgets[this.get("class")].description;var t=this.get("values"),i=["title","text"];for(var s in t)t.hasOwnProperty(s)&&i.push(s);i=_.uniq(i);for(var o in i)if("undefined"!=typeof t[i[o]]&&"string"==typeof t[i[o]]&&""!==t[i[o]]&&"on"!==t[i[o]]&&"_"!==i[o][0]&&!jQuery.isNumeric(t[i[o]])){var l=t[i[o]];l=l.replace(/<\/?[^>]+(>|$)/g,"");var n=l.split(" ");return n=n.slice(0,20),n.join(" ")}return this.getWidgetField("description")}})},{}],18:[function(e,t,i){var s=(window.panels,jQuery);t.exports=Backbone.View.extend({wrapperTemplate:_.template(jQuery("#siteorigin-panels-context-menu").html().panelsProcessTemplate()),sectionTemplate:_.template(jQuery("#siteorigin-panels-context-menu-section").html().panelsProcessTemplate()),contexts:[],active:!1,events:{"keyup .so-search-wrapper input":"searchKeyUp"},initialize:function(){this.listenContextMenu(),this.render(),this.attach()},listenContextMenu:function(){var e=this;s(window).on("contextmenu",function(t){return e.active&&!e.isOverEl(e.$el,t)?(e.closeMenu(),e.active=!1,t.preventDefault(),!1):e.active?!0:(e.active=!1,e.trigger("activate_context",t,e),void(e.active&&(t.preventDefault(),e.openMenu({left:t.pageX,top:t.pageY}))))})},render:function(){this.setElement(this.wrapperTemplate())},attach:function(){this.$el.appendTo("body")},openMenu:function(e){this.trigger("open_menu"),s(window).on("keyup",{menu:this},this.keyboardListen),s(window).on("click",{menu:this},this.clickOutsideListen),e.left+this.$el.outerWidth()+10>=s(window).width()&&(e.left=s(window).width()-this.$el.outerWidth()-10),e.left<=0&&(e.left=10),e.top+this.$el.outerHeight()-s(window).scrollTop()+10>=s(window).height()&&(e.top=s(window).height()+s(window).scrollTop()-this.$el.outerHeight()-10),e.left<=0&&(e.left=10),this.$el.css({left:e.left+1,top:e.top+1}).show(),this.$(".so-search-wrapper input").focus()},closeMenu:function(){this.trigger("close_menu"),s(window).off("keyup",this.keyboardListen),s(window).off("click",this.clickOutsideListen),this.active=!1,this.$el.empty().hide()},keyboardListen:function(e){var t=e.data.menu;switch(e.which){case 27:t.closeMenu()}},clickOutsideListen:function(e){var t=e.data.menu;3!==e.which&&t.$el.is(":visible")&&!t.isOverEl(t.$el,e)&&t.closeMenu()},addSection:function(e,t,i){var o=this;e=_.extend({display:5,defaultDisplay:!1,search:!0,sectionTitle:"",searchPlaceholder:"",titleKey:"title"},e);var l=s(this.sectionTemplate({settings:e,items:t}));this.$el.append(l),l.find(".so-item").click(function(){var e=jQuery(this);i(e.data("key")),o.closeMenu()}),l.data("settings",e).find(".so-search-wrapper input").trigger("keyup"),this.active=!0},searchKeyUp:function(e){var t=jQuery(e.currentTarget),i=t.closest(".so-section"),o=i.data("settings");if(38===e.which||40===e.which){var l=i.find("ul li:visible"),n=l.filter(".so-active").eq(0);if(0!==n.length){l.removeClass("so-active");var a=l.index(n);38===e.which?n=0>a-1?l.last():l.eq(a-1):40===e.which&&(n=a+1>=l.length?l.first():l.eq(a+1))}else 38===e.which?n=l.last():40===e.which&&(n=l.first());return n.addClass("so-active"),!1}if(13===e.which)return 1===i.find("ul li:visible").length?(i.find("ul li:visible").trigger("click"),!1):(i.find("ul li.so-active:visible").trigger("click"),!1);if(""===t.val())if(o.defaultDisplay){i.find(".so-item").hide();for(var r=0;r<o.defaultDisplay.length;r++)i.find('.so-item[data-key="'+o.defaultDisplay[r]+'"]').show()}else i.find(".so-item").show();else i.find(".so-item").hide().each(function(){var e=s(this);-1!==e.html().toLowerCase().indexOf(t.val().toLowerCase())&&e.show()});i.find(".so-item:visible:gt("+(o.display-1)+")").hide(),0===i.find(".so-item:visible").length&&""!==t.val()?i.find(".so-no-results").show():i.find(".so-no-results").hide()},isOverEl:function(e,t){var i=[[e.offset().left,e.offset().top],[e.offset().left+e.outerWidth(),e.offset().top+e.outerHeight()]];return t.pageX>=i[0][0]&&t.pageX<=i[1][0]&&t.pageY>=i[0][1]&&t.pageY<=i[1][1]}})},{}],19:[function(e,t,i){var s=window.panels,o=jQuery;t.exports=Backbone.View.extend({template:_.template(o("#siteorigin-panels-builder").html().panelsProcessTemplate()),dialogs:{},rowsSortable:null,dataField:!1,currentData:"",attachedToEditor:!1,liveEditor:!1,menu:!1,builderType:"",events:{"click .so-tool-button.so-widget-add":"displayAddWidgetDialog","click .so-tool-button.so-row-add":"displayAddRowDialog","click .so-tool-button.so-prebuilt-add":"displayAddPrebuiltDialog","click .so-tool-button.so-history":"displayHistoryDialog","click .so-tool-button.so-live-editor":"displayLiveEditor"},rows:null,initialize:function(){var e=this;return this.dialogs={widgets:new s.dialog.widgets,row:new s.dialog.row,prebuilt:new s.dialog.prebuilt},_.each(this.dialogs,function(t,i,s){s[i].setBuilder(e)}),this.dialogs.row.setRowDialogType("create"),this.model.rows.on("add",this.onAddRow,this),o(window).resize(function(t){t.target===window&&e.trigger("builder_resize")}),this.model.on("change:data",this.storeModelData,this),this.on("content_change",this.handleContentChange,this),this.on("display_builder",this.handleDisplayBuilder,this),this.model.on("change:data load_panels_data",this.toggleWelcomeDisplay,this),this.menu=new s.utils.menu({}),this.menu.on("activate_context",this.activateContextMenu,this),this},render:function(){return this.$el.html(this.template()),this.$el.attr("id","siteorigin-panels-builder-"+this.cid).addClass("so-builder-container"),this.trigger("builder_rendered"),this},attach:function(e){return e=_.extend({type:"",container:!1,dialog:!1},e),e.dialog?(this.dialog=new s.dialog.builder,this.dialog.builder=this):(this.$el.appendTo(e.container),this.metabox=e.container.closest(".postbox"),this.initSortable(),this.trigger("attached_to_container",e.container)),this.builderType=e.type,this},attachToEditor:function(){if("undefined"==typeof this.metabox)return this;this.attachedToEditor=!0;var e=this.metabox,t=this;o("#wp-content-wrap .wp-editor-tabs").find(".wp-switch-editor").click(function(e){e.preventDefault(),o("#wp-content-editor-container, #post-status-info").show(),o("#wp-content-wrap").removeClass("panels-active"),o("#content-resize-handle").show(),t.trigger("hide_builder")}).end().append(o('<a id="content-panels" class="hide-if-no-js wp-switch-editor switch-panels">'+e.find(".hndle span").html()+"</a>").click(function(i){i.preventDefault();jQuery(this);o("#wp-content-wrap, #post-status-info").hide(),e.show().find("> .inside").show(),o(window).resize(),o(document).scroll(),t.trigger("display_builder")})),e.find(".so-switch-to-standard").click(function(i){i.preventDefault(),confirm(panelsOptions.loc.confirm_stop_builder)&&(t.addHistoryEntry("back_to_editor"),t.model.loadPanelsData(!1),o("#wp-content-wrap, #post-status-info").show(),e.hide(),o(window).resize())}).show(),e.insertAfter("#wp-content-wrap").hide().addClass("attached-to-editor");var i=this.model.get("data");("undefined"!=typeof i.widgets&&0!==_.size(i.widgets)||"undefined"!=typeof i.grids&&0!==_.size(i.grids))&&o("#content-panels.switch-panels").click();var s=function(){var e=t.$(".so-builder-toolbar"),i=o(window).scrollTop()-t.$el.offset().top;"fixed"===o("#wpadminbar").css("position")&&(i+=o("#wpadminbar").outerHeight());var s={top:0,bottom:t.$el.outerHeight()-e.outerHeight()+20};i>s.top&&i<s.bottom?"fixed"!==e.css("position")&&e.css({top:o("#wpadminbar").outerHeight(),left:t.$el.offset().left,width:t.$el.outerWidth(),position:"fixed"}):e.css({top:Math.min(Math.max(i,0),t.$el.outerHeight()-e.outerHeight()+20),left:0,width:"100%",position:"absolute"}),t.$el.css("padding-top",e.outerHeight())};return o(window).resize(s),o(document).scroll(s),s(),this},initSortable:function(){var e=(this.$el,this);this.rowsSortable=this.$el.find(".so-rows-container").sortable({appendTo:"#wpwrap",items:".so-row-container",handle:".so-row-move",axis:"y",tolerance:"pointer",scroll:!1,stop:function(t){e.addHistoryEntry("row_moved"),e.sortCollections()}})},refreshSortable:function(){null!==this.rowsSortable&&this.rowsSortable.sortable("refresh")},setDataField:function(e,t){if(t=_.extend({load:!0},t),this.dataField=e,this.dataField.data("builder",this),t.load&&""!==e.val()){var i;try{i=JSON.parse(this.dataField.val())}catch(s){i=""}this.model.loadPanelsData(i),this.currentData=i,this.toggleWelcomeDisplay()}return this},storeModelData:function(){var e=JSON.stringify(this.model.get("data"));o(this.dataField).val()!==e&&(o(this.dataField).val(e),o(this.dataField).trigger("change"),this.trigger("content_change"))},onAddRow:function(e,t,i){i=_.extend({noAnimate:!1},i);var o=new s.view.row({model:e});o.builder=this,o.render(),"undefined"==typeof i.at||t.length<=1?o.$el.appendTo(this.$(".so-rows-container")):o.$el.insertAfter(this.$(".so-rows-container .so-row-container").eq(i.at-1)),i.noAnimate===!1&&o.visualCreate(),this.refreshSortable(),o.resize()},displayAddWidgetDialog:function(){return this.dialogs.widgets.openDialog(),!1},displayAddRowDialog:function(){return this.dialogs.row.openDialog(),this.dialogs.row.setRowModel(),!1},displayAddPrebuiltDialog:function(){return this.dialogs.prebuilt.openDialog(),!1},displayHistoryDialog:function(){return this.dialogs.history.openDialog(),!1},getActiveCell:function(e){if(e=_.extend({createCell:!0,defaultPosition:"first"},e),0===this.$(".so-cells .cell").length){if(!e.createCell)return null;this.model.addRow([1],{noAnimate:!0})}var t=this.$(".so-cells .cell.cell-selected");return t.length||(t="last"===e.defaultPosition?this.$(".so-cells .cell").first():this.$(".so-cells .cell").last()),t.data("view").model},sortCollections:function(){var e={};this.$(".so-rows-container .so-row-container").each(function(t,i){var s=o(i);e[s.data("view").model.cid]=t,s.find(".so-cells .cell").each(function(t,i){var s=o(i);s.find(".so-widget").each(function(t,i){var s=o(i);e[s.data("view").model.cid]=t})})}),this.model.rows.models=this.model.rows.sortBy(function(t){return e[t.cid]}),this.model.rows.each(function(t){t.cells.each(function(t){t.widgets.models=t.widgets.sortBy(function(t){return e[t.cid]})})}),this.model.refreshPanelsData()},addLiveEditor:function(e){return"undefined"==typeof s.view.liveEditor?this:(this.liveEditor=new s.view.liveEditor,this.liveEditor.setPostId(e),this.liveEditor.builder=this,this.liveEditor.hasPreviewUrl()&&this.$(".so-builder-toolbar .so-live-editor").show(),this)},displayLiveEditor:function(){return"undefined"==typeof this.liveEditor?!1:(this.liveEditor.open(),!1)},addHistoryBrowser:function(){return"undefined"==typeof s.dialog.history?this:(this.dialogs.history=new s.dialog.history,this.dialogs.history.builder=this,this.dialogs.history.entries.builder=this.model,this.dialogs.history.setRevertEntry(this.model),void this.$(".so-builder-toolbar .so-history").show())},addHistoryEntry:function(e,t){"undefined"==typeof t&&(t=null),"undefined"!=typeof this.dialogs.history&&this.dialogs.history.entries.addEntry(e,t)},handleContentChange:function(){panelsOptions.copy_content&&this.attachedToEditor&&this.$el.is(":visible")&&this.model.rows.length>0&&o.post(panelsOptions.ajaxurl,{action:"so_panels_builder_content",panels_data:JSON.stringify(this.model.getPanelsData()),post_id:o("#post_ID").val()},function(e){if(""!==e){var t=o("<div />").html(e);t.find("div").each(function(){var e=o(this).contents();o(this).replaceWith(e)}),e=t.html().replace(/[\r\n]+/g,"\n").replace(/\n\s+/g,"\n").trim(),this.updateEditorContent(e)}}.bind(this)),this.liveEditor!==!1&&this.liveEditor.refreshPreview()},updateEditorContent:function(e){if("undefined"==typeof tinyMCE||null===tinyMCE.get("content")){var t=o("#content");t.val(e).trigger("change").trigger("keyup")}else{var i=tinyMCE.get("content");i.setContent(e),i.fire("change"),i.fire("keyup")}this.triggerYoastSeoChange()},triggerYoastSeoChange:function(){if(o("#yoast_wpseo_focuskw_text_input").length){var e,t=document.getElementById("yoast_wpseo_focuskw_text_input");document.createEvent?(e=document.createEvent("HTMLEvents"),e.initEvent("keyup",!0,!0)):(e=document.createEventObject(),e.eventType="keyup"),e.eventName="keyup",document.createEvent?t.dispatchEvent(e):t.fireEvent("on"+e.eventType,e)}},handleDisplayBuilder:function(){var e,t="";if("undefined"!=typeof tinyMCE&&(e=tinyMCE.get("content")),t=e&&"function"==typeof e.getContent?e.getContent():o("textarea#content").val(),_.isEmpty(this.model.get("data"))&&""!==t){if(!confirm(panelsOptions.loc.confirm_use_builder))return;var i="";if("undefined"!=typeof panelsOptions.widgets.SiteOrigin_Widget_Editor_Widget?i="SiteOrigin_Widget_Editor_Widget":"undefined"!=typeof panelsOptions.widgets.WP_Widget_Text&&(i="WP_Widget_Text"),""===i)return;this.model.loadPanelsData({grid_cells:[{grid:0,weight:1}],grids:[{cells:1}],widgets:[{filter:"1",text:t,title:"",type:"visual",panels_info:{"class":i,raw:!1,grid:0,cell:0}}]}),this.model.trigger("change"),this.model.trigger("change:data")}},setDialogParents:function(e,t){_.each(this.dialogs,function(i,s,o){o[s].setParent(e,t)}),this.on("add_dialog",function(i){i.setParent(e,t)},this)},toggleWelcomeDisplay:function(){this.model.rows.length?this.$(".so-panels-welcome-message").hide():this.$(".so-panels-welcome-message").show()},activateContextMenu:function(e,t){var i=this;if("undefined"==typeof window.panelsDialogOpen||!window.panelsDialogOpen){var s=o([]).add(i.$(".so-rows-container > .so-row-container")).add(i.$(".so-cells > .cell")).add(i.$(".cell-wrapper > .so-widget")).filter(function(i){return t.isOverEl(o(this),e)}),l=s.last().data("view");void 0!==l&&void 0!==l.buildContextualMenu&&l.buildContextualMenu(e,t)}}})},{}],20:[function(e,t,i){var s=window.panels,o=jQuery;t.exports=Backbone.View.extend({template:_.template(o("#siteorigin-panels-builder-cell").html().panelsProcessTemplate()),events:{"click .cell-wrapper":"handleCellClick"},row:null,widgetSortable:null,initialize:function(){this.model.widgets.on("add",this.onAddWidget,this)},render:function(){var e={weight:this.model.get("weight"),totalWeight:this.row.model.cells.totalWeight()};this.setElement(this.template(e)),this.$el.data("view",this);var t=this;this.model.widgets.each(function(e){var i=new s.view.widget({model:e});i.cell=t,i.render(),i.$el.appendTo(t.$(".widgets-container"))}),this.initSortable(),this.initResizable()},initSortable:function(){var e=this,t=e.row.builder.$el.attr("id");this.widgetSortable=this.$el.find(".widgets-container").sortable({placeholder:"so-widget-sortable-highlight",connectWith:"#"+t+" .so-cells .cell .widgets-container",tolerance:"pointer",scroll:!1,over:function(t,i){e.row.builder.trigger("widget_sortable_move")},stop:function(t,i){e.row.builder.addHistoryEntry("widget_moved");var s=o(i.item).data("view"),l=o(i.item).closest(".cell").data("view");s.model.moveToCell(l.model),s.cell=l,e.row.builder.sortCollections()},helper:function(e,t){var i=t.clone().css({width:t.outerWidth(),"z-index":1e4,position:"fixed"}).addClass("widget-being-dragged").appendTo("body");return t.outerWidth()>720&&i.animate({"margin-left":e.pageX-t.offset().left-240,width:480},"fast"),i}})},refreshSortable:function(){this.widgetSortable.sortable("refresh")},initResizable:function(){var e,t=this.$(".resize-handle").css("position","absolute"),i=this.row.$el,s=this;t.draggable({axis:"x",containment:i,start:function(t,i){if(e=s.$el.prev().data("view"),"undefined"==typeof e)return!1;var l=s.$el.clone().appendTo(i.helper).css({position:"absolute",top:"0",width:s.$el.outerWidth(),left:5,height:s.$el.outerHeight()});l.find(".resize-handle").remove();var n=e.$el.clone().appendTo(i.helper).css({position:"absolute",top:"0",width:e.$el.outerWidth(),right:5,height:e.$el.outerHeight()});n.find(".resize-handle").remove(),o(this).data({newCellClone:l,prevCellClone:n})},drag:function(i,l){var n=s.row.$el.width()+10,a=s.model.get("weight")-(l.position.left+t.outerWidth()/2)/n,r=e.model.get("weight")+(l.position.left+t.outerWidth()/2)/n;o(this).data("newCellClone").css("width",n*a).find(".preview-cell-weight").html(Math.round(1e3*a)/10),o(this).data("prevCellClone").css("width",n*r).find(".preview-cell-weight").html(Math.round(1e3*r)/10)},stop:function(i,l){o(this).data("newCellClone").remove(),o(this).data("prevCellClone").remove();var n=s.row.$el.width()+10,a=s.model.get("weight")-(l.position.left+t.outerWidth()/2)/n,r=e.model.get("weight")+(l.position.left+t.outerWidth()/2)/n;a>.02&&r>.02&&(s.row.builder.addHistoryEntry("cell_resized"),s.model.set("weight",a),e.model.set("weight",r),s.row.resize()),l.helper.css("left",-t.outerWidth()/2)}})},onAddWidget:function(e,t,i){i=_.extend({noAnimate:!1},i);var o=new s.view.widget({model:e});o.cell=this,"undefined"==typeof e.isDuplicate&&(e.isDuplicate=!1),o.render({loadForm:e.isDuplicate}),"undefined"==typeof i.at||t.length<=1?o.$el.appendTo(this.$(".widgets-container")):o.$el.insertAfter(this.$(".widgets-container .so-widget").eq(i.at-1)),i.noAnimate===!1&&o.visualCreate(),this.refreshSortable(),this.row.resize()},handleCellClick:function(e){this.$el.closest(".so-rows-container").find(".so-cells .cell").removeClass("cell-selected");return o(e.target).parent().addClass("cell-selected"),!1},buildContextualMenu:function(e,t){var i=this;t.addSection({sectionTitle:panelsOptions.loc.contextual.add_widget_cell,searchPlaceholder:panelsOptions.loc.contextual.search_widgets,defaultDisplay:panelsOptions.contextual.default_widgets},panelsOptions.widgets,function(e){i.row.builder.addHistoryEntry("widget_added");var t=new s.model.widget({"class":e});t.cell=i.model,t.cell.widgets.add(t)}),this.row.buildContextualMenu(e,t)}})},{}],21:[function(e,t,i){var s=(window.panels,jQuery);t.exports=Backbone.View.extend({dialogTemplate:_.template(s("#siteorigin-panels-dialog").html().panelsProcessTemplate()),dialogTabTemplate:_.template(s("#siteorigin-panels-dialog-tab").html().panelsProcessTemplate()),tabbed:!1,rendered:!1,builder:!1,className:"so-panels-dialog-wrapper",dialogClass:"",parentDialog:!1,dialogOpen:!1,events:{"click .so-close":"closeDialog","click .so-nav.so-previous":"navToPrevious","click .so-nav.so-next":"navToNext"},initialize:function(){this.once("open_dialog",this.render),this.once("open_dialog",this.attach),this.once("open_dialog",this.setDialogClass),this.trigger("initialize_dialog",this),"undefined"!=typeof this.initializeDialog&&this.initializeDialog()},getNextDialog:function(){return null},getPrevDialog:function(){return null},setDialogClass:function(){""!==this.dialogClass&&this.$(".so-panels-dialog").addClass(this.dialogClass)},setBuilder:function(e){return this.builder=e,e.trigger("add_dialog",this,this.builder),this},attach:function(){return this.$el.appendTo("body"),this},parseDialogContent:function(e,t){t=_.extend({cid:this.cid},t);var i=s(_.template(e.panelsProcessTemplate())(t)),o={title:i.find(".title").html(),buttons:i.find(".buttons").html(),content:i.find(".content").html()};return i.has(".left-sidebar")&&(o.left_sidebar=i.find(".left-sidebar").html()),i.has(".right-sidebar")&&(o.right_sidebar=i.find(".right-sidebar").html()),o},renderDialog:function(e){if(this.$el.html(this.dialogTemplate(e)).hide(),this.$el.data("view",this),this.$el.addClass("so-panels-dialog-wrapper"),this.parentDialog!==!1){var t=this,i=s('<h3 class="so-parent-link"></h3>').html(this.parentDialog.text+'<div class="so-separator"></div>');i.click(function(e){e.preventDefault(),t.closeDialog(),t.parentDialog.openDialog()}),this.$(".so-title-bar").prepend(i)}return this},initTabs:function(){var e=this.$el.find(".so-sidebar-tabs li a");if(0===e.length)return this;var t=this;return e.click(function(e){e.preventDefault();var i=jQuery(this);t.$(".so-sidebar-tabs li").removeClass("tab-active"),t.$(".so-content .so-content-tabs > *").hide(),i.parent().addClass("tab-active");var s=i.attr("href");if("undefined"!=typeof s&&"#"===s.charAt(0)){var o=s.split("#")[1];t.$(".so-content .so-content-tabs .tab-"+o).show()}t.trigger("tab_click",i)}),this.$el.find(".so-sidebar-tabs li a").first().click(),this},setupDialog:function(){this.openDialog(),this.closeDialog()},refreshDialogNav:function(){this.$(".so-title-bar .so-nav").show().removeClass("so-disabled");var e=this.getNextDialog(),t=this.$(".so-title-bar .so-next"),i=this.getPrevDialog(),s=this.$(".so-title-bar .so-previous");null===e?t.hide():e===!1&&t.addClass("so-disabled"),null===i?s.hide():i===!1&&s.addClass("so-disabled")},openDialog:function(){this.trigger("open_dialog"),this.dialogOpen=!0,window.panelsDialogOpen=!0,this.refreshDialogNav(),this.bodyScrollTop=s("body").scrollTop(),s("body").css({overflow:"hidden"}),s(window).on("keyup",this.keyboardListen),this.$el.show(),this.trigger("open_dialog_complete")},closeDialog:function(e){return this.trigger("close_dialog"),this.dialogOpen=!1,window.panelsDialogOpen=!1,"undefined"!=typeof this.builder&&this.builder.model.refreshPanelsData(),this.$el.hide(),s(".so-panels-dialog-wrapper").is(":visible")||(s("body").css({overflow:"auto"}),s("body").scrollTop(this.bodyScrollTop)),s(window).off("keyup",this.keyboardListen),this.trigger("close_dialog_complete"),!1},keyboardListen:function(e){27===e.which&&s(".so-panels-dialog-wrapper .so-close").trigger("click")},navToPrevious:function(){this.closeDialog(null);var e=this.getPrevDialog();null!==e&&e!==!1&&e.openDialog()},navToNext:function(){this.closeDialog(null);var e=this.getNextDialog();null!==e&&e!==!1&&e.openDialog()},getFormValues:function(e){"undefined"==typeof e&&(e=".so-content");var t,i=this.$(e),o={};return i.find("[name]").each(function(){var e=jQuery(this),i=/([A-Za-z_]+)\[(.*)\]/.exec(e.attr("name"));if(void 0===i)return!0;"undefined"==typeof i[2]?t=e.attr("name"):(t=i[2].split("]["),t.unshift(i[1])),t=t.map(function(e){return!isNaN(parseFloat(e))&&isFinite(e)?parseInt(e):e});var l=o,n=null,a="string"==typeof e.attr("type")?e.attr("type").toLowerCase():!1;if("checkbox"===a)n=e.is(":checked")?""!==e.val()?e.val():!0:null;else if("radio"===a){if(!e.is(":checked"))return;n=e.val()}else if("TEXTAREA"===e.prop("tagName")&&e.hasClass("wp-editor-area")){var r=null;"undefined"!=typeof tinyMCE&&(r=tinyMCE.get(e.attr("id"))),n=null===r||"function"!=typeof r.getContent||r.isHidden()?e.val():r.getContent()}else if("SELECT"===e.prop("tagName")){var d=e.find("option:selected");1===d.length?n=e.find("option:selected").val():d.length>1&&(n=_.map(e.find("option:selected"),function(e,t){return s(e).val()}))}else n=e.val();if("undefined"!=typeof e.data("panels-filter"))switch(e.data("panels-filter")){case"json_parse":try{n=JSON.parse(n)}catch(c){n=""}}if(null!==n)for(var h=0;h<t.length;h++)h===t.length-1?""===t[h]?l.push(n):l[t[h]]=n:("undefined"==typeof l[t[h]]&&(""===t[h+1]?l[t[h]]=[]:l[t[h]]={}),l=l[t[h]])}),o},setStatusMessage:function(e,t){this.$(".so-toolbar .so-status").html(e),"undefined"!=typeof t&&t&&this.$(".so-toolbar .so-status").addClass("so-panels-loading")},setParent:function(e,t){this.parentDialog={text:e,dialog:t}}})},{}],22:[function(e,t,i){var s=(window.panels,jQuery);t.exports=Backbone.View.extend({template:_.template(s("#siteorigin-panels-live-editor").html().panelsProcessTemplate()),sectionTemplate:_.template(s("#siteorigin-panels-live-editor-sidebar-section").html().panelsProcessTemplate()),postId:!1,bodyScrollTop:null,displayed:!1,events:{"click .live-editor-close":"close"},frameScrollTop:0,initialize:function(){},render:function(){this.setElement(this.template()),this.$el.html(this.template());var e=this;this.$("iframe#siteorigin-panels-live-editor-iframe").load(function(){s(this).show();var t=s(this).contents();t.find(".panel-grid .panel-grid-cell .so-panel").filter(function(){return 0==s(this).parents(".widget_siteorigin-panels-builder").length}).each(function(t,i){var o,l=jQuery(i),n=e.$(".page-widgets .so-widget").eq(t);l.css({cursor:"pointer"}).mouseenter(function(){n.addClass("so-hovered"),o=e.createPreviewOverlay(s(this))}).mouseleave(function(){n.removeClass("so-hovered"),o.fadeOut("fast",function(){s(this).remove()})}).click(function(e){e.preventDefault(),n.click()})}),t.find("a").css({"pointer-events":"none"}).click(function(e){return!1})})},attach:function(){this.$el.appendTo("body")},setPostId:function(e){this.postId=e},open:function(){""===this.$el.html()&&this.render(),0===this.$el.closest("body").length&&this.attach(),this.refreshWidgets(),this.$el.show(),this.refreshPreview(),this.bodyScrollTop=s("body").scrollTop(),s("body").css({overflow:"hidden"}),this.displayed=!0},close:function(){return this.$el.hide(),s("body").css({overflow:"auto"}),s("body").scrollTop(this.bodyScrollTop),this.displayed=!1,!1},refreshPreview:function(){return this.$el.is(":visible")?(this.$("iframe#siteorigin-panels-live-editor-iframe").hide(),this.frameScrollTop=this.$("iframe#siteorigin-panels-live-editor-iframe").contents().find("body").scrollTop(),this.$('form.live-editor-form input[name="siteorigin_panels_data"]').val(JSON.stringify(this.builder.model.getPanelsData())),void this.$("form.live-editor-form").submit()):!1},createPreviewOverlay:function(e){var t=this.$("iframe#siteorigin-panels-live-editor-iframe"),i=t.contents().find("body").css("position","relative");t.contents().find(".panels-live-editor-overlay").remove();var o=s("<div />").addClass("panels-live-editor-overlay").css({"pointer-events":"none"}),l=s("<div />").css({position:"absolute",background:"#000000","z-index":1e4,opacity:.25}),n=15;return o.append(l.clone().css({top:-i.offset().top,left:0,right:0,height:e.offset().top-n})).append(l.clone().css({bottom:0,left:0,right:0,height:Math.round(i.height()-e.offset().top-e.outerHeight()-n+i.offset().top-.01)})).append(l.clone().css({top:e.offset().top-n-i.offset().top,left:0,width:e.offset().left-n,height:Math.ceil(e.outerHeight()+2*n)})).append(l.clone().css({top:e.offset().top-n-i.offset().top,right:0,left:e.offset().left+e.outerWidth()+n,height:Math.ceil(e.outerHeight()+2*n)})),t.contents().find("body").append(o),o},refreshWidgets:function(){this.$(".so-sidebar .page-widgets").empty();var e=this.$("iframe#siteorigin-panels-live-editor-iframe"),t=this,i=0;this.builder.$(".so-row-container").each(function(o,l){var n=s(l),a=n.find(".so-cells .cell .so-widget"),r=s(t.sectionTemplate({title:"Row "+(o+1)})).appendTo(t.$(".so-sidebar .page-widgets"));r.find(".section-header").click(function(){n.data("view").editSettingsHandler()});var d=r.find(".section-widgets");a.each(function(o,l){var n=s(this),a=n.clone().show().css({opacity:1});a.find(".actions").remove(),a.find(".widget-icon").remove();var r=i++,c=function(){return e.contents().find("#pl-"+t.postId+" .panel-grid .panel-grid-cell .so-panel").filter(function(){return 0===s(this).parents(".widget_siteorigin-panels-builder").length}).not("panel-hover-widget").eq(r)},h=null,u=null;a.click(function(e){return e.preventDefault(),n.data("view").editHandler(),!1}).mouseenter(function(){var i=c();i&&i.offset()&&(e.contents().find("html,body").clearQueue().animate({scrollTop:i.offset().top-Math.max(30,(Math.min(e.contents().height(),e.height())-i.outerHeight())/2)},750),h=t.createPreviewOverlay(i))}).mouseleave(function(){e.contents().find("html,body").clearQueue(),null!==h&&(h.fadeOut("fast",function(){s(this).remove()}),h=null),null!==u&&(u.remove(),u=null)}).appendTo(d)})})},hasPreviewUrl:function(){return""!==this.$("form.live-editor-form").attr("action")}})},{}],23:[function(e,t,i){var s=window.panels,o=jQuery;t.exports=Backbone.View.extend({template:_.template(o("#siteorigin-panels-builder-row").html().panelsProcessTemplate()),events:{"click .so-row-settings":"editSettingsHandler","click .so-row-duplicate":"duplicateHandler","click .so-row-delete":"confirmedDeleteHandler"},builder:null,dialog:null,initialize:function(){this.model.cells.on("add",this.handleCellAdd,this),this.model.cells.on("remove",this.handleCellRemove,this),this.model.on("reweight_cells",this.resize,this),
3
- this.model.on("destroy",this.onModelDestroy,this),this.model.on("visual_destroy",this.visualDestroyModel,this);var e=this;this.model.cells.each(function(t){e.listenTo(t.widgets,"add",e.resize)}),this.model.cells.on("add",function(t){e.listenTo(t.widgets,"add",e.resize)},this)},render:function(){this.setElement(this.template()),this.$el.data("view",this);var e=this;return this.model.cells.each(function(t){var i=new s.view.cell({model:t});i.row=e,i.render(),i.$el.appendTo(e.$(".so-cells"))}),this.builder.on("widget_sortable_move",this.resize,this),this.builder.on("builder_resize",this.resize,this),this.resize(),this},visualCreate:function(){this.$el.hide().fadeIn("fast")},resize:function(e){if(!this.$el.is(":visible"))return!1;this.$el.find(".so-cells .cell-wrapper").css("min-height",0);var t=0;this.$el.find(".so-cells .cell").each(function(){t=Math.max(t,o(this).height()),o(this).css("width",100*o(this).data("view").model.get("weight")+"%")}),this.$el.find(".so-cells .cell-wrapper").css("min-height",Math.max(t,70))},onModelDestroy:function(){this.remove()},visualDestroyModel:function(){this.builder.addHistoryEntry("row_deleted");var e=this;this.$el.fadeOut("normal",function(){e.model.destroy(),e.builder.model.refreshPanelsData(),e.builder.liveEditor.displayed&&e.builder.liveEditor.refreshWidgets()})},duplicateHandler:function(){this.builder.addHistoryEntry("row_duplicated");var e=this.model.clone(this.builder.model);return this.builder.model.rows.add(e,{at:this.builder.model.rows.indexOf(this.model)+1}),!1},confirmedDeleteHandler:function(e){var t=jQuery(e.target);if(t.hasClass("dashicons")&&(t=jQuery$.parent()),t.hasClass("so-confirmed"))this.visualDestroyModel();else{var i=t.html();t.addClass("so-confirmed").html('<span class="dashicons dashicons-yes"></span>'+panelsOptions.loc.dropdown_confirm),setTimeout(function(){t.removeClass("so-confirmed").html(i)},2500)}return!1},editSettingsHandler:function(){return null===this.dialog&&(this.dialog=new s.dialog.row,this.dialog.setBuilder(this.builder).setRowModel(this.model)),this.dialog.openDialog(),!1},deleteHandler:function(){return this.model.destroy(),!1},handleCellAdd:function(e){var t=new s.view.cell({model:e});t.row=this,t.render(),t.$el.appendTo(this.$(".so-cells"))},handleCellRemove:function(e){this.$el.find(".so-cells > .cell").each(function(){var t=o(this).data("view");return"undefined"==typeof t?!1:void(t.model.cid===e.cid&&t.remove())})},buildContextualMenu:function(e,t){for(var i=this,o=[],l=1;5>l;l++)o.push({title:l+" "+panelsOptions.loc.contextual.column});t.addSection({sectionTitle:panelsOptions.loc.contextual.add_row,search:!1},o,function(e){i.builder.addHistoryEntry("row_added");for(var t=Number(e)+1,o=[],l=0;t>l;l++)o.push(100/t);var n=new s.model.row({collection:i.collection});n.setCells(o),n.builder=i.builder,i.builder.model.rows.add(n,{at:i.builder.model.rows.indexOf(i.model)+1})})}})},{}],24:[function(e,t,i){var s=(window.panels,jQuery);t.exports=Backbone.View.extend({stylesLoaded:!1,initialize:function(){},render:function(e,t,i){if("undefined"==typeof e)return!1;i=_.extend({builderType:""},i),this.$el.addClass("so-visual-styles");var o=this;s.post(panelsOptions.ajaxurl,{action:"so_panels_style_form",type:e,style:this.model.get("style"),args:JSON.stringify(i),postId:t},function(e){o.$el.html(e),o.setupFields(),o.stylesLoaded=!0,o.trigger("styles_loaded")})},attach:function(e){e.append(this.$el)},detach:function(){this.$el.detach()},setupFields:function(){this.$(".style-section-wrapper").each(function(){var e=s(this);e.find(".style-section-head").click(function(t){t.preventDefault(),e.find(".style-section-fields").slideToggle("fast")})}),"undefined"!=typeof s.fn.wpColorPicker&&("object"!=typeof panelsOptions.wpColorPickerOptions.palettes||s.isArray(panelsOptions.wpColorPickerOptions.palettes)||(panelsOptions.wpColorPickerOptions.palettes=s.map(panelsOptions.wpColorPickerOptions.palettes,function(e){return e})),this.$(".so-wp-color-field").wpColorPicker(panelsOptions.wpColorPickerOptions)),this.$(".style-field-image").each(function(){var e=null,t=s(this);t.find(".so-image-selector").click(function(i){i.preventDefault(),null===e&&(e=wp.media({title:"choose",library:{type:"image"},button:{text:"Done",close:!0}}),e.on("select",function(){var i=e.state().get("selection").first().attributes,s=i.url;if(!_.isUndefined(i.sizes))try{s=i.sizes.thumbnail.url}catch(o){s=i.sizes.full.url}t.find(".current-image").css("background-image","url("+s+")"),t.find("input").val(i.id)})),e.open()}),t.find(".remove-image").click(function(e){e.preventDefault(),t.find(".current-image").css("background-image","none"),t.find("input").val("")})}),this.$(".style-field-measurement").each(function(){var e=jQuery(this),t=e.find('input[type="text"]'),i=e.find("select"),s=e.find('input[type="hidden"]');if(""!==s.val()){var o=/(?:([0-9\.,]+)(.*))+/,l=s.val().split(" "),n=[];for(var a in l){var r=o.exec(l[a]);null!=r&&"undefined"!=typeof r[1]&&"undefined"!=typeof r[2]&&(n.push(r[1]),i.val(r[2]))}t.val(n.join(" "))}var d=function(){var e=t.val().split(" ").filter(function(e){return""!==e}).map(function(e){return e+i.val()}).join(" ");s.val(e)};t.keyup(d).change(d),i.change(d)})}})},{}],25:[function(e,t,i){var s=window.panels,o=jQuery;t.exports=Backbone.View.extend({template:_.template(o("#siteorigin-panels-builder-widget").html().panelsProcessTemplate()),cell:null,dialog:null,events:{"click .widget-edit":"editHandler","click .title h4":"editHandler","click .actions .widget-duplicate":"duplicateHandler","click .actions .widget-delete":"deleteHandler"},initialize:function(){this.model.on("user_edit",this.editHandler,this),this.model.on("user_duplicate",this.duplicateHandler,this),this.model.on("destroy",this.onModelDestroy,this),this.model.on("visual_destroy",this.visualDestroyModel,this),this.model.on("change:values",this.onModelChange,this)},render:function(e){if(e=_.extend({loadForm:!1},e),this.setElement(this.template({title:this.model.getWidgetField("title"),description:this.model.getTitle()})),this.$el.data("view",this),0===_.size(this.model.get("values"))||e.loadForm){var t=this.getEditDialog();t.once("form_loaded",t.saveWidget,t),t.setupDialog()}},visualCreate:function(){this.$el.hide().fadeIn("fast")},getEditDialog:function(){return null===this.dialog&&(this.dialog=new s.dialog.widget({model:this.model}),this.dialog.setBuilder(this.cell.row.builder),this.dialog.widgetView=this),this.dialog},editHandler:function(){return this.getEditDialog().openDialog(),!1},duplicateHandler:function(){this.cell.row.builder.addHistoryEntry("widget_duplicated");var e=this.model.clone(this.model.cell);return this.cell.model.widgets.add(e,{at:this.model.collection.indexOf(this.model)+1}),!1},deleteHandler:function(){return this.model.trigger("visual_destroy"),!1},onModelChange:function(){this.$(".description").html(this.model.getTitle())},onModelDestroy:function(){this.remove()},visualDestroyModel:function(){this.cell.row.builder.addHistoryEntry("widget_deleted");var e=this;this.$el.fadeOut("fast",function(){e.cell.row.resize(),e.model.destroy(),e.remove()})},buildContextualMenu:function(e,t){var i=this;t.addSection({sectionTitle:panelsOptions.loc.contextual.add_widget_below,searchPlaceholder:panelsOptions.loc.contextual.search_widgets,defaultDisplay:panelsOptions.contextual.default_widgets},panelsOptions.widgets,function(e){i.cell.row.builder.addHistoryEntry("widget_added");var t=new s.model.widget({"class":e});t.cell=i.cell.model,i.cell.model.widgets.add(t,{at:i.model.collection.indexOf(i.model)+1})}),this.cell.row.buildContextualMenu(e,t)}})},{}]},{},[12]);
 
 
 
js/siteorigin-panels-24.js ADDED
@@ -0,0 +1,5832 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
2
+ var panels = window.panels;
3
+
4
+ module.exports = Backbone.Collection.extend( {
5
+ model: panels.model.cell,
6
+
7
+ initialize: function () {
8
+ },
9
+
10
+ /**
11
+ * Get the total weight for the cells in this collection.
12
+ * @returns {number}
13
+ */
14
+ totalWeight: function () {
15
+ var totalWeight = 0;
16
+ this.each( function ( cell ) {
17
+ totalWeight += cell.get( 'weight' );
18
+ } );
19
+
20
+ return totalWeight;
21
+ },
22
+
23
+ comparator: function ( item ) {
24
+ if ( ! _.isNull( item.indexes ) ) {
25
+ return item.indexes.builder;
26
+ } else {
27
+ return null;
28
+ }
29
+ }
30
+ } );
31
+
32
+ },{}],2:[function(require,module,exports){
33
+ var panels = window.panels;
34
+
35
+ module.exports = Backbone.Collection.extend( {
36
+ model: panels.model.historyEntry,
37
+
38
+ /**
39
+ * The builder model
40
+ */
41
+ builder: null,
42
+
43
+ /**
44
+ * The maximum number of items in the history
45
+ */
46
+ maxSize: 12,
47
+
48
+ initialize: function () {
49
+ this.on( 'add', this.onAddEntry, this );
50
+ },
51
+
52
+ /**
53
+ * Add an entry to the collection.
54
+ *
55
+ * @param text The text that defines the action taken to get to this
56
+ * @param data
57
+ */
58
+ addEntry: function ( text, data ) {
59
+
60
+ if ( _.isEmpty( data ) ) {
61
+ data = this.builder.getPanelsData();
62
+ }
63
+
64
+ var entry = new panels.model.historyEntry( {
65
+ text: text,
66
+ data: JSON.stringify( data ),
67
+ time: parseInt( new Date().getTime() / 1000 ),
68
+ collection: this
69
+ } );
70
+
71
+ this.add( entry );
72
+ },
73
+
74
+ /**
75
+ * Resize the collection so it's not bigger than this.maxSize
76
+ */
77
+ onAddEntry: function ( entry ) {
78
+
79
+ if ( this.models.length > 1 ) {
80
+ var lastEntry = this.at( this.models.length - 2 );
81
+
82
+ if (
83
+ (
84
+ entry.get( 'text' ) === lastEntry.get( 'text' ) && entry.get( 'time' ) - lastEntry.get( 'time' ) < 15
85
+ ) ||
86
+ (
87
+ entry.get( 'data' ) === lastEntry.get( 'data' )
88
+ )
89
+ ) {
90
+ // If both entries have the same text and are within 20 seconds of each other, or have the same data, then remove most recent
91
+ this.remove( entry );
92
+ lastEntry.set( 'count', lastEntry.get( 'count' ) + 1 );
93
+ }
94
+ }
95
+
96
+ // Make sure that there are not to many entries in this collection
97
+ while ( this.models.length > this.maxSize ) {
98
+ this.shift();
99
+ }
100
+ }
101
+ } );
102
+
103
+ },{}],3:[function(require,module,exports){
104
+ var panels = window.panels;
105
+
106
+ module.exports = Backbone.Collection.extend( {
107
+ model: panels.model.row,
108
+
109
+ /**
110
+ * Destroy all the rows in this collection
111
+ */
112
+ empty: function () {
113
+ var model;
114
+ do {
115
+ model = this.collection.first();
116
+ if ( ! model ) {
117
+ break;
118
+ }
119
+
120
+ model.destroy();
121
+ } while ( true );
122
+ },
123
+
124
+ comparator: function ( item ) {
125
+ if ( ! _.isNull( item.indexes ) ) {
126
+ return item.indexes.builder;
127
+ } else {
128
+ return null;
129
+ }
130
+ }
131
+ } );
132
+
133
+ },{}],4:[function(require,module,exports){
134
+ var panels = window.panels;
135
+
136
+ module.exports = Backbone.Collection.extend( {
137
+ model: panels.model.widget,
138
+
139
+ initialize: function () {
140
+
141
+ },
142
+
143
+ comparator: function ( item ) {
144
+ if ( ! _.isNull( item.indexes ) ) {
145
+ return item.indexes.builder;
146
+ } else {
147
+ return null;
148
+ }
149
+ }
150
+
151
+ } );
152
+
153
+ },{}],5:[function(require,module,exports){
154
+ var panels = window.panels, $ = jQuery;
155
+
156
+ module.exports = panels.view.dialog.extend( {
157
+ dialogClass: 'so-panels-dialog-add-builder',
158
+
159
+ render: function () {
160
+ // Render the dialog and attach it to the builder interface
161
+ this.renderDialog( this.parseDialogContent( $( '#siteorigin-panels-dialog-builder' ).html(), {} ) );
162
+ this.$( '.so-content .siteorigin-panels-builder' ).append( this.builder.$el );
163
+ },
164
+
165
+ initializeDialog: function () {
166
+ var thisView = this;
167
+ this.once( 'open_dialog_complete', function () {
168
+ thisView.builder.initSortable();
169
+ } );
170
+
171
+ this.on( 'open_dialog_complete', function () {
172
+ thisView.builder.trigger( 'builder_resize' );
173
+ } );
174
+ }
175
+ } );
176
+
177
+ },{}],6:[function(require,module,exports){
178
+ var panels = window.panels, $ = jQuery;
179
+
180
+ module.exports = panels.view.dialog.extend( {
181
+
182
+ historyEntryTemplate: _.template( $( '#siteorigin-panels-dialog-history-entry' ).html().panelsProcessTemplate() ),
183
+
184
+ entries: {},
185
+ currentEntry: null,
186
+ revertEntry: null,
187
+ selectedEntry: null,
188
+
189
+ previewScrollTop: null,
190
+
191
+ dialogClass: 'so-panels-dialog-history',
192
+
193
+ events: {
194
+ 'click .so-close': 'closeDialog',
195
+ 'click .so-restore': 'restoreSelectedEntry'
196
+ },
197
+
198
+ initializeDialog: function () {
199
+ this.entries = new panels.collection.historyEntries();
200
+
201
+ this.on( 'open_dialog', this.setCurrentEntry, this );
202
+ this.on( 'open_dialog', this.renderHistoryEntries, this );
203
+ },
204
+
205
+ render: function () {
206
+ var thisView = this;
207
+
208
+ // Render the dialog and attach it to the builder interface
209
+ this.renderDialog( this.parseDialogContent( $( '#siteorigin-panels-dialog-history' ).html(), {} ) );
210
+
211
+ this.$( 'iframe.siteorigin-panels-history-iframe' ).load( function () {
212
+ var $$ = $( this );
213
+ $$.show();
214
+
215
+ $$.contents().scrollTop( thisView.previewScrollTop );
216
+ } );
217
+ },
218
+
219
+ /**
220
+ * Set the original entry. This should be set when creating the dialog.
221
+ *
222
+ * @param {panels.model.builder} builder
223
+ */
224
+ setRevertEntry: function ( builder ) {
225
+ this.revertEntry = new panels.model.historyEntry( {
226
+ data: JSON.stringify( builder.getPanelsData() ),
227
+ time: parseInt( new Date().getTime() / 1000 )
228
+ } );
229
+ },
230
+
231
+ /**
232
+ * This is triggered when the dialog is opened.
233
+ */
234
+ setCurrentEntry: function () {
235
+ this.currentEntry = new panels.model.historyEntry( {
236
+ data: JSON.stringify( this.builder.model.getPanelsData() ),
237
+ time: parseInt( new Date().getTime() / 1000 )
238
+ } );
239
+
240
+ this.selectedEntry = this.currentEntry;
241
+ this.previewEntry( this.currentEntry );
242
+ this.$( '.so-buttons .so-restore' ).addClass( 'disabled' );
243
+ },
244
+
245
+ /**
246
+ * Render the history entries in the sidebar
247
+ */
248
+ renderHistoryEntries: function () {
249
+ // Set up an interval that will display the time since every 10 seconds
250
+ var thisView = this;
251
+
252
+ var c = this.$( '.history-entries' ).empty();
253
+
254
+ if ( this.currentEntry.get( 'data' ) !== this.revertEntry.get( 'data' ) || ! _.isEmpty( this.entries.models ) ) {
255
+ $( this.historyEntryTemplate( {title: panelsOptions.loc.history.revert, count: 1} ) )
256
+ .data( 'historyEntry', this.revertEntry )
257
+ .prependTo( c );
258
+ }
259
+
260
+ // Now load all the entries in this.entries
261
+ this.entries.each( function ( entry ) {
262
+
263
+ var html = thisView.historyEntryTemplate( {
264
+ title: panelsOptions.loc.history[entry.get( 'text' )],
265
+ count: entry.get( 'count' )
266
+ } );
267
+
268
+ $( html )
269
+ .data( 'historyEntry', entry )
270
+ .prependTo( c );
271
+ } );
272
+
273
+
274
+ $( this.historyEntryTemplate( {title: panelsOptions.loc.history['current'], count: 1} ) )
275
+ .data( 'historyEntry', this.currentEntry )
276
+ .addClass( 'so-selected' )
277
+ .prependTo( c );
278
+
279
+ // Handle loading and selecting
280
+ c.find( '.history-entry' ).click( function () {
281
+ var $$ = jQuery( this );
282
+ c.find( '.history-entry' ).not( $$ ).removeClass( 'so-selected' );
283
+ $$.addClass( 'so-selected' );
284
+
285
+ var entry = $$.data( 'historyEntry' );
286
+
287
+ thisView.selectedEntry = entry;
288
+
289
+ if ( thisView.selectedEntry.cid !== thisView.currentEntry.cid ) {
290
+ thisView.$( '.so-buttons .so-restore' ).removeClass( 'disabled' );
291
+ } else {
292
+ thisView.$( '.so-buttons .so-restore' ).addClass( 'disabled' );
293
+ }
294
+
295
+ thisView.previewEntry( entry );
296
+ } );
297
+
298
+ this.updateEntryTimes();
299
+ },
300
+
301
+ /**
302
+ * Preview an entry
303
+ *
304
+ * @param entry
305
+ */
306
+ previewEntry: function ( entry ) {
307
+ var iframe = this.$( 'iframe.siteorigin-panels-history-iframe' );
308
+ iframe.hide();
309
+ this.previewScrollTop = iframe.contents().scrollTop();
310
+
311
+ this.$( 'form.history-form input[name="live_editor_panels_data"]' ).val( entry.get( 'data' ) );
312
+ this.$( 'form.history-form' ).submit();
313
+ },
314
+
315
+ /**
316
+ * Restore the current entry
317
+ */
318
+ restoreSelectedEntry: function () {
319
+
320
+ if ( this.$( '.so-buttons .so-restore' ).hasClass( 'disabled' ) ) {
321
+ return false;
322
+ }
323
+
324
+ if ( this.currentEntry.get( 'data' ) === this.selectedEntry.get( 'data' ) ) {
325
+ this.closeDialog();
326
+ return false;
327
+ }
328
+
329
+ // Add an entry for this restore event
330
+ if ( this.selectedEntry.get( 'text' ) !== 'restore' ) {
331
+ this.builder.addHistoryEntry( 'restore', this.builder.model.getPanelsData() );
332
+ }
333
+
334
+ this.builder.model.loadPanelsData( JSON.parse( this.selectedEntry.get( 'data' ) ) );
335
+
336
+ this.closeDialog();
337
+
338
+ return false;
339
+ },
340
+
341
+ /**
342
+ * Update the entry times for the list of entries down the side
343
+ */
344
+ updateEntryTimes: function () {
345
+ var thisView = this;
346
+
347
+ this.$( '.history-entries .history-entry' ).each( function () {
348
+ var $$ = jQuery( this );
349
+
350
+ var time = $$.find( '.timesince' );
351
+ var entry = $$.data( 'historyEntry' );
352
+
353
+ time.html( thisView.timeSince( entry.get( 'time' ) ) );
354
+ } );
355
+ },
356
+
357
+ /**
358
+ * Gets the time since as a nice string.
359
+ *
360
+ * @param date
361
+ */
362
+ timeSince: function ( time ) {
363
+ var diff = parseInt( new Date().getTime() / 1000 ) - time;
364
+
365
+ var parts = [];
366
+ var interval;
367
+
368
+ // There are 3600 seconds in an hour
369
+ if ( diff > 3600 ) {
370
+ interval = Math.floor( diff / 3600 );
371
+ if ( interval === 1 ) {
372
+ parts.push( panelsOptions.loc.time.hour.replace( '%d', interval ) );
373
+ } else {
374
+ parts.push( panelsOptions.loc.time.hours.replace( '%d', interval ) );
375
+ }
376
+ diff -= interval * 3600;
377
+ }
378
+
379
+ // There are 60 seconds in a minute
380
+ if ( diff > 60 ) {
381
+ interval = Math.floor( diff / 60 );
382
+ if ( interval === 1 ) {
383
+ parts.push( panelsOptions.loc.time.minute.replace( '%d', interval ) );
384
+ } else {
385
+ parts.push( panelsOptions.loc.time.minutes.replace( '%d', interval ) );
386
+ }
387
+ diff -= interval * 60;
388
+ }
389
+
390
+ if ( diff > 0 ) {
391
+ if ( diff === 1 ) {
392
+ parts.push( panelsOptions.loc.time.second.replace( '%d', diff ) );
393
+ } else {
394
+ parts.push( panelsOptions.loc.time.seconds.replace( '%d', diff ) );
395
+ }
396
+ }
397
+
398
+ // Return the amount of time ago
399
+ return _.isEmpty( parts ) ? panelsOptions.loc.time.now : panelsOptions.loc.time.ago.replace( '%s', parts.slice( 0, 2 ).join( ', ' ) );
400
+
401
+ }
402
+
403
+ } );
404
+
405
+ },{}],7:[function(require,module,exports){
406
+ var panels = window.panels, $ = jQuery;
407
+
408
+ module.exports = panels.view.dialog.extend( {
409
+
410
+ directoryTemplate: _.template( $( '#siteorigin-panels-directory-items' ).html().panelsProcessTemplate() ),
411
+
412
+ builder: null,
413
+ dialogClass: 'so-panels-dialog-prebuilt-layouts',
414
+
415
+ layoutCache: {},
416
+ currentTab: false,
417
+ directoryPage: 1,
418
+
419
+ events: {
420
+ 'click .so-close': 'closeDialog',
421
+ 'click .so-sidebar-tabs li a': 'tabClickHandler',
422
+ 'click .so-content .layout': 'layoutClickHandler',
423
+ 'keyup .so-sidebar-search': 'searchHandler',
424
+
425
+ // The directory items
426
+ 'click .so-screenshot, .so-title': 'directoryItemClickHandler'
427
+ },
428
+
429
+ /**
430
+ * Initialize the prebuilt dialog.
431
+ */
432
+ initializeDialog: function () {
433
+ var thisView = this;
434
+
435
+ this.on( 'open_dialog', function () {
436
+ thisView.$( '.so-sidebar-tabs li a' ).first().click();
437
+ thisView.$( '.so-status' ).removeClass( 'so-panels-loading' );
438
+ } );
439
+
440
+ this.on( 'button_click', this.toolbarButtonClick, this );
441
+ },
442
+
443
+ /**
444
+ * Render the prebuilt layouts dialog
445
+ */
446
+ render: function () {
447
+ this.renderDialog( this.parseDialogContent( $( '#siteorigin-panels-dialog-prebuilt' ).html(), {} ) );
448
+
449
+ this.initToolbar();
450
+ },
451
+
452
+ /**
453
+ *
454
+ * @param e
455
+ * @return {boolean}
456
+ */
457
+ tabClickHandler: function ( e ) {
458
+ e.preventDefault();
459
+ // Reset selected item state when changing tabs
460
+ this.selectedLayoutItem = null;
461
+ this.uploadedLayout = null;
462
+ this.updateButtonState( false );
463
+
464
+ this.$( '.so-sidebar-tabs li' ).removeClass( 'tab-active' );
465
+
466
+ var $$ = $( e.target );
467
+ var tab = $$.attr( 'href' ).split( '#' )[1];
468
+ $$.parent().addClass( 'tab-active' );
469
+
470
+ var thisView = this;
471
+
472
+ // Empty everything
473
+ this.$( '.so-content' ).empty();
474
+
475
+ thisView.currentTab = tab;
476
+ if ( tab == 'import' ) {
477
+ this.displayImportExport();
478
+ } else {
479
+ this.displayLayoutDirectory( '', 1, tab );
480
+ }
481
+
482
+ thisView.$( '.so-sidebar-search' ).val( '' );
483
+ },
484
+
485
+ /**
486
+ * Display and setup the import/export form
487
+ */
488
+ displayImportExport: function () {
489
+ var c = this.$( '.so-content' ).empty().removeClass( 'so-panels-loading' );
490
+ c.html( $( '#siteorigin-panels-dialog-prebuilt-importexport' ).html() );
491
+
492
+ var thisView = this;
493
+ var uploadUi = thisView.$( '.import-upload-ui' ).hide();
494
+
495
+ // Create the uploader
496
+ var uploader = new plupload.Uploader( {
497
+ runtimes: 'html5,silverlight,flash,html4',
498
+
499
+ browse_button: uploadUi.find( '.file-browse-button' ).get( 0 ),
500
+ container: uploadUi.get( 0 ),
501
+ drop_element: uploadUi.find( '.drag-upload-area' ).get( 0 ),
502
+
503
+ file_data_name: 'panels_import_data',
504
+ multiple_queues: false,
505
+ max_file_size: panelsOptions.plupload.max_file_size,
506
+ url: panelsOptions.plupload.url,
507
+ flash_swf_url: panelsOptions.plupload.flash_swf_url,
508
+ silverlight_xap_url: panelsOptions.plupload.silverlight_xap_url,
509
+ filters: [
510
+ {title: panelsOptions.plupload.filter_title, extensions: 'json'}
511
+ ],
512
+
513
+ multipart_params: {
514
+ action: 'so_panels_import_layout'
515
+ },
516
+
517
+ init: {
518
+ PostInit: function ( uploader ) {
519
+ if ( uploader.features.dragdrop ) {
520
+ uploadUi.addClass( 'has-drag-drop' );
521
+ }
522
+ uploadUi.show().find( '.progress-precent' ).css( 'width', '0%' );
523
+ },
524
+ FilesAdded: function ( uploader ) {
525
+ uploadUi.find( '.file-browse-button' ).blur();
526
+ uploadUi.find( '.drag-upload-area' ).removeClass( 'file-dragover' );
527
+ uploadUi.find( '.progress-bar' ).fadeIn( 'fast' );
528
+ thisView.$( '.js-so-selected-file' ).text( panelsOptions.loc.prebuilt_loading );
529
+ uploader.start();
530
+ },
531
+ UploadProgress: function ( uploader, file ) {
532
+ uploadUi.find( '.progress-precent' ).css( 'width', file.percent + '%' );
533
+ },
534
+ FileUploaded: function ( uploader, file, response ) {
535
+ var layout = JSON.parse( response.response );
536
+ if ( ! _.isUndefined( layout.widgets ) ) {
537
+
538
+ thisView.uploadedLayout = layout;
539
+ uploadUi.find( '.progress-bar' ).hide();
540
+ thisView.$( '.js-so-selected-file' ).text(
541
+ panelsOptions.loc.ready_to_insert.replace( '%s', file.name )
542
+ );
543
+ thisView.updateButtonState( true );
544
+ } else {
545
+ alert( panelsOptions.plupload.error_message );
546
+ }
547
+ },
548
+ Error: function () {
549
+ alert( panelsOptions.plupload.error_message );
550
+ }
551
+ }
552
+ } );
553
+ uploader.init();
554
+
555
+ // This is
556
+ uploadUi.find( '.drag-upload-area' )
557
+ .on( 'dragover', function () {
558
+ $( this ).addClass( 'file-dragover' );
559
+ } )
560
+ .on( 'dragleave', function () {
561
+ $( this ).removeClass( 'file-dragover' );
562
+ } );
563
+
564
+ // Handle exporting the file
565
+ c.find( '.so-export' ).submit( function ( e ) {
566
+ var $$ = jQuery( this );
567
+ $$.find( 'input[name="panels_export_data"]' ).val( JSON.stringify( thisView.builder.model.getPanelsData() ) );
568
+ } );
569
+
570
+ },
571
+
572
+ /**
573
+ * Display the layout directory tab.
574
+ *
575
+ * @param query
576
+ */
577
+ displayLayoutDirectory: function ( search, page, type ) {
578
+ var thisView = this;
579
+ var c = this.$( '.so-content' ).empty().addClass( 'so-panels-loading' );
580
+
581
+ if ( search === undefined ) {
582
+ search = '';
583
+ }
584
+ if ( page === undefined ) {
585
+ page = 1;
586
+ }
587
+ if ( type === undefined ) {
588
+ type = 'directory';
589
+ }
590
+
591
+ if ( type === 'directory' && ! panelsOptions.directory_enabled ) {
592
+ // Display the button to enable the prebuilt layout
593
+ c.removeClass( 'so-panels-loading' ).html( $( '#siteorigin-panels-directory-enable' ).html() );
594
+ c.find( '.so-panels-enable-directory' ).click( function ( e ) {
595
+ e.preventDefault();
596
+ // Sent the query to enable the directory, then enable the directory
597
+ $.get(
598
+ panelsOptions.ajaxurl,
599
+ {action: 'so_panels_directory_enable'},
600
+ function () {
601
+
602
+ }
603
+ );
604
+
605
+ // Enable the layout directory
606
+ panelsOptions.directory_enabled = true;
607
+ c.addClass( 'so-panels-loading' );
608
+ thisView.displayLayoutDirectory( search, page );
609
+ } );
610
+ return;
611
+ }
612
+
613
+ // Get all the items for the current query
614
+ $.get(
615
+ panelsOptions.ajaxurl,
616
+ {
617
+ action: 'so_panels_layouts_query',
618
+ search: search,
619
+ page: page,
620
+ type: type,
621
+ },
622
+ function ( data ) {
623
+ // Skip this if we're no longer viewing the layout directory
624
+ if ( thisView.currentTab !== type ) {
625
+ return;
626
+ }
627
+
628
+ // Add the directory items
629
+ c.removeClass( 'so-panels-loading' ).html( thisView.directoryTemplate( data ) );
630
+
631
+ // Lets setup the next and previous buttons
632
+ var prev = c.find( '.so-previous' ), next = c.find( '.so-next' );
633
+
634
+ if ( page <= 1 ) {
635
+ prev.addClass( 'button-disabled' );
636
+ } else {
637
+ prev.click( function ( e ) {
638
+ e.preventDefault();
639
+ thisView.displayLayoutDirectory( search, page - 1, thisView.currentTab );
640
+ } );
641
+ }
642
+
643
+ if ( page === data.max_num_pages || data.max_num_pages === 0 ) {
644
+ next.addClass( 'button-disabled' );
645
+ } else {
646
+ next.click( function ( e ) {
647
+ e.preventDefault();
648
+ thisView.displayLayoutDirectory( search, page + 1, thisView.currentTab );
649
+ } );
650
+ }
651
+
652
+ // Handle nice preloading of the screenshots
653
+ c.find( '.so-screenshot' ).each( function () {
654
+ var $$ = $( this ), $a = $$.find( '.so-screenshot-wrapper' );
655
+ $a.css( 'height', (
656
+ $a.width() / 4 * 3
657
+ ) + 'px' ).addClass( 'so-loading' );
658
+
659
+ if ( $$.data( 'src' ) !== '' ) {
660
+ // Set the initial height
661
+ var $img = $( '<img/>' ).attr( 'src', $$.data( 'src' ) ).load( function () {
662
+ $a.removeClass( 'so-loading' ).css( 'height', 'auto' );
663
+ $img.appendTo( $a ).hide().fadeIn( 'fast' );
664
+ } );
665
+ } else {
666
+ $( '<img/>' ).attr( 'src', panelsOptions.prebuiltDefaultScreenshot ).appendTo( $a ).hide().fadeIn( 'fast' );
667
+ }
668
+
669
+ } );
670
+
671
+ // Set the title
672
+ c.find( '.so-directory-browse' ).html( data.title );
673
+ },
674
+ 'json'
675
+ );
676
+ },
677
+
678
+ /**
679
+ * Set the selected state for the clicked layout directory item and remove previously selected item.
680
+ * Enable the toolbar buttons.
681
+ */
682
+ directoryItemClickHandler: function ( e ) {
683
+ var $directoryItem = this.$( e.target ).closest( '.so-directory-item' );
684
+ this.$( '.so-directory-items' ).find( '.selected' ).removeClass( 'selected' );
685
+ $directoryItem.addClass( 'selected' );
686
+ this.selectedLayoutItem = {lid: $directoryItem.data( 'layout-id' ), type: $directoryItem.data( 'layout-type' )};
687
+ this.updateButtonState( true );
688
+
689
+ },
690
+
691
+ /**
692
+ * Load a particular layout into the builder.
693
+ *
694
+ * @param id
695
+ */
696
+ toolbarButtonClick: function ( $button ) {
697
+ if ( ! this.canAddLayout() ) {
698
+ return false;
699
+ }
700
+ var position = $button.data( 'value' );
701
+ if ( _.isUndefined( position ) ) {
702
+ return false;
703
+ }
704
+ this.updateButtonState( false );
705
+
706
+ if ( $button.hasClass( 'so-needs-confirm' ) && ! $button.hasClass( 'so-confirmed' ) ) {
707
+ this.updateButtonState( true );
708
+ if ( $button.hasClass( 'so-confirming' ) ) {
709
+ return;
710
+ }
711
+ $button.addClass( 'so-confirming' );
712
+ var originalText = $button.html();
713
+ $button.html( '<span class="dashicons dashicons-yes"></span>' + $button.data( 'confirm' ) );
714
+ setTimeout( function () {
715
+ $button.removeClass( 'so-confirmed' ).html( originalText );
716
+ }, 2500 );
717
+ setTimeout( function () {
718
+ $button.removeClass( 'so-confirming' );
719
+ $button.addClass( 'so-confirmed' );
720
+ }, 200 );
721
+ return false;
722
+ }
723
+ this.addingLayout = true;
724
+ if ( this.currentTab === 'import' ) {
725
+ this.addLayoutToBuilder( this.uploadedLayout, position );
726
+ } else {
727
+ this.loadSelectedLayout().then( function ( layout ) {
728
+ this.addLayoutToBuilder( layout, position );
729
+ }.bind( this ) );
730
+ }
731
+ },
732
+
733
+ canAddLayout: function () {
734
+ return (
735
+ this.selectedLayoutItem || this.uploadedLayout
736
+ ) && ! this.addingLayout;
737
+ },
738
+
739
+ /**
740
+ * Load the layout according to selectedLayoutItem.
741
+ */
742
+ loadSelectedLayout: function () {
743
+ this.setStatusMessage( panelsOptions.loc.prebuilt_loading, true );
744
+
745
+ var args = _.extend( this.selectedLayoutItem, {action: 'so_panels_get_layout'} );
746
+ var deferredLayout = new $.Deferred();
747
+
748
+ $.get(
749
+ panelsOptions.ajaxurl,
750
+ args,
751
+ function ( layout ) {
752
+ if ( layout.error !== undefined ) {
753
+ // There was an error
754
+ alert( layout.error );
755
+ deferredLayout.reject( layout );
756
+ } else {
757
+ this.setStatusMessage( '', false );
758
+ deferredLayout.resolve( layout );
759
+ }
760
+ }.bind( this )
761
+ );
762
+ return deferredLayout.promise();
763
+ },
764
+
765
+ /**
766
+ * Handle an update to the search
767
+ */
768
+ searchHandler: function ( e ) {
769
+ if ( e.keyCode === 13 ) {
770
+ this.displayLayoutDirectory( $( e.currentTarget ).val(), 1, this.currentTab );
771
+ }
772
+ },
773
+
774
+ /**
775
+ * Attempt to set the 'Insert' button's state according to the `enabled` argument, also checking whether the
776
+ * requirements for inserting a layout have valid values.
777
+ */
778
+ updateButtonState: function ( enabled ) {
779
+ enabled = enabled && (
780
+ this.selectedLayoutItem || this.uploadedLayout
781
+ );
782
+ var $button = this.$( '.so-import-layout' );
783
+ $button.prop( "disabled", ! enabled );
784
+ if ( enabled ) {
785
+ $button.removeClass( 'disabled' );
786
+ } else {
787
+ $button.addClass( 'disabled' );
788
+ }
789
+ },
790
+
791
+ addLayoutToBuilder: function ( layout, position ) {
792
+ this.builder.addHistoryEntry( 'prebuilt_loaded' );
793
+ this.builder.model.loadPanelsData( layout, position );
794
+ this.addingLayout = false;
795
+ this.closeDialog();
796
+ }
797
+ } );
798
+
799
+ },{}],8:[function(require,module,exports){
800
+ var panels = window.panels, $ = jQuery;
801
+
802
+ module.exports = panels.view.dialog.extend( {
803
+
804
+ cellPreviewTemplate: _.template( $( '#siteorigin-panels-dialog-row-cell-preview' ).html().panelsProcessTemplate() ),
805
+
806
+ events: {
807
+ 'click .so-close': 'closeDialog',
808
+
809
+ // Toolbar buttons
810
+ 'click .so-toolbar .so-save': 'saveHandler',
811
+ 'click .so-toolbar .so-insert': 'insertHandler',
812
+ 'click .so-toolbar .so-delete': 'deleteHandler',
813
+ 'click .so-toolbar .so-duplicate': 'duplicateHandler',
814
+
815
+ // Changing the row
816
+ 'change .row-set-form > *': 'setCellsFromForm',
817
+ 'click .row-set-form button.set-row': 'setCellsFromForm'
818
+ },
819
+
820
+ dialogClass: 'so-panels-dialog-row-edit',
821
+ styleType: 'row',
822
+
823
+ dialogType: 'edit',
824
+
825
+ /**
826
+ * The current settings, not yet saved to the model
827
+ */
828
+ row: {
829
+ // This is just the cell weights, cell content is not edited by this dialog
830
+ cells: [],
831
+ // The style settings of the row
832
+ style: {}
833
+ },
834
+
835
+ initializeDialog: function () {
836
+ this.on( 'open_dialog', function () {
837
+ if ( ! _.isUndefined( this.model ) && ! _.isEmpty( this.model.cells ) ) {
838
+ this.setRowModel( this.model );
839
+ } else {
840
+ this.setRowModel( null );
841
+ }
842
+
843
+ this.regenerateRowPreview();
844
+ }, this );
845
+
846
+ // This is the default row layout
847
+ this.row = {
848
+ cells: [0.5, 0.5],
849
+ style: {}
850
+ };
851
+
852
+ // Refresh panels data after both dialog form components are loaded
853
+ this.dialogFormsLoaded = 0;
854
+ var thisView = this;
855
+ this.on( 'form_loaded styles_loaded', function () {
856
+ this.dialogFormsLoaded ++;
857
+ if ( this.dialogFormsLoaded === 2 ) {
858
+ thisView.updateModel( {
859
+ refreshArgs: {
860
+ silent: true
861
+ }
862
+ } );
863
+ }
864
+ } );
865
+ },
866
+
867
+ /**
868
+ *
869
+ * @param dialogType Either "edit" or "create"
870
+ */
871
+ setRowDialogType: function ( dialogType ) {
872
+ this.dialogType = dialogType;
873
+ },
874
+
875
+ /**
876
+ * Render the new row dialog
877
+ */
878
+ render: function ( dialogType ) {
879
+ this.renderDialog( this.parseDialogContent( $( '#siteorigin-panels-dialog-row' ).html(), {dialogType: this.dialogType} ) );
880
+
881
+ if ( this.dialogType === 'edit' ) {
882
+ // Now we need to attach the style window
883
+ this.styles = new panels.view.styles();
884
+ this.styles.model = this.model;
885
+ this.styles.render( 'row', $( '#post_ID' ).val(), {
886
+ builderType: this.builder.builderType,
887
+ dialog: this
888
+ } );
889
+
890
+ var $rightSidebar = this.$( '.so-sidebar.so-right-sidebar' );
891
+ this.styles.attach( $rightSidebar );
892
+
893
+ // Handle the loading class
894
+ this.styles.on( 'styles_loaded', function ( hasStyles ) {
895
+ // If we have styles remove the loading spinner, else remove the whole empty sidebar.
896
+ if ( hasStyles ) {
897
+ $rightSidebar.removeClass( 'so-panels-loading' );
898
+ } else {
899
+ $rightSidebar.closest( '.so-panels-dialog' ).removeClass( 'so-panels-dialog-has-right-sidebar' );
900
+ $rightSidebar.remove();
901
+ }
902
+ }, this );
903
+ $rightSidebar.addClass( 'so-panels-loading' );
904
+ }
905
+
906
+ if ( ! _.isUndefined( this.model ) ) {
907
+ // Set the initial value of the
908
+ this.$( 'input.so-row-field' ).val( this.model.cells.length );
909
+ }
910
+
911
+ var thisView = this;
912
+ this.$( 'input.so-row-field' ).keyup( function () {
913
+ $( this ).trigger( 'change' );
914
+ } );
915
+
916
+ return this;
917
+ },
918
+
919
+ /**
920
+ * Set the row model we'll be using for this dialog.
921
+ *
922
+ * @param model
923
+ */
924
+ setRowModel: function ( model ) {
925
+ this.model = model;
926
+
927
+ if ( _.isEmpty( this.model ) ) {
928
+ return this;
929
+ }
930
+
931
+ // Set the rows to be a copy of the model
932
+ this.row = {
933
+ cells: this.model.cells.map( function ( cell ) {
934
+ return cell.get( 'weight' );
935
+ } ),
936
+ style: {}
937
+ };
938
+
939
+ // Set the initial value of the cell field.
940
+ this.$( 'input.so-row-field' ).val( this.model.cells.length );
941
+
942
+ return this;
943
+ },
944
+
945
+ /**
946
+ * Regenerate the row preview and resizing interface.
947
+ */
948
+ regenerateRowPreview: function () {
949
+ var thisDialog = this;
950
+ var rowPreview = this.$( '.row-preview' );
951
+
952
+ rowPreview.empty();
953
+
954
+ var timeout;
955
+
956
+ // Represent the cells
957
+ _.each( this.row.cells, function ( cell, i ) {
958
+ var newCell = $( this.cellPreviewTemplate( {weight: cell} ) );
959
+ rowPreview.append( newCell );
960
+
961
+ var prevCell = newCell.prev();
962
+ var handle;
963
+
964
+ if ( prevCell.length ) {
965
+ handle = $( '<div class="resize-handle"></div>' );
966
+ handle
967
+ .appendTo( newCell )
968
+ .dblclick( function () {
969
+ var t = thisDialog.row.cells[i] + thisDialog.row.cells[i - 1];
970
+ thisDialog.row.cells[i] = thisDialog.row.cells[i - 1] = t / 2;
971
+ thisDialog.scaleRowWidths();
972
+ } );
973
+
974
+ handle.draggable( {
975
+ axis: 'x',
976
+ containment: rowPreview,
977
+ start: function ( e, ui ) {
978
+
979
+ // Create the clone for the current cell
980
+ var newCellClone = newCell.clone().appendTo( ui.helper ).css( {
981
+ position: 'absolute',
982
+ top: '0',
983
+ width: newCell.outerWidth(),
984
+ left: 6,
985
+ height: newCell.outerHeight()
986
+ } );
987
+ newCellClone.find( '.resize-handle' ).remove();
988
+
989
+ // Create the clone for the previous cell
990
+ var prevCellClone = prevCell.clone().appendTo( ui.helper ).css( {
991
+ position: 'absolute',
992
+ top: '0',
993
+ width: prevCell.outerWidth(),
994
+ right: 6,
995
+ height: prevCell.outerHeight()
996
+ } );
997
+ prevCellClone.find( '.resize-handle' ).remove();
998
+
999
+ $( this ).data( {
1000
+ 'newCellClone': newCellClone,
1001
+ 'prevCellClone': prevCellClone
1002
+ } );
1003
+
1004
+ // Hide the
1005
+ newCell.find( '> .preview-cell-in' ).css( 'visibility', 'hidden' );
1006
+ prevCell.find( '> .preview-cell-in' ).css( 'visibility', 'hidden' );
1007
+ },
1008
+ drag: function ( e, ui ) {
1009
+ // Calculate the new cell and previous cell widths as a percent
1010
+ var ncw = thisDialog.row.cells[i] - (
1011
+ (
1012
+ ui.position.left + 6
1013
+ ) / rowPreview.width()
1014
+ );
1015
+ var pcw = thisDialog.row.cells[i - 1] + (
1016
+ (
1017
+ ui.position.left + 6
1018
+ ) / rowPreview.width()
1019
+ );
1020
+
1021
+ var helperLeft = ui.helper.offset().left - rowPreview.offset().left - 6;
1022
+
1023
+ $( this ).data( 'newCellClone' ).css( 'width', rowPreview.width() * ncw )
1024
+ .find( '.preview-cell-weight' ).html( Math.round( ncw * 1000 ) / 10 );
1025
+
1026
+ $( this ).data( 'prevCellClone' ).css( 'width', rowPreview.width() * pcw )
1027
+ .find( '.preview-cell-weight' ).html( Math.round( pcw * 1000 ) / 10 );
1028
+ },
1029
+ stop: function ( e, ui ) {
1030
+ // Remove the clones
1031
+ $( this ).data( 'newCellClone' ).remove();
1032
+ $( this ).data( 'prevCellClone' ).remove();
1033
+
1034
+ // Reshow the main cells
1035
+ newCell.find( '.preview-cell-in' ).css( 'visibility', 'visible' );
1036
+ prevCell.find( '.preview-cell-in' ).css( 'visibility', 'visible' );
1037
+
1038
+ // Calculate the new cell weights
1039
+ var offset = ui.position.left + 6;
1040
+ var percent = offset / rowPreview.width();
1041
+
1042
+ // Ignore this if any of the cells are below 2% in width.
1043
+ if ( thisDialog.row.cells[i] - percent > 0.02 && thisDialog.row.cells[i - 1] + percent > 0.02 ) {
1044
+ thisDialog.row.cells[i] -= percent;
1045
+ thisDialog.row.cells[i - 1] += percent;
1046
+ }
1047
+
1048
+ thisDialog.scaleRowWidths();
1049
+ ui.helper.css( 'left', - 6 );
1050
+ }
1051
+ } );
1052
+ }
1053
+
1054
+ // Make this row weight click editable
1055
+ newCell.find( '.preview-cell-weight' ).click( function ( ci ) {
1056
+
1057
+ // Disable the draggable while entering values
1058
+ thisDialog.$( '.resize-handle' ).css( 'pointer-event', 'none' ).draggable( 'disable' );
1059
+
1060
+ rowPreview.find( '.preview-cell-weight' ).each( function () {
1061
+ var $$ = jQuery( this ).hide();
1062
+ $( '<input type="text" class="preview-cell-weight-input no-user-interacted" />' )
1063
+ .val( parseFloat( $$.html() ) ).insertAfter( $$ )
1064
+ .focus( function () {
1065
+ clearTimeout( timeout );
1066
+ } )
1067
+ .keyup( function ( e ) {
1068
+ if ( e.keyCode !== 9 ) {
1069
+ // Only register the interaction if the user didn't press tab
1070
+ $( this ).removeClass( 'no-user-interacted' );
1071
+ }
1072
+
1073
+ // Enter is clicked
1074
+ if ( e.keyCode === 13 ) {
1075
+ e.preventDefault();
1076
+ $( this ).blur();
1077
+ }
1078
+ } )
1079
+ .keydown( function ( e ) {
1080
+ if ( e.keyCode === 9 ) {
1081
+ e.preventDefault();
1082
+
1083
+ // Tab will always cycle around the row inputs
1084
+ var inputs = rowPreview.find( '.preview-cell-weight-input' );
1085
+ var i = inputs.index( $( this ) );
1086
+ if ( i === inputs.length - 1 ) {
1087
+ inputs.eq( 0 ).focus().select();
1088
+ } else {
1089
+ inputs.eq( i + 1 ).focus().select();
1090
+ }
1091
+ }
1092
+ } )
1093
+ .blur( function () {
1094
+ rowPreview.find( '.preview-cell-weight-input' ).each( function ( i, el ) {
1095
+ if ( isNaN( parseFloat( $( el ).val() ) ) ) {
1096
+ $( el ).val( Math.floor( thisDialog.row.cells[i] * 1000 ) / 10 );
1097
+ }
1098
+ } );
1099
+
1100
+ timeout = setTimeout( function () {
1101
+ // If there are no weight inputs, then skip this
1102
+ if ( rowPreview.find( '.preview-cell-weight-input' ).legnth === 0 ) {
1103
+ return false;
1104
+ }
1105
+
1106
+ // Go through all the inputs
1107
+ var rowWeights = [],
1108
+ rowChanged = [],
1109
+ changedSum = 0,
1110
+ unchangedSum = 0;
1111
+
1112
+ rowPreview.find( '.preview-cell-weight-input' ).each( function ( i, el ) {
1113
+ var val = parseFloat( $( el ).val() );
1114
+ if ( isNaN( val ) ) {
1115
+ val = 1 / thisDialog.row.cells.length;
1116
+ } else {
1117
+ val = Math.round( val * 10 ) / 1000;
1118
+ }
1119
+
1120
+ // Check within 3 decimal points
1121
+ var changed = ! $( el ).hasClass( 'no-user-interacted' );
1122
+
1123
+ rowWeights.push( val );
1124
+ rowChanged.push( changed );
1125
+
1126
+ if ( changed ) {
1127
+ changedSum += val;
1128
+ } else {
1129
+ unchangedSum += val;
1130
+ }
1131
+ } );
1132
+
1133
+ if ( changedSum > 0 && unchangedSum > 0 && (
1134
+ 1 - changedSum
1135
+ ) > 0 ) {
1136
+ // Balance out the unchanged rows to occupy the weight left over by the changed sum
1137
+ for ( var i = 0; i < rowWeights.length; i ++ ) {
1138
+ if ( ! rowChanged[i] ) {
1139
+ rowWeights[i] = (
1140
+ rowWeights[i] / unchangedSum
1141
+ ) * (
1142
+ 1 - changedSum
1143
+ );
1144
+ }
1145
+ }
1146
+ }
1147
+
1148
+ // Last check to ensure total weight is 1
1149
+ var sum = _.reduce( rowWeights, function ( memo, num ) {
1150
+ return memo + num;
1151
+ } );
1152
+ rowWeights = rowWeights.map( function ( w ) {
1153
+ return w / sum;
1154
+ } );
1155
+
1156
+ // Set the new cell weights and regenerate the preview.
1157
+ if ( Math.min.apply( Math, rowWeights ) > 0.01 ) {
1158
+ thisDialog.row.cells = rowWeights;
1159
+ }
1160
+
1161
+ // Now lets animate the cells into their new widths
1162
+ rowPreview.find( '.preview-cell' ).each( function ( i, el ) {
1163
+ $( el ).animate( {'width': Math.round( thisDialog.row.cells[i] * 1000 ) / 10 + "%"}, 250 );
1164
+ $( el ).find( '.preview-cell-weight-input' ).val( Math.round( thisDialog.row.cells[i] * 1000 ) / 10 );
1165
+ } );
1166
+
1167
+ // So the draggable handle is not hidden.
1168
+ rowPreview.find( '.preview-cell' ).css( 'overflow', 'visible' );
1169
+
1170
+ setTimeout( function () {
1171
+ thisDialog.regenerateRowPreview();
1172
+ }, 260 );
1173
+
1174
+ }, 100 );
1175
+ } )
1176
+ .click( function () {
1177
+ $( this ).select();
1178
+ } );
1179
+ } );
1180
+
1181
+ $( this ).siblings( '.preview-cell-weight-input' ).select();
1182
+
1183
+ } );
1184
+
1185
+ }, this );
1186
+
1187
+ this.trigger( 'form_loaded', this );
1188
+ },
1189
+
1190
+ /**
1191
+ * Visually scale the row widths based on the cell weights
1192
+ */
1193
+ scaleRowWidths: function () {
1194
+ var thisDialog = this;
1195
+ this.$( '.row-preview .preview-cell' ).each( function ( i, el ) {
1196
+ $( el )
1197
+ .css( 'width', thisDialog.row.cells[i] * 100 + "%" )
1198
+ .find( '.preview-cell-weight' ).html( Math.round( thisDialog.row.cells[i] * 1000 ) / 10 );
1199
+ } );
1200
+ },
1201
+
1202
+ /**
1203
+ * Get the weights from the
1204
+ */
1205
+ setCellsFromForm: function () {
1206
+ var f = {
1207
+ 'cells': parseInt( this.$( '.row-set-form input[name="cells"]' ).val() ),
1208
+ 'ratio': parseFloat( this.$( '.row-set-form select[name="ratio"]' ).val() ),
1209
+ 'direction': this.$( '.row-set-form select[name="ratio_direction"]' ).val()
1210
+ };
1211
+
1212
+ if( _.isNaN( f.cells ) ) {
1213
+ f.cells = 1;
1214
+ }
1215
+ if( isNaN( f.ratio ) ) {
1216
+ f.ratio = 1;
1217
+ }
1218
+ if ( f.cells < 1 ) {
1219
+ f.cells = 1;
1220
+ this.$( '.row-set-form input[name="cells"]' ).val( f.cells );
1221
+ }
1222
+ else if ( f.cells > 10 ) {
1223
+ f.cells = 10;
1224
+ this.$( '.row-set-form input[name="cells"]' ).val( f.cells );
1225
+ }
1226
+
1227
+ this.$( '.row-set-form input[name="ratio"]' ).val( f.ratio );
1228
+
1229
+ var cells = [];
1230
+ var cellCountChanged = (
1231
+ this.row.cells.length !== f.cells
1232
+ );
1233
+
1234
+ // Now, lets create some cells
1235
+ var currentWeight = 1;
1236
+ for ( var i = 0; i < f.cells; i ++ ) {
1237
+ cells.push( currentWeight );
1238
+ currentWeight *= f.ratio;
1239
+ }
1240
+
1241
+ // Now lets make sure that the row weights add up to 1
1242
+
1243
+ var totalRowWeight = _.reduce( cells, function ( memo, weight ) {
1244
+ return memo + weight;
1245
+ } );
1246
+ cells = _.map( cells, function ( cell ) {
1247
+ return cell / totalRowWeight;
1248
+ } );
1249
+
1250
+ // Don't return cells that are too small
1251
+ cells = _.filter( cells, function ( cell ) {
1252
+ return cell > 0.01;
1253
+ } );
1254
+
1255
+ if ( f.direction === 'left' ) {
1256
+ cells = cells.reverse();
1257
+ }
1258
+
1259
+ this.row.cells = cells;
1260
+
1261
+ if ( cellCountChanged ) {
1262
+ this.regenerateRowPreview();
1263
+ } else {
1264
+ var thisDialog = this;
1265
+
1266
+ // Now lets animate the cells into their new widths
1267
+ this.$( '.preview-cell' ).each( function ( i, el ) {
1268
+ $( el ).animate( {'width': Math.round( thisDialog.row.cells[i] * 1000 ) / 10 + "%"}, 250 );
1269
+ $( el ).find( '.preview-cell-weight' ).html( Math.round( thisDialog.row.cells[i] * 1000 ) / 10 );
1270
+ } );
1271
+
1272
+ // So the draggable handle is not hidden.
1273
+ this.$( '.preview-cell' ).css( 'overflow', 'visible' );
1274
+
1275
+ setTimeout( function () {
1276
+ thisDialog.regenerateRowPreview();
1277
+ }, 260 );
1278
+ }
1279
+
1280
+
1281
+ // Remove the button primary class
1282
+ this.$( '.row-set-form .so-button-row-set' ).removeClass( 'button-primary' );
1283
+ },
1284
+
1285
+ /**
1286
+ * Handle a click on the dialog left bar tab
1287
+ */
1288
+ tabClickHandler: function ( $t ) {
1289
+ if ( $t.attr( 'href' ) === '#row-layout' ) {
1290
+ this.$( '.so-panels-dialog' ).addClass( 'so-panels-dialog-has-right-sidebar' );
1291
+ } else {
1292
+ this.$( '.so-panels-dialog' ).removeClass( 'so-panels-dialog-has-right-sidebar' );
1293
+ }
1294
+ },
1295
+
1296
+ /**
1297
+ * Update the current model with what we have in the dialog
1298
+ */
1299
+ updateModel: function ( args ) {
1300
+ args = _.extend( {
1301
+ refresh: true,
1302
+ refreshArgs: null
1303
+ }, args );
1304
+
1305
+ // Set the cells
1306
+ if( ! _.isUndefined( this.model ) ) {
1307
+ this.model.setCells( this.row.cells );
1308
+ }
1309
+
1310
+ // Update the styles if they've loaded
1311
+ if ( ! _.isUndefined( this.styles ) && this.styles.stylesLoaded ) {
1312
+ // This is an edit dialog, so there are styles
1313
+ var style = {};
1314
+ try {
1315
+ style = this.getFormValues( '.so-sidebar .so-visual-styles' ).style;
1316
+ }
1317
+ catch ( e ) {
1318
+ }
1319
+
1320
+ this.model.set( 'style', style );
1321
+ }
1322
+
1323
+ if ( args.refresh ) {
1324
+ this.builder.model.refreshPanelsData( args.refreshArgs );
1325
+ }
1326
+ },
1327
+
1328
+ /**
1329
+ * Insert the new row
1330
+ */
1331
+ insertHandler: function () {
1332
+ this.builder.addHistoryEntry( 'row_added' );
1333
+
1334
+ this.model = new panels.model.row();
1335
+ this.updateModel();
1336
+
1337
+ var activeCell = this.builder.getActiveCell( {
1338
+ createCell: false,
1339
+ defaultPosition: 'last'
1340
+ } );
1341
+
1342
+ var options = {};
1343
+ if ( activeCell !== null ) {
1344
+ options.at = this.builder.model.rows.indexOf( activeCell.row ) + 1;
1345
+ }
1346
+
1347
+ // Set up the model and add it to the builder
1348
+ this.model.collection = this.builder.model.rows;
1349
+ this.builder.model.rows.add( this.model, options );
1350
+
1351
+ this.closeDialog();
1352
+
1353
+ this.builder.model.refreshPanelsData();
1354
+
1355
+ return false;
1356
+ },
1357
+
1358
+ /**
1359
+ * We'll just save this model and close the dialog
1360
+ */
1361
+ saveHandler: function () {
1362
+ this.builder.addHistoryEntry( 'row_edited' );
1363
+ this.updateModel();
1364
+ this.closeDialog();
1365
+
1366
+ this.builder.model.refreshPanelsData();
1367
+
1368
+ return false;
1369
+ },
1370
+
1371
+ /**
1372
+ * The user clicks delete, so trigger deletion on the row model
1373
+ */
1374
+ deleteHandler: function () {
1375
+ // Trigger a destroy on the model that will happen with a visual indication to the user
1376
+ this.model.trigger( 'visual_destroy' );
1377
+ this.closeDialog( {silent: true} );
1378
+
1379
+ return false;
1380
+ },
1381
+
1382
+ /**
1383
+ * Duplicate this row
1384
+ */
1385
+ duplicateHandler: function () {
1386
+ this.builder.addHistoryEntry( 'row_duplicated' );
1387
+
1388
+ var duplicateRow = this.model.clone( this.builder.model );
1389
+
1390
+ this.builder.model.rows.add( duplicateRow, {
1391
+ at: this.builder.model.rows.indexOf( this.model ) + 1
1392
+ } );
1393
+
1394
+ this.closeDialog( {silent: true} );
1395
+
1396
+ return false;
1397
+ }
1398
+
1399
+ } );
1400
+
1401
+ },{}],9:[function(require,module,exports){
1402
+ var panels = window.panels, $ = jQuery;
1403
+
1404
+ module.exports = panels.view.dialog.extend( {
1405
+
1406
+ builder: null,
1407
+ sidebarWidgetTemplate: _.template( $( '#siteorigin-panels-dialog-widget-sidebar-widget' ).html().panelsProcessTemplate() ),
1408
+ dialogClass: 'so-panels-dialog-edit-widget',
1409
+ widgetView: false,
1410
+ savingWidget: false,
1411
+
1412
+ events: {
1413
+ 'click .so-close': 'saveHandler',
1414
+ 'click .so-nav.so-previous': 'navToPrevious',
1415
+ 'click .so-nav.so-next': 'navToNext',
1416
+
1417
+ // Action handlers
1418
+ 'click .so-toolbar .so-delete': 'deleteHandler',
1419
+ 'click .so-toolbar .so-duplicate': 'duplicateHandler'
1420
+ },
1421
+
1422
+ initializeDialog: function () {
1423
+ var thisView = this;
1424
+ this.model.on( 'change:values', this.handleChangeValues, this );
1425
+ this.model.on( 'destroy', this.remove, this );
1426
+
1427
+ // Refresh panels data after both dialog form components are loaded
1428
+ this.dialogFormsLoaded = 0;
1429
+ this.on( 'form_loaded styles_loaded', function () {
1430
+ this.dialogFormsLoaded ++;
1431
+ if ( this.dialogFormsLoaded === 2 ) {
1432
+ thisView.updateModel( {
1433
+ refreshArgs: {
1434
+ silent: true
1435
+ }
1436
+ } );
1437
+ }
1438
+ } );
1439
+ },
1440
+
1441
+ /**
1442
+ * Render the widget dialog.
1443
+ */
1444
+ render: function () {
1445
+ // Render the dialog and attach it to the builder interface
1446
+ this.renderDialog( this.parseDialogContent( $( '#siteorigin-panels-dialog-widget' ).html(), {} ) );
1447
+ this.loadForm();
1448
+
1449
+ if ( ! _.isUndefined( panelsOptions.widgets[this.model.get( 'class' )] ) ) {
1450
+ this.$( '.so-title .widget-name' ).html( panelsOptions.widgets[this.model.get( 'class' )].title );
1451
+ } else {
1452
+ this.$( '.so-title .widget-name' ).html( panelsOptions.loc.missing_widget.title );
1453
+ }
1454
+
1455
+ // Now we need to attach the style window
1456
+ this.styles = new panels.view.styles();
1457
+ this.styles.model = this.model;
1458
+ this.styles.render( 'widget', $( '#post_ID' ).val(), {
1459
+ builderType: this.builder.builderType,
1460
+ dialog: this
1461
+ } );
1462
+
1463
+ var $rightSidebar = this.$( '.so-sidebar.so-right-sidebar' );
1464
+ this.styles.attach( $rightSidebar );
1465
+
1466
+ // Handle the loading class
1467
+ this.styles.on( 'styles_loaded', function ( hasStyles ) {
1468
+ // If we have styles remove the loading spinner, else remove the whole empty sidebar.
1469
+ if ( hasStyles ) {
1470
+ $rightSidebar.removeClass( 'so-panels-loading' );
1471
+ } else {
1472
+ $rightSidebar.closest( '.so-panels-dialog' ).removeClass( 'so-panels-dialog-has-right-sidebar' );
1473
+ $rightSidebar.remove();
1474
+ }
1475
+ }, this );
1476
+ $rightSidebar.addClass( 'so-panels-loading' );
1477
+ },
1478
+
1479
+ /**
1480
+ * Get the previous widget editing dialog by looking at the dom.
1481
+ * @returns {*}
1482
+ */
1483
+ getPrevDialog: function () {
1484
+ var widgets = this.builder.$( '.so-cells .cell .so-widget' );
1485
+ if ( widgets.length <= 1 ) {
1486
+ return false;
1487
+ }
1488
+ var currentIndex = widgets.index( this.widgetView.$el );
1489
+
1490
+ if ( currentIndex === 0 ) {
1491
+ return false;
1492
+ } else {
1493
+ var widgetView = widgets.eq( currentIndex - 1 ).data( 'view' );
1494
+ if ( _.isUndefined( widgetView ) ) {
1495
+ return false;
1496
+ }
1497
+
1498
+ return widgetView.getEditDialog();
1499
+ }
1500
+ },
1501
+
1502
+ /**
1503
+ * Get the next widget editing dialog by looking at the dom.
1504
+ * @returns {*}
1505
+ */
1506
+ getNextDialog: function () {
1507
+ var widgets = this.builder.$( '.so-cells .cell .so-widget' );
1508
+ if ( widgets.length <= 1 ) {
1509
+ return false;
1510
+ }
1511
+ var currentIndex = widgets.index( this.widgetView.$el );
1512
+
1513
+ if ( currentIndex === widgets.length - 1 ) {
1514
+ return false;
1515
+ } else {
1516
+ var widgetView = widgets.eq( currentIndex + 1 ).data( 'view' );
1517
+ if ( _.isUndefined( widgetView ) ) {
1518
+ return false;
1519
+ }
1520
+
1521
+ return widgetView.getEditDialog();
1522
+ }
1523
+ },
1524
+
1525
+ /**
1526
+ * Load the widget form from the server.
1527
+ * This is called when rendering the dialog for the first time.
1528
+ */
1529
+ loadForm: function () {
1530
+ // don't load the form if this dialog hasn't been rendered yet
1531
+ if ( ! this.$( '> *' ).length ) {
1532
+ return;
1533
+ }
1534
+
1535
+ var thisView = this;
1536
+ this.$( '.so-content' ).addClass( 'so-panels-loading' );
1537
+
1538
+ var data = {
1539
+ 'action': 'so_panels_widget_form',
1540
+ 'widget': this.model.get( 'class' ),
1541
+ 'instance': JSON.stringify( this.model.get( 'values' ) ),
1542
+ 'raw': this.model.get( 'raw' )
1543
+ };
1544
+
1545
+ $.post(
1546
+ panelsOptions.ajaxurl,
1547
+ data,
1548
+ function ( result ) {
1549
+ // Add in the CID of the widget model
1550
+ var html = result.replace( /{\$id}/g, thisView.model.cid );
1551
+
1552
+ // Load this content into the form
1553
+ thisView.$( '.so-content' )
1554
+ .removeClass( 'so-panels-loading' )
1555
+ .html( html );
1556
+
1557
+ // Trigger all the necessary events
1558
+ thisView.trigger( 'form_loaded', thisView );
1559
+
1560
+ // For legacy compatibility, trigger a panelsopen event
1561
+ thisView.$( '.panel-dialog' ).trigger( 'panelsopen' );
1562
+
1563
+ // If the main dialog is closed from this point on, save the widget content
1564
+ thisView.on( 'close_dialog', thisView.updateModel, thisView );
1565
+ },
1566
+ 'html'
1567
+ );
1568
+ },
1569
+
1570
+ /**
1571
+ * Save the widget from the form to the model
1572
+ */
1573
+ updateModel: function ( args ) {
1574
+ args = _.extend( {
1575
+ refresh: true,
1576
+ refreshArgs: null
1577
+ }, args );
1578
+
1579
+ // Get the values from the form and assign the new values to the model
1580
+ this.savingWidget = true;
1581
+
1582
+ if ( ! this.model.get( 'missing' ) ) {
1583
+ // Only get the values for non missing widgets.
1584
+ var values = this.getFormValues();
1585
+ if ( _.isUndefined( values.widgets ) ) {
1586
+ values = {};
1587
+ } else {
1588
+ values = values.widgets;
1589
+ values = values[Object.keys( values )[0]];
1590
+ }
1591
+
1592
+ this.model.setValues( values );
1593
+ this.model.set( 'raw', true ); // We've saved from the widget form, so this is now raw
1594
+ }
1595
+
1596
+ if ( this.styles.stylesLoaded ) {
1597
+ // If the styles view has loaded
1598
+ var style = {};
1599
+ try {
1600
+ style = this.getFormValues( '.so-sidebar .so-visual-styles' ).style;
1601
+ }
1602
+ catch ( e ) {
1603
+ }
1604
+ this.model.set( 'style', style );
1605
+ }
1606
+
1607
+ this.savingWidget = false;
1608
+
1609
+ if ( args.refresh ) {
1610
+ this.builder.model.refreshPanelsData( args.refreshArgs );
1611
+ }
1612
+ },
1613
+
1614
+ /**
1615
+ *
1616
+ */
1617
+ handleChangeValues: function () {
1618
+ if ( ! this.savingWidget ) {
1619
+ // Reload the form when we've changed the model and we're not currently saving from the form
1620
+ this.loadForm();
1621
+ }
1622
+ },
1623
+
1624
+ /**
1625
+ * Save a history entry for this widget. Called when the dialog is closed.
1626
+ */
1627
+ saveHandler: function () {
1628
+ this.builder.addHistoryEntry( 'widget_edited' );
1629
+ this.closeDialog();
1630
+ },
1631
+
1632
+ /**
1633
+ * When the user clicks delete.
1634
+ *
1635
+ * @returns {boolean}
1636
+ */
1637
+ deleteHandler: function () {
1638
+
1639
+ this.model.trigger( 'visual_destroy' );
1640
+ this.closeDialog( {silent: true} );
1641
+ this.builder.model.refreshPanelsData();
1642
+
1643
+ return false;
1644
+ },
1645
+
1646
+ duplicateHandler: function () {
1647
+ this.model.trigger( 'user_duplicate' );
1648
+
1649
+ this.closeDialog( {silent: true} );
1650
+ this.builder.model.refreshPanelsData();
1651
+
1652
+ return false;
1653
+ }
1654
+
1655
+ } );
1656
+
1657
+ },{}],10:[function(require,module,exports){
1658
+ var panels = window.panels, $ = jQuery;
1659
+
1660
+ module.exports = panels.view.dialog.extend( {
1661
+
1662
+ builder: null,
1663
+ widgetTemplate: _.template( $( '#siteorigin-panels-dialog-widgets-widget' ).html().panelsProcessTemplate() ),
1664
+ filter: {},
1665
+
1666
+ dialogClass: 'so-panels-dialog-add-widget',
1667
+
1668
+ events: {
1669
+ 'click .so-close': 'closeDialog',
1670
+ 'click .widget-type': 'widgetClickHandler',
1671
+ 'keyup .so-sidebar-search': 'searchHandler'
1672
+ },
1673
+
1674
+ /**
1675
+ * Initialize the widget adding dialog
1676
+ */
1677
+ initializeDialog: function () {
1678
+
1679
+ this.on( 'open_dialog', function () {
1680
+ this.filter.search = '';
1681
+ this.filterWidgets( this.filter );
1682
+ }, this );
1683
+
1684
+ this.on( 'open_dialog_complete', function () {
1685
+ // Clear the search and re-filter the widgets when we open the dialog
1686
+ this.$( '.so-sidebar-search' ).val( '' ).focus();
1687
+ this.balanceWidgetHeights();
1688
+ } );
1689
+
1690
+ // We'll implement a custom tab click handler
1691
+ this.on( 'tab_click', this.tabClickHandler, this );
1692
+ },
1693
+
1694
+ render: function () {
1695
+ // Render the dialog and attach it to the builder interface
1696
+ this.renderDialog( this.parseDialogContent( $( '#siteorigin-panels-dialog-widgets' ).html(), {} ) );
1697
+
1698
+ // Add all the widgets
1699
+ _.each( panelsOptions.widgets, function ( widget ) {
1700
+ var $w = $( this.widgetTemplate( {
1701
+ title: widget.title,
1702
+ description: widget.description
1703
+ } ) );
1704
+
1705
+ if ( _.isUndefined( widget.icon ) ) {
1706
+ widget.icon = 'dashicons dashicons-admin-generic';
1707
+ }
1708
+
1709
+ $( '<span class="widget-icon" />' ).addClass( widget.icon ).prependTo( $w.find( '.widget-type-wrapper' ) );
1710
+
1711
+ $w.data( 'class', widget.class ).appendTo( this.$( '.widget-type-list' ) );
1712
+ }, this );
1713
+
1714
+ // Add the sidebar tabs
1715
+ var tabs = this.$( '.so-sidebar-tabs' );
1716
+ _.each( panelsOptions.widget_dialog_tabs, function ( tab ) {
1717
+ $( this.dialogTabTemplate( {'title': tab.title} ) ).data( {
1718
+ 'message': tab.message,
1719
+ 'filter': tab.filter
1720
+ } ).appendTo( tabs );
1721
+ }, this );
1722
+
1723
+ // We'll be using tabs, so initialize them
1724
+ this.initTabs();
1725
+
1726
+ var thisDialog = this;
1727
+ $( window ).resize( function () {
1728
+ thisDialog.balanceWidgetHeights();
1729
+ } );
1730
+ },
1731
+
1732
+ /**
1733
+ * Handle a tab being clicked
1734
+ */
1735
+ tabClickHandler: function ( $t ) {
1736
+ // Get the filter from the tab, and filter the widgets
1737
+ this.filter = $t.parent().data( 'filter' );
1738
+ this.filter.search = this.$( '.so-sidebar-search' ).val();
1739
+
1740
+ var message = $t.parent().data( 'message' );
1741
+ if ( _.isEmpty( message ) ) {
1742
+ message = '';
1743
+ }
1744
+
1745
+ this.$( '.so-toolbar .so-status' ).html( message );
1746
+
1747
+ this.filterWidgets( this.filter );
1748
+
1749
+ return false;
1750
+ },
1751
+
1752
+ /**
1753
+ * Handle changes to the search value
1754
+ */
1755
+ searchHandler: function ( e ) {
1756
+ this.filter.search = $( e.target ).val();
1757
+ this.filterWidgets( this.filter );
1758
+ },
1759
+
1760
+ /**
1761
+ * Filter the widgets that we're displaying
1762
+ * @param filter
1763
+ */
1764
+ filterWidgets: function ( filter ) {
1765
+ if ( _.isUndefined( filter ) ) {
1766
+ filter = {};
1767
+ }
1768
+
1769
+ if ( _.isUndefined( filter.groups ) ) {
1770
+ filter.groups = '';
1771
+ }
1772
+
1773
+ this.$( '.widget-type-list .widget-type' ).each( function () {
1774
+ var $$ = $( this ), showWidget;
1775
+ var widgetClass = $$.data( 'class' );
1776
+
1777
+ var widgetData = (
1778
+ ! _.isUndefined( panelsOptions.widgets[widgetClass] )
1779
+ ) ? panelsOptions.widgets[widgetClass] : null;
1780
+
1781
+ if ( _.isEmpty( filter.groups ) ) {
1782
+ // This filter doesn't specify groups, so show all
1783
+ showWidget = true;
1784
+ } else if ( widgetData !== null && ! _.isEmpty( _.intersection( filter.groups, panelsOptions.widgets[widgetClass].groups ) ) ) {
1785
+ // This widget is in the filter group
1786
+ showWidget = true;
1787
+ } else {
1788
+ // This widget is not in the filter group
1789
+ showWidget = false;
1790
+ }
1791
+
1792
+ // This can probably be done with a more intelligent operator
1793
+ if ( showWidget ) {
1794
+
1795
+ if ( ! _.isUndefined( filter.search ) && filter.search !== '' ) {
1796
+ // Check if the widget title contains the search term
1797
+ if ( widgetData.title.toLowerCase().indexOf( filter.search.toLowerCase() ) === - 1 ) {
1798
+ showWidget = false;
1799
+ }
1800
+ }
1801
+
1802
+ }
1803
+
1804
+ if ( showWidget ) {
1805
+ $$.show();
1806
+ } else {
1807
+ $$.hide();
1808
+ }
1809
+ } );
1810
+
1811
+ // Balance the tags after filtering
1812
+ this.balanceWidgetHeights();
1813
+ },
1814
+
1815
+ /**
1816
+ * Add the widget to the current builder
1817
+ *
1818
+ * @param e
1819
+ */
1820
+ widgetClickHandler: function ( e ) {
1821
+ // Add the history entry
1822
+ this.builder.addHistoryEntry( 'widget_added' );
1823
+
1824
+ var $w = $( e.currentTarget );
1825
+
1826
+ var widget = new panels.model.widget( {
1827
+ class: $w.data( 'class' )
1828
+ } );
1829
+
1830
+ // Add the widget to the cell model
1831
+ widget.cell = this.builder.getActiveCell();
1832
+ widget.cell.widgets.add( widget );
1833
+
1834
+ this.closeDialog();
1835
+ this.builder.model.refreshPanelsData();
1836
+ },
1837
+
1838
+ /**
1839
+ * Balance widgets in a given row so they have enqual height.
1840
+ * @param e
1841
+ */
1842
+ balanceWidgetHeights: function ( e ) {
1843
+ var widgetRows = [[]];
1844
+ var previousWidget = null;
1845
+
1846
+ // Work out how many widgets there are per row
1847
+ var perRow = Math.round( this.$( '.widget-type' ).parent().width() / this.$( '.widget-type' ).width() );
1848
+
1849
+ // Add clears to create balanced rows
1850
+ this.$( '.widget-type' )
1851
+ .css( 'clear', 'none' )
1852
+ .filter( ':visible' )
1853
+ .each( function ( i, el ) {
1854
+ if ( i % perRow === 0 && i !== 0 ) {
1855
+ $( el ).css( 'clear', 'both' );
1856
+ }
1857
+ } );
1858
+
1859
+ // Group the widgets into rows
1860
+ this.$( '.widget-type-wrapper' )
1861
+ .css( 'height', 'auto' )
1862
+ .filter( ':visible' )
1863
+ .each( function ( i, el ) {
1864
+ var $el = $( el );
1865
+ if ( previousWidget !== null && previousWidget.position().top !== $el.position().top ) {
1866
+ widgetRows[widgetRows.length] = [];
1867
+ }
1868
+ previousWidget = $el;
1869
+ widgetRows[widgetRows.length - 1].push( $el );
1870
+ } );
1871
+
1872
+ // Balance the height of the widgets within the row.
1873
+ _.each( widgetRows, function ( row, i ) {
1874
+ var maxHeight = _.max( row.map( function ( el ) {
1875
+ return el.height();
1876
+ } ) );
1877
+ // Set the height of each widget in the row
1878
+ _.each( row, function ( el ) {
1879
+ el.height( maxHeight );
1880
+ } );
1881
+
1882
+ } );
1883
+ }
1884
+ } );
1885
+
1886
+ },{}],11:[function(require,module,exports){
1887
+ /* global _, jQuery, panels */
1888
+
1889
+ var panels = window.panels, $ = jQuery;
1890
+
1891
+ module.exports = function () {
1892
+
1893
+ return this.each( function () {
1894
+ var $$ = jQuery( this );
1895
+ var widgetId = $$.closest( 'form' ).find( '.widget-id' ).val();
1896
+
1897
+ // Exit if this isn't a real widget
1898
+ if ( ! _.isUndefined( widgetId ) && widgetId.indexOf( '__i__' ) > - 1 ) {
1899
+ return;
1900
+ }
1901
+
1902
+ // Create the main builder model
1903
+ var builderModel = new panels.model.builder();
1904
+
1905
+ // Now for the view to display the builder
1906
+ var builderView = new panels.view.builder( {
1907
+ model: builderModel
1908
+ } );
1909
+
1910
+ // Save panels data when we close the dialog, if we're in a dialog
1911
+ var dialog = $$.closest( '.so-panels-dialog-wrapper' ).data( 'view' );
1912
+ if ( ! _.isUndefined( dialog ) ) {
1913
+ dialog.on( 'close_dialog', function () {
1914
+ builderModel.refreshPanelsData();
1915
+ } );
1916
+
1917
+ dialog.on( 'open_dialog_complete', function () {
1918
+ // Make sure the new layout widget is always properly setup
1919
+ builderView.trigger( 'builder_resize' );
1920
+ } );
1921
+
1922
+ dialog.model.on( 'destroy', function () {
1923
+ // Destroy the builder
1924
+ builderModel.emptyRows().destroy();
1925
+ } );
1926
+
1927
+ // Set the parent for all the sub dialogs
1928
+ builderView.setDialogParents( panelsOptions.loc.layout_widget, dialog );
1929
+ }
1930
+
1931
+ // Basic setup for the builder
1932
+ var isWidget = Boolean( $$.closest( '.widget-content' ).length );
1933
+ builderView
1934
+ .render()
1935
+ .attach( {
1936
+ container: $$,
1937
+ dialog: isWidget,
1938
+ type: $$.data( 'type' )
1939
+ } )
1940
+ .setDataField( $$.find( 'input.panels-data' ) );
1941
+
1942
+ if ( isWidget ) {
1943
+ // Set up the dialog opening
1944
+ builderView.setDialogParents( panelsOptions.loc.layout_widget, builderView.dialog );
1945
+ $$.find( '.siteorigin-panels-display-builder' ).click( function () {
1946
+ builderView.dialog.openDialog();
1947
+ } );
1948
+ } else {
1949
+ // Remove the dialog opener button, this is already being displayed in a page builder dialog.
1950
+ $$.find( '.siteorigin-panels-display-builder' ).parent().remove();
1951
+ }
1952
+
1953
+ // Trigger a global jQuery event after we've setup the builder view
1954
+ $( document ).trigger( 'panels_setup', builderView );
1955
+ } );
1956
+ };
1957
+
1958
+ },{}],12:[function(require,module,exports){
1959
+ /**
1960
+ * Everything we need for SiteOrigin Page Builder.
1961
+ *
1962
+ * @copyright Greg Priday 2013 - 2014 - <https://siteorigin.com/>
1963
+ * @license GPL 3.0 http://www.gnu.org/licenses/gpl.html
1964
+ */
1965
+
1966
+ /* global Backbone, _, jQuery, tinyMCE, panelsOptions, plupload, confirm, console */
1967
+
1968
+ /**
1969
+ * Convert template into something compatible with Underscore.js templates
1970
+ *
1971
+ * @param s
1972
+ * @return {*}
1973
+ */
1974
+ String.prototype.panelsProcessTemplate = function () {
1975
+ var s = this;
1976
+ s = s.replace( /{{%/g, '<%' );
1977
+ s = s.replace( /%}}/g, '%>' );
1978
+ s = s.trim();
1979
+ return s;
1980
+ };
1981
+
1982
+ var panels = {};
1983
+
1984
+ // Store everything globally
1985
+ window.panels = panels;
1986
+ window.siteoriginPanels = panels;
1987
+
1988
+ // The models
1989
+ panels.model = {};
1990
+ panels.model.widget = require( './model/widget' );
1991
+ panels.model.cell = require( './model/cell' );
1992
+ panels.model.row = require( './model/row' );
1993
+ panels.model.builder = require( './model/builder' );
1994
+ panels.model.historyEntry = require( './model/history-entry' );
1995
+
1996
+ // The collections
1997
+ panels.collection = {};
1998
+ panels.collection.widgets = require( './collection/widgets' );
1999
+ panels.collection.cells = require( './collection/cells' );
2000
+ panels.collection.rows = require( './collection/rows' );
2001
+ panels.collection.historyEntries = require( './collection/history-entries' );
2002
+
2003
+ // The views
2004
+ panels.view = {};
2005
+ panels.view.widget = require( './view/widget' );
2006
+ panels.view.cell = require( './view/cell' );
2007
+ panels.view.row = require( './view/row' );
2008
+ panels.view.builder = require( './view/builder' );
2009
+ panels.view.dialog = require( './view/dialog' );
2010
+ panels.view.styles = require( './view/styles' );
2011
+ panels.view.liveEditor = require( './view/live-editor' );
2012
+
2013
+ // The dialogs
2014
+ panels.dialog = {};
2015
+ panels.dialog.builder = require( './dialog/builder' );
2016
+ panels.dialog.widgets = require( './dialog/widgets' );
2017
+ panels.dialog.widget = require( './dialog/widget' );
2018
+ panels.dialog.prebuilt = require( './dialog/prebuilt' );
2019
+ panels.dialog.row = require( './dialog/row' );
2020
+ panels.dialog.history = require( './dialog/history' );
2021
+
2022
+ // The utils
2023
+ panels.utils = {};
2024
+ panels.utils.menu = require( './utils/menu' );
2025
+
2026
+ // jQuery Plugins
2027
+ jQuery.fn.soPanelsSetupBuilderWidget = require( './jquery/setup-builder-widget' );
2028
+
2029
+
2030
+ // Set up Page Builder if we're on the main interface
2031
+ jQuery( function ( $ ) {
2032
+
2033
+ var container, field, form, editorType, editorId, postId, builderType;
2034
+
2035
+ if ( $( '#siteorigin-panels-metabox' ).length && $( 'form#post' ).length ) {
2036
+ // This is usually the case when we're in the post edit interface
2037
+ container = $( '#siteorigin-panels-metabox' );
2038
+ field = $( '#siteorigin-panels-metabox .siteorigin-panels-data-field' );
2039
+ form = $( 'form#post' );
2040
+ editorType = 'tinymce';
2041
+ editorId = '#content';
2042
+ postId = $( '#post_ID' ).val();
2043
+ builderType = 'editor_attached';
2044
+ }
2045
+ else if ( $( '.siteorigin-panels-builder-form' ).length ) {
2046
+ // We're dealing with another interface like the custom home page interface
2047
+ var $$ = $( '.siteorigin-panels-builder-form' );
2048
+ container = $$.find( '.siteorigin-panels-builder-container' );
2049
+ field = $$.find( 'input[name="panels_data"]' );
2050
+ form = $$;
2051
+ editorId = '#post_content';
2052
+ postId = $( '#panels-home-page' ).data( 'post-id' );
2053
+ builderType = $$.data( 'type' );
2054
+ }
2055
+
2056
+ if ( ! _.isUndefined( container ) ) {
2057
+ // If we have a container, then set up the main builder
2058
+ var panels = window.siteoriginPanels;
2059
+
2060
+ // Create the main builder model
2061
+ var builderModel = new panels.model.builder();
2062
+
2063
+ // Create the builder config
2064
+ var builderConfig = {
2065
+ editorType: editorType,
2066
+ postId: postId,
2067
+ editorId: editorId,
2068
+ builderType: builderType,
2069
+ };
2070
+
2071
+ // Now for the view to display the builder
2072
+ var builderView = new panels.view.builder( {
2073
+ model: builderModel,
2074
+ config: builderConfig,
2075
+ } );
2076
+
2077
+ // Set up the builder view
2078
+ builderView
2079
+ .render()
2080
+ .attach( {
2081
+ container: container,
2082
+ type: builderType
2083
+ } )
2084
+ .setDataField( field )
2085
+ .attachToEditor()
2086
+ .addLiveEditor( postId )
2087
+ .addHistoryBrowser();
2088
+
2089
+ // When the form is submitted, update the panels data
2090
+ form.submit( function ( e ) {
2091
+ // Refresh the data
2092
+ builderModel.refreshPanelsData();
2093
+ } );
2094
+
2095
+ container.removeClass( 'so-panels-loading' );
2096
+
2097
+ // Trigger a global jQuery event after we've setup the builder view. Everything is accessible form there
2098
+ $( document ).trigger( 'panels_setup', builderView, window.panels );
2099
+ }
2100
+
2101
+ // Setup new widgets when they're added in the standard widget interface
2102
+ $( document ).on( 'widget-added', function ( e, widget ) {
2103
+ $( widget ).find( '.siteorigin-page-builder-widget' ).soPanelsSetupBuilderWidget();
2104
+ } );
2105
+
2106
+ // Setup existing widgets on the page (for the widgets interface)
2107
+ if ( ! $( 'body' ).hasClass( 'wp-customizer' ) ) {
2108
+ $( function () {
2109
+ $( '.siteorigin-page-builder-widget' ).soPanelsSetupBuilderWidget();
2110
+ } );
2111
+ }
2112
+ } );
2113
+
2114
+ },{"./collection/cells":1,"./collection/history-entries":2,"./collection/rows":3,"./collection/widgets":4,"./dialog/builder":5,"./dialog/history":6,"./dialog/prebuilt":7,"./dialog/row":8,"./dialog/widget":9,"./dialog/widgets":10,"./jquery/setup-builder-widget":11,"./model/builder":13,"./model/cell":14,"./model/history-entry":15,"./model/row":16,"./model/widget":17,"./utils/menu":18,"./view/builder":19,"./view/cell":20,"./view/dialog":21,"./view/live-editor":22,"./view/row":23,"./view/styles":24,"./view/widget":25}],13:[function(require,module,exports){
2115
+ module.exports = Backbone.Model.extend( {
2116
+ layoutPosition: {
2117
+ BEFORE: 'before',
2118
+ AFTER: 'after',
2119
+ REPLACE: 'replace',
2120
+ },
2121
+
2122
+ rows: {},
2123
+
2124
+ defaults: {
2125
+ 'data': {
2126
+ 'widgets': [],
2127
+ 'grids': [],
2128
+ 'grid_cells': []
2129
+ }
2130
+ },
2131
+
2132
+ initialize: function () {
2133
+ // These are the main rows in the interface
2134
+ this.rows = new panels.collection.rows();
2135
+ },
2136
+
2137
+ /**
2138
+ * Add a new row to this builder.
2139
+ *
2140
+ * @param weights
2141
+ */
2142
+ addRow: function ( weights, options ) {
2143
+ options = _.extend( {
2144
+ noAnimate: false
2145
+ }, options );
2146
+ // Create the actual row
2147
+ var row = new panels.model.row( {
2148
+ collection: this.rows
2149
+ } );
2150
+
2151
+ row.setCells( weights );
2152
+ row.builder = this;
2153
+
2154
+ this.rows.add( row, options );
2155
+
2156
+ return row;
2157
+ },
2158
+
2159
+ /**
2160
+ * Load the panels data into the builder
2161
+ *
2162
+ * @param data Object the layout and widgets data to load.
2163
+ * @param position string Where to place the new layout. Allowed options are 'before', 'after'. Anything else will
2164
+ * cause the new layout to replace the old one.
2165
+ */
2166
+ loadPanelsData: function ( data, position ) {
2167
+
2168
+ if ( position === this.layoutPosition.BEFORE ) {
2169
+ data = this.concatPanelsData( data, this.getPanelsData() );
2170
+ } else if ( position === this.layoutPosition.AFTER ) {
2171
+ data = this.concatPanelsData( this.getPanelsData(), data );
2172
+ }
2173
+
2174
+ // Start by destroying any rows that currently exist. This will in turn destroy cells, widgets and all the associated views
2175
+ this.emptyRows();
2176
+
2177
+ // This will empty out the current rows and reload the builder data.
2178
+ this.set( 'data', JSON.parse( JSON.stringify( data ) ), {silent: true} );
2179
+
2180
+ var cit = 0;
2181
+ var rows = [];
2182
+
2183
+ if ( _.isUndefined( data.grid_cells ) ) {
2184
+ this.trigger( 'load_panels_data' );
2185
+ return;
2186
+ }
2187
+
2188
+ var gi;
2189
+ for ( var ci = 0; ci < data.grid_cells.length; ci ++ ) {
2190
+ gi = parseInt( data.grid_cells[ci].grid );
2191
+ if ( _.isUndefined( rows[gi] ) ) {
2192
+ rows[gi] = [];
2193
+ }
2194
+
2195
+ rows[gi].push( parseFloat( data.grid_cells[ci].weight ) );
2196
+ }
2197
+
2198
+ var builderModel = this;
2199
+ _.each( rows, function ( row, i ) {
2200
+ // This will create and add the row model and its cells
2201
+ var newRow = builderModel.addRow( row, {noAnimate: true} );
2202
+
2203
+ if ( ! _.isUndefined( data.grids[i].style ) ) {
2204
+ newRow.set( 'style', data.grids[i].style );
2205
+ }
2206
+ } );
2207
+
2208
+
2209
+ if ( _.isUndefined( data.widgets ) ) {
2210
+ return;
2211
+ }
2212
+
2213
+ // Add the widgets
2214
+ _.each( data.widgets, function ( widgetData ) {
2215
+ try {
2216
+ var panels_info = null;
2217
+ if ( ! _.isUndefined( widgetData.panels_info ) ) {
2218
+ panels_info = widgetData.panels_info;
2219
+ delete widgetData.panels_info;
2220
+ } else {
2221
+ panels_info = widgetData.info;
2222
+ delete widgetData.info;
2223
+ }
2224
+
2225
+ var row = builderModel.rows.at( parseInt( panels_info.grid ) );
2226
+ var cell = row.cells.at( parseInt( panels_info.cell ) );
2227
+
2228
+ var newWidget = new panels.model.widget( {
2229
+ class: panels_info.class,
2230
+ values: widgetData
2231
+ } );
2232
+
2233
+ if ( ! _.isUndefined( panels_info.style ) ) {
2234
+ newWidget.set( 'style', panels_info.style );
2235
+ }
2236
+
2237
+ newWidget.cell = cell;
2238
+ cell.widgets.add( newWidget, {noAnimate: true} );
2239
+ }
2240
+ catch ( err ) {
2241
+ }
2242
+ } );
2243
+
2244
+ this.trigger( 'load_panels_data' );
2245
+ },
2246
+
2247
+ /**
2248
+ * Concatenate the second set of Page Builder data to the first. There is some validation of input, but for the most
2249
+ * part it's up to the caller to ensure the Page Builder data is well formed.
2250
+ */
2251
+ concatPanelsData: function ( panelsDataA, panelsDataB ) {
2252
+
2253
+ if ( _.isUndefined( panelsDataB ) || _.isUndefined( panelsDataB.grids ) || _.isEmpty( panelsDataB.grids ) ||
2254
+ _.isUndefined( panelsDataB.grid_cells ) || _.isEmpty( panelsDataB.grid_cells ) ) {
2255
+ return panelsDataA;
2256
+ }
2257
+
2258
+ if ( _.isUndefined( panelsDataA ) || _.isUndefined( panelsDataA.grids ) || _.isEmpty( panelsDataA.grids ) ) {
2259
+ return panelsDataB;
2260
+ }
2261
+
2262
+ var gridsBOffset = panelsDataA.grids.length;
2263
+ var widgetsBOffset = ! _.isUndefined( panelsDataA.widgets ) ? panelsDataA.widgets.length : 0;
2264
+ var newPanelsData = {grids: [], 'grid_cells': [], 'widgets': []};
2265
+
2266
+ // Concatenate grids (rows)
2267
+ newPanelsData.grids = panelsDataA.grids.concat( panelsDataB.grids );
2268
+
2269
+ // Create a copy of panelsDataA grid_cells and widgets
2270
+ if ( ! _.isUndefined( panelsDataA.grid_cells ) ) {
2271
+ newPanelsData.grid_cells = panelsDataA.grid_cells.slice();
2272
+ }
2273
+ if ( ! _.isUndefined( panelsDataA.widgets ) ) {
2274
+ newPanelsData.widgets = panelsDataA.widgets.slice();
2275
+ }
2276
+
2277
+ var i;
2278
+ // Concatenate grid cells (row columns)
2279
+ for ( i = 0; i < panelsDataB.grid_cells.length; i ++ ) {
2280
+ var gridCellB = panelsDataB.grid_cells[i];
2281
+ gridCellB.grid = parseInt( gridCellB.grid ) + gridsBOffset;
2282
+ newPanelsData.grid_cells.push( gridCellB );
2283
+ }
2284
+
2285
+ // Concatenate widgets
2286
+ if ( ! _.isUndefined( panelsDataB.widgets ) ) {
2287
+ for ( i = 0; i < panelsDataB.widgets.length; i ++ ) {
2288
+ var widgetB = panelsDataB.widgets[i];
2289
+ widgetB.panels_info.grid = parseInt( widgetB.panels_info.grid ) + gridsBOffset;
2290
+ widgetB.panels_info.id = parseInt( widgetB.panels_info.id ) + widgetsBOffset;
2291
+ newPanelsData.widgets.push( widgetB );
2292
+ }
2293
+ }
2294
+
2295
+ return newPanelsData;
2296
+ },
2297
+
2298
+ /**
2299
+ * Convert the content of the builder into a object that represents the page builder data
2300
+ */
2301
+ getPanelsData: function () {
2302
+
2303
+ var data = {
2304
+ 'widgets': [],
2305
+ 'grids': [],
2306
+ 'grid_cells': []
2307
+ };
2308
+ var widgetId = 0;
2309
+
2310
+ this.rows.each( function ( row, ri ) {
2311
+
2312
+ row.cells.each( function ( cell, ci ) {
2313
+
2314
+ cell.widgets.each( function ( widget, wi ) {
2315
+ // Add the data for the widget, including the panels_info field.
2316
+ var values = _.extend( _.clone( widget.get( 'values' ) ), {
2317
+ panels_info: {
2318
+ class: widget.get( 'class' ),
2319
+ raw: widget.get( 'raw' ),
2320
+ grid: ri,
2321
+ cell: ci,
2322
+ id: widgetId ++,
2323
+ style: widget.get( 'style' )
2324
+ }
2325
+ } );
2326
+ data.widgets.push( values );
2327
+ } );
2328
+
2329
+ // Add the cell info
2330
+ data.grid_cells.push( {
2331
+ grid: ri,
2332
+ weight: cell.get( 'weight' )
2333
+ } );
2334
+
2335
+ } );
2336
+
2337
+ data.grids.push( {
2338
+ cells: row.cells.length,
2339
+ style: row.get( 'style' )
2340
+ } );
2341
+
2342
+ } );
2343
+
2344
+ return data;
2345
+
2346
+ },
2347
+
2348
+ /**
2349
+ * This will check all the current entries and refresh the panels data
2350
+ */
2351
+ refreshPanelsData: function ( args ) {
2352
+ args = _.extend( {
2353
+ silent: false
2354
+ }, args );
2355
+
2356
+ var oldData = this.get( 'data' );
2357
+ var newData = this.getPanelsData();
2358
+ this.set( 'data', newData, {silent: true} );
2359
+
2360
+ if ( ! args.silent && JSON.stringify( newData ) !== JSON.stringify( oldData ) ) {
2361
+ // The default change event doesn't trigger on deep changes, so we'll trigger our own
2362
+ this.trigger( 'change' );
2363
+ this.trigger( 'change:data' );
2364
+ this.trigger( 'refresh_panels_data', newData, args );
2365
+ }
2366
+ },
2367
+
2368
+ /**
2369
+ * Empty all the rows and the cells/widgets they contain.
2370
+ */
2371
+ emptyRows: function () {
2372
+ _.invoke( this.rows.toArray(), 'destroy' );
2373
+ this.rows.reset();
2374
+
2375
+ return this;
2376
+ },
2377
+
2378
+ isValidLayoutPosition: function ( position ) {
2379
+ return position === this.layoutPosition.BEFORE ||
2380
+ position === this.layoutPosition.AFTER ||
2381
+ position === this.layoutPosition.REPLACE;
2382
+ }
2383
+
2384
+ } );
2385
+
2386
+ },{}],14:[function(require,module,exports){
2387
+ module.exports = Backbone.Model.extend( {
2388
+ /* A collection of widgets */
2389
+ widgets: {},
2390
+
2391
+ /* The row this model belongs to */
2392
+ row: null,
2393
+
2394
+ defaults: {
2395
+ weight: 0
2396
+ },
2397
+
2398
+ indexes: null,
2399
+
2400
+ /**
2401
+ * Set up the cell model
2402
+ */
2403
+ initialize: function () {
2404
+ this.widgets = new panels.collection.widgets();
2405
+ this.on( 'destroy', this.onDestroy, this );
2406
+ },
2407
+
2408
+ /**
2409
+ * Triggered when we destroy a cell
2410
+ */
2411
+ onDestroy: function () {
2412
+ _.invoke( this.widgets.toArray(), 'destroy' );
2413
+ this.widgets.reset();
2414
+ },
2415
+
2416
+ /**
2417
+ * Create a clone of the cell, along with all its widgets
2418
+ */
2419
+ clone: function ( row, cloneOptions ) {
2420
+ if ( _.isUndefined( row ) ) {
2421
+ row = this.row;
2422
+ }
2423
+ cloneOptions = _.extend( {cloneWidgets: true}, cloneOptions );
2424
+
2425
+ var clone = new this.constructor( this.attributes );
2426
+ clone.set( 'collection', row.cells, {silent: true} );
2427
+ clone.row = row;
2428
+
2429
+ if ( cloneOptions.cloneWidgets ) {
2430
+ // Now we're going add all the widgets that belong to this, to the clone
2431
+ this.widgets.each( function ( widget ) {
2432
+ clone.widgets.add( widget.clone( clone, cloneOptions ), {silent: true} );
2433
+ } );
2434
+ }
2435
+
2436
+ return clone;
2437
+ }
2438
+
2439
+ } );
2440
+
2441
+ },{}],15:[function(require,module,exports){
2442
+ module.exports = Backbone.Model.extend( {
2443
+ defaults: {
2444
+ text: '',
2445
+ data: '',
2446
+ time: null,
2447
+ count: 1
2448
+ }
2449
+ } );
2450
+
2451
+ },{}],16:[function(require,module,exports){
2452
+ module.exports = Backbone.Model.extend( {
2453
+ /* A collection of the cells in this row */
2454
+ cells: {},
2455
+
2456
+ /* The builder model */
2457
+ builder: null,
2458
+
2459
+ defaults: {
2460
+ style: {}
2461
+ },
2462
+
2463
+ indexes: null,
2464
+
2465
+ /**
2466
+ * Initialize the row model
2467
+ */
2468
+ initialize: function () {
2469
+ this.cells = new panels.collection.cells();
2470
+ this.on( 'destroy', this.onDestroy, this );
2471
+ },
2472
+
2473
+ /**
2474
+ * Add cells to the model row
2475
+ *
2476
+ * @param cells an array of cells, where each object in the array has a weight value
2477
+ */
2478
+ setCells: function ( cells ) {
2479
+ var thisModel = this;
2480
+
2481
+ if ( _.isEmpty( this.cells ) ) {
2482
+ // We're adding the initial cells
2483
+ _.each( cells, function ( cellWeight ) {
2484
+ // Add the new cell to the row
2485
+ var cell = new panels.model.cell( {
2486
+ weight: cellWeight,
2487
+ collection: thisModel.cells
2488
+ } );
2489
+ cell.row = thisModel;
2490
+ thisModel.cells.add( cell );
2491
+ } );
2492
+ } else {
2493
+
2494
+ if ( cells.length > this.cells.length ) {
2495
+ // We need to add cells
2496
+ for ( var i = this.cells.length; i < cells.length; i ++ ) {
2497
+ var cell = new panels.model.cell( {
2498
+ weight: cells[cells.length + i],
2499
+ collection: thisModel.cells
2500
+ } );
2501
+ cell.row = this;
2502
+ thisModel.cells.add( cell );
2503
+ }
2504
+
2505
+ }
2506
+ else if ( cells.length < this.cells.length ) {
2507
+ var newParentCell = this.cells.at( cells.length - 1 );
2508
+
2509
+ // We need to remove cells
2510
+ _.each( this.cells.slice( cells.length, this.cells.length ), function ( cell ) {
2511
+ var widgetsToMove = cell.widgets.models.slice( 0 );
2512
+ for ( var i = 0; i < widgetsToMove.length; i ++ ) {
2513
+ widgetsToMove[i].moveToCell( newParentCell, {silent: false} );
2514
+ }
2515
+
2516
+ // First move all the widgets to the new cell
2517
+ cell.destroy();
2518
+ } );
2519
+ }
2520
+
2521
+ // Now we need to change the weights of all the cells
2522
+ this.cells.each( function ( cell, i ) {
2523
+ cell.set( 'weight', cells[i] );
2524
+ } );
2525
+ }
2526
+
2527
+ // Rescale the cells when we add or remove
2528
+ this.reweightCells();
2529
+ },
2530
+
2531
+ /**
2532
+ * Make sure that all the cell weights add up to 1
2533
+ */
2534
+ reweightCells: function () {
2535
+ var totalWeight = 0;
2536
+ this.cells.each( function ( cell ) {
2537
+ totalWeight += cell.get( 'weight' );
2538
+ } );
2539
+
2540
+ this.cells.each( function ( cell ) {
2541
+ cell.set( 'weight', cell.get( 'weight' ) / totalWeight );
2542
+ } );
2543
+
2544
+ // This is for the row view to hook into and resize
2545
+ this.trigger( 'reweight_cells' );
2546
+ },
2547
+
2548
+ /**
2549
+ * Triggered when the model is destroyed
2550
+ */
2551
+ onDestroy: function () {
2552
+ // Also destroy all the cells
2553
+ _.invoke( this.cells.toArray(), 'destroy' );
2554
+ this.cells.reset();
2555
+ },
2556
+
2557
+ /**
2558
+ * Create a clone of the row, along with all its cells
2559
+ *
2560
+ * @param {panels.model.builder} builder The builder model to attach this to.
2561
+ *
2562
+ * @return {panels.model.row} The cloned row.
2563
+ */
2564
+ clone: function ( builder, cloneOptions ) {
2565
+ if ( _.isUndefined( builder ) ) {
2566
+ builder = this.builder;
2567
+ }
2568
+ cloneOptions = _.extend( {cloneCells: true}, cloneOptions );
2569
+
2570
+ var clone = new this.constructor( this.attributes );
2571
+ clone.set( 'collection', builder.rows, {silent: true} );
2572
+ clone.builder = builder;
2573
+
2574
+ if ( cloneOptions.cloneCells ) {
2575
+ // Clone all the rows
2576
+ this.cells.each( function ( cell ) {
2577
+ clone.cells.add( cell.clone( clone, cloneOptions ), {silent: true} );
2578
+ } );
2579
+ }
2580
+
2581
+ return clone;
2582
+ }
2583
+ } );
2584
+
2585
+ },{}],17:[function(require,module,exports){
2586
+ /**
2587
+ * Model for an instance of a widget
2588
+ */
2589
+ module.exports = Backbone.Model.extend( {
2590
+
2591
+ cell: null,
2592
+
2593
+ defaults: {
2594
+ // The PHP Class of the widget
2595
+ class: null,
2596
+
2597
+ // Is this class missing? Missing widgets are a special case.
2598
+ missing: false,
2599
+
2600
+ // The values of the widget
2601
+ values: {},
2602
+
2603
+ // Have the current values been passed through the widgets update function
2604
+ raw: false,
2605
+
2606
+ // Visual style fields
2607
+ styles: {}
2608
+ },
2609
+
2610
+ indexes: null,
2611
+
2612
+ initialize: function () {
2613
+ var widgetClass = this.get( 'class' );
2614
+ if ( _.isUndefined( panelsOptions.widgets[widgetClass] ) || ! panelsOptions.widgets[widgetClass].installed ) {
2615
+ this.set( 'missing', true );
2616
+ }
2617
+ },
2618
+
2619
+ /**
2620
+ * @param field
2621
+ * @returns {*}
2622
+ */
2623
+ getWidgetField: function ( field ) {
2624
+ if ( _.isUndefined( panelsOptions.widgets[this.get( 'class' )] ) ) {
2625
+ if ( field === 'title' || field === 'description' ) {
2626
+ return panelsOptions.loc.missing_widget[field];
2627
+ } else {
2628
+ return '';
2629
+ }
2630
+ } else {
2631
+ return panelsOptions.widgets[this.get( 'class' )][field];
2632
+ }
2633
+ },
2634
+
2635
+ /**
2636
+ * Move this widget model to a new cell. Called by the views.
2637
+ *
2638
+ * @param panels.model.cell newCell
2639
+ *
2640
+ * @return bool Indicating if the widget was moved into a different cell
2641
+ */
2642
+ moveToCell: function ( newCell, options ) {
2643
+ options = _.extend( {
2644
+ silent: true
2645
+ }, options );
2646
+
2647
+ if ( this.cell.cid === newCell.cid ) {
2648
+ return false;
2649
+ }
2650
+
2651
+ this.cell = newCell;
2652
+ this.collection.remove( this, options );
2653
+ newCell.widgets.add( this, options );
2654
+
2655
+ return true;
2656
+ },
2657
+
2658
+ /**
2659
+ * Trigger an event on the model that indicates a user wants to edit it
2660
+ */
2661
+ triggerEdit: function () {
2662
+ this.trigger( 'user_edit', this );
2663
+ },
2664
+
2665
+ /**
2666
+ * Trigger an event on the widget that indicates a user wants to duplicate it
2667
+ */
2668
+ triggerDuplicate: function () {
2669
+ this.trigger( 'user_duplicate', this );
2670
+ },
2671
+
2672
+ /**
2673
+ * This is basically a wrapper for set that checks if we need to trigger a change
2674
+ */
2675
+ setValues: function ( values ) {
2676
+ var hasChanged = false;
2677
+ if ( JSON.stringify( values ) !== JSON.stringify( this.get( 'values' ) ) ) {
2678
+ hasChanged = true;
2679
+ }
2680
+
2681
+ this.set( 'values', values, {silent: true} );
2682
+
2683
+ if ( hasChanged ) {
2684
+ // We'll trigger our own change events.
2685
+ // NB: Must include the model being changed (i.e. `this`) as a workaround for a bug in Backbone 1.2.3
2686
+ this.trigger( 'change', this );
2687
+ this.trigger( 'change:values' );
2688
+ }
2689
+ },
2690
+
2691
+ /**
2692
+ * Create a clone of this widget attached to the given cell.
2693
+ *
2694
+ * @param {panels.model.cell} cell The cell model we're attaching this widget clone to.
2695
+ * @returns {panels.model.widget}
2696
+ */
2697
+ clone: function ( cell, options ) {
2698
+ if ( _.isUndefined( cell ) ) {
2699
+ cell = this.cell;
2700
+ }
2701
+
2702
+ var clone = new this.constructor( this.attributes );
2703
+
2704
+ // Create a deep clone of the original values
2705
+ var cloneValues = JSON.parse( JSON.stringify( this.get( 'values' ) ) );
2706
+
2707
+ // We want to exclude any fields that start with _ from the clone. Assuming these are internal.
2708
+ var cleanClone = function ( vals ) {
2709
+ _.each( vals, function ( el, i ) {
2710
+ if ( _.isString( i ) && i[0] === '_' ) {
2711
+ delete vals[i];
2712
+ }
2713
+ else if ( _.isObject( vals[i] ) ) {
2714
+ cleanClone( vals[i] );
2715
+ }
2716
+ } );
2717
+
2718
+ return vals;
2719
+ };
2720
+ cloneValues = cleanClone( cloneValues );
2721
+
2722
+ if ( this.get( 'class' ) === "SiteOrigin_Panels_Widgets_Layout" ) {
2723
+ // Special case of this being a layout widget, it needs a new ID
2724
+ cloneValues.builder_id = Math.random().toString( 36 ).substr( 2 );
2725
+ }
2726
+
2727
+ clone.set( 'values', cloneValues, {silent: true} );
2728
+ clone.set( 'collection', cell.widgets, {silent: true} );
2729
+ clone.cell = cell;
2730
+
2731
+ // This is used to force a form reload later on
2732
+ clone.isDuplicate = true;
2733
+
2734
+ return clone;
2735
+ },
2736
+
2737
+ /**
2738
+ * Gets the value that makes most sense as the title.
2739
+ */
2740
+ getTitle: function () {
2741
+ var widgetData = panelsOptions.widgets[this.get( 'class' )];
2742
+
2743
+ if ( _.isUndefined( widgetData ) ) {
2744
+ return this.get( 'class' ).replace( /_/g, ' ' );
2745
+ }
2746
+ else if ( ! _.isUndefined( widgetData.panels_title ) ) {
2747
+ // This means that the widget has told us which field it wants us to use as a title
2748
+ if ( widgetData.panels_title === false ) {
2749
+ return panelsOptions.widgets[this.get( 'class' )].description;
2750
+ }
2751
+ }
2752
+
2753
+ var values = this.get( 'values' );
2754
+
2755
+ // Create a list of fields to check for a title
2756
+ var titleFields = ['title', 'text'];
2757
+
2758
+ for ( var k in values ) {
2759
+ if ( values.hasOwnProperty( k ) ) {
2760
+ titleFields.push( k );
2761
+ }
2762
+ }
2763
+
2764
+ titleFields = _.uniq( titleFields );
2765
+
2766
+ for ( var i in titleFields ) {
2767
+ if (
2768
+ ! _.isUndefined( values[titleFields[i]] ) &&
2769
+ _.isString( values[titleFields[i]] ) &&
2770
+ values[titleFields[i]] !== '' &&
2771
+ values[titleFields[i]] !== 'on' &&
2772
+ titleFields[i][0] !== '_' && ! jQuery.isNumeric( values[titleFields[i]] )
2773
+ ) {
2774
+ var title = values[titleFields[i]];
2775
+ title = title.replace( /<\/?[^>]+(>|$)/g, "" );
2776
+ var parts = title.split( " " );
2777
+ parts = parts.slice( 0, 20 );
2778
+ return parts.join( ' ' );
2779
+ }
2780
+ }
2781
+
2782
+ // If we still have nothing, then just return the widget description
2783
+ return this.getWidgetField( 'description' );
2784
+ }
2785
+
2786
+ } );
2787
+
2788
+ },{}],18:[function(require,module,exports){
2789
+ var panels = window.panels, $ = jQuery;
2790
+
2791
+ module.exports = Backbone.View.extend( {
2792
+ wrapperTemplate: _.template( $( '#siteorigin-panels-context-menu' ).html().panelsProcessTemplate() ),
2793
+ sectionTemplate: _.template( $( '#siteorigin-panels-context-menu-section' ).html().panelsProcessTemplate() ),
2794
+
2795
+ contexts: [],
2796
+ active: false,
2797
+
2798
+ events: {
2799
+ 'keyup .so-search-wrapper input': 'searchKeyUp'
2800
+ },
2801
+
2802
+ /**
2803
+ * Intialize the context menu
2804
+ */
2805
+ initialize: function () {
2806
+ this.listenContextMenu();
2807
+ this.render();
2808
+ this.attach();
2809
+ },
2810
+
2811
+ /**
2812
+ * Listen for the right click context menu
2813
+ */
2814
+ listenContextMenu: function () {
2815
+ var thisView = this;
2816
+
2817
+ $( window ).on( 'contextmenu', function ( e ) {
2818
+ if ( thisView.active && ! thisView.isOverEl( thisView.$el, e ) ) {
2819
+ thisView.closeMenu();
2820
+ thisView.active = false;
2821
+ e.preventDefault();
2822
+ return false;
2823
+ }
2824
+
2825
+ if ( thisView.active ) {
2826
+ // Lets not double up on the context menu
2827
+ return true;
2828
+ }
2829
+
2830
+ // Other components should listen to activate_context
2831
+ thisView.active = false;
2832
+ thisView.trigger( 'activate_context', e, thisView );
2833
+
2834
+ if ( thisView.active ) {
2835
+ // We don't want the default event to happen.
2836
+ e.preventDefault();
2837
+
2838
+ thisView.openMenu( {
2839
+ left: e.pageX,
2840
+ top: e.pageY
2841
+ } );
2842
+ }
2843
+ } );
2844
+ },
2845
+
2846
+ render: function () {
2847
+ this.setElement( this.wrapperTemplate() );
2848
+ },
2849
+
2850
+ attach: function () {
2851
+ this.$el.appendTo( 'body' );
2852
+ },
2853
+
2854
+ /**
2855
+ * Display the actual context menu.
2856
+ *
2857
+ * @param position
2858
+ */
2859
+ openMenu: function ( position ) {
2860
+ this.trigger( 'open_menu' );
2861
+
2862
+ // Start listening for situations when we should close the menu
2863
+ $( window ).on( 'keyup', {menu: this}, this.keyboardListen );
2864
+ $( window ).on( 'click', {menu: this}, this.clickOutsideListen );
2865
+
2866
+ // Set the maximum height of the menu
2867
+ this.$el.css( 'max-height', $( window ).height() - 20 );
2868
+
2869
+ // Correct the left position
2870
+ if ( position.left + this.$el.outerWidth() + 10 >= $( window ).width() ) {
2871
+ position.left = $( window ).width() - this.$el.outerWidth() - 10;
2872
+ }
2873
+ if ( position.left <= 0 ) {
2874
+ position.left = 10;
2875
+ }
2876
+
2877
+ // Check top position
2878
+ if ( position.top + this.$el.outerHeight() - $( window ).scrollTop() + 10 >= $( window ).height() ) {
2879
+ position.top = $( window ).height() + $( window ).scrollTop() - this.$el.outerHeight() - 10;
2880
+ }
2881
+ if ( position.left <= 0 ) {
2882
+ position.left = 10;
2883
+ }
2884
+
2885
+ // position the contextual menu
2886
+ this.$el.css( {
2887
+ left: position.left + 1,
2888
+ top: position.top + 1
2889
+ } ).show();
2890
+ this.$( '.so-search-wrapper input' ).focus();
2891
+ },
2892
+
2893
+ closeMenu: function () {
2894
+ this.trigger( 'close_menu' );
2895
+
2896
+ // Stop listening for situations when we should close the menu
2897
+ $( window ).off( 'keyup', this.keyboardListen );
2898
+ $( window ).off( 'click', this.clickOutsideListen );
2899
+
2900
+ this.active = false;
2901
+ this.$el.empty().hide();
2902
+ },
2903
+
2904
+ /**
2905
+ * Keyboard events handler
2906
+ */
2907
+ keyboardListen: function ( e ) {
2908
+ var menu = e.data.menu;
2909
+
2910
+ switch ( e.which ) {
2911
+ case 27:
2912
+ menu.closeMenu();
2913
+ break;
2914
+ }
2915
+ },
2916
+
2917
+ /**
2918
+ * Listen for a click outside the menu to close it.
2919
+ * @param e
2920
+ */
2921
+ clickOutsideListen: function ( e ) {
2922
+ var menu = e.data.menu;
2923
+ if ( e.which !== 3 && menu.$el.is( ':visible' ) && ! menu.isOverEl( menu.$el, e ) ) {
2924
+ menu.closeMenu();
2925
+ }
2926
+ },
2927
+
2928
+ /**
2929
+ * Add a new section to the contextual menu.
2930
+ *
2931
+ * @param settings
2932
+ * @param items
2933
+ * @param callback
2934
+ */
2935
+ addSection: function ( settings, items, callback ) {
2936
+ var thisView = this;
2937
+ settings = _.extend( {
2938
+ display: 5,
2939
+ defaultDisplay: false,
2940
+ search: true,
2941
+
2942
+ // All the labels
2943
+ sectionTitle: '',
2944
+ searchPlaceholder: '',
2945
+
2946
+ // This is the key to be used in items for the title. Makes it easier to list objects
2947
+ titleKey: 'title'
2948
+ }, settings );
2949
+
2950
+ // Create the new section
2951
+ var section = $( this.sectionTemplate( {
2952
+ settings: settings,
2953
+ items: items
2954
+ } ) );
2955
+ this.$el.append( section );
2956
+
2957
+ section.find( '.so-item:not(.so-confirm)' ).click( function () {
2958
+ var $$ = $( this );
2959
+ callback( $$.data( 'key' ) );
2960
+ thisView.closeMenu();
2961
+ } );
2962
+
2963
+ section.find( '.so-item.so-confirm' ).click( function () {
2964
+ var $$ = $( this );
2965
+
2966
+ if ( $$.hasClass( 'so-confirming' ) ) {
2967
+ callback( $$.data( 'key' ) );
2968
+ thisView.closeMenu();
2969
+ return;
2970
+ }
2971
+
2972
+ $$
2973
+ .data( 'original-text', $$.html() )
2974
+ .addClass( 'so-confirming' )
2975
+ .html( '<span class="dashicons dashicons-yes"></span> ' + panelsOptions.loc.dropdown_confirm );
2976
+
2977
+ setTimeout( function () {
2978
+ $$.removeClass( 'so-confirming' );
2979
+ $$.html( $$.data( 'original-text' ) );
2980
+ }, 2500 );
2981
+ } );
2982
+
2983
+ section.data( 'settings', settings ).find( '.so-search-wrapper input' ).trigger( 'keyup' );
2984
+
2985
+ this.active = true;
2986
+ },
2987
+
2988
+ /**
2989
+ * Handle searching inside a section.
2990
+ *
2991
+ * @param e
2992
+ * @returns {boolean}
2993
+ */
2994
+ searchKeyUp: function ( e ) {
2995
+ var
2996
+ $$ = $( e.currentTarget ),
2997
+ section = $$.closest( '.so-section' ),
2998
+ settings = section.data( 'settings' );
2999
+
3000
+ if ( e.which === 38 || e.which === 40 ) {
3001
+ // First, lets check if this is an up, down or enter press
3002
+ var
3003
+ items = section.find( 'ul li:visible' ),
3004
+ activeItem = items.filter( '.so-active' ).eq( 0 );
3005
+
3006
+ if ( activeItem.length ) {
3007
+ items.removeClass( 'so-active' );
3008
+
3009
+ var activeIndex = items.index( activeItem );
3010
+
3011
+ if ( e.which === 38 ) {
3012
+ if ( activeIndex - 1 < 0 ) {
3013
+ activeItem = items.last();
3014
+ } else {
3015
+ activeItem = items.eq( activeIndex - 1 );
3016
+ }
3017
+ }
3018
+ else if ( e.which === 40 ) {
3019
+ if ( activeIndex + 1 >= items.length ) {
3020
+ activeItem = items.first();
3021
+ } else {
3022
+ activeItem = items.eq( activeIndex + 1 );
3023
+ }
3024
+ }
3025
+ }
3026
+ else if ( e.which === 38 ) {
3027
+ activeItem = items.last();
3028
+ }
3029
+ else if ( e.which === 40 ) {
3030
+ activeItem = items.first();
3031
+ }
3032
+
3033
+ activeItem.addClass( 'so-active' );
3034
+ return false;
3035
+ }
3036
+ if ( e.which === 13 ) {
3037
+ if ( section.find( 'ul li:visible' ).length === 1 ) {
3038
+ // We'll treat a single visible item as active when enter is clicked
3039
+ section.find( 'ul li:visible' ).trigger( 'click' );
3040
+ return false;
3041
+ }
3042
+ section.find( 'ul li.so-active:visible' ).trigger( 'click' );
3043
+ return false;
3044
+ }
3045
+
3046
+ if ( $$.val() === '' ) {
3047
+ // We'll display the defaultDisplay items
3048
+ if ( settings.defaultDisplay ) {
3049
+ section.find( '.so-item' ).hide();
3050
+ for ( var i = 0; i < settings.defaultDisplay.length; i ++ ) {
3051
+ section.find( '.so-item[data-key="' + settings.defaultDisplay[i] + '"]' ).show();
3052
+ }
3053
+ } else {
3054
+ // We'll just display all the items
3055
+ section.find( '.so-item' ).show();
3056
+ }
3057
+ } else {
3058
+ section.find( '.so-item' ).hide().each( function () {
3059
+ var item = $( this );
3060
+ if ( item.html().toLowerCase().indexOf( $$.val().toLowerCase() ) !== - 1 ) {
3061
+ item.show();
3062
+ }
3063
+ } );
3064
+ }
3065
+
3066
+ // Now, we'll only show the first settings.display visible items
3067
+ section.find( '.so-item:visible:gt(' + (
3068
+ settings.display - 1
3069
+ ) + ')' ).hide();
3070
+
3071
+
3072
+ if ( section.find( '.so-item:visible' ).length === 0 && $$.val() !== '' ) {
3073
+ section.find( '.so-no-results' ).show();
3074
+ } else {
3075
+ section.find( '.so-no-results' ).hide();
3076
+ }
3077
+ },
3078
+
3079
+ /**
3080
+ * Check if the given mouse event is over the element
3081
+ * @param el
3082
+ * @param event
3083
+ */
3084
+ isOverEl: function ( el, event ) {
3085
+ var elPos = [
3086
+ [el.offset().left, el.offset().top],
3087
+ [el.offset().left + el.outerWidth(), el.offset().top + el.outerHeight()]
3088
+ ];
3089
+
3090
+ // Return if this event is over the given element
3091
+ return (
3092
+ event.pageX >= elPos[0][0] && event.pageX <= elPos[1][0] &&
3093
+ event.pageY >= elPos[0][1] && event.pageY <= elPos[1][1]
3094
+ );
3095
+ }
3096
+
3097
+ } );
3098
+
3099
+ },{}],19:[function(require,module,exports){
3100
+ var panels = window.panels, $ = jQuery;
3101
+
3102
+ module.exports = Backbone.View.extend( {
3103
+
3104
+ // Config options
3105
+ editorType: null,
3106
+ postId: null,
3107
+ editorId: null,
3108
+
3109
+ template: _.template( $( '#siteorigin-panels-builder' ).html().panelsProcessTemplate() ),
3110
+ dialogs: {},
3111
+ rowsSortable: null,
3112
+ dataField: false,
3113
+ currentData: '',
3114
+
3115
+ attachedToEditor: false,
3116
+ liveEditor: undefined,
3117
+ menu: false,
3118
+
3119
+ /* The builderType is sent with all requests to the server */
3120
+ builderType: '',
3121
+
3122
+ events: {
3123
+ 'click .so-tool-button.so-widget-add': 'displayAddWidgetDialog',
3124
+ 'click .so-tool-button.so-row-add': 'displayAddRowDialog',
3125
+ 'click .so-tool-button.so-prebuilt-add': 'displayAddPrebuiltDialog',
3126
+ 'click .so-tool-button.so-history': 'displayHistoryDialog',
3127
+ 'click .so-tool-button.so-live-editor': 'displayLiveEditor'
3128
+ },
3129
+
3130
+ /* A row collection */
3131
+ rows: null,
3132
+
3133
+ /**
3134
+ * Initialize the builder
3135
+ */
3136
+ initialize: function ( options ) {
3137
+ var builder = this;
3138
+
3139
+ if ( ! _.isUndefined( options.config ) ) {
3140
+ this.editorType = options.config.editorType;
3141
+ this.editorId = options.config.editorId;
3142
+ this.builderType = options.config.builderType;
3143
+ this.postId = options.config.postId;
3144
+ }
3145
+
3146
+ // Now lets create all the dialog boxes that the main builder interface uses
3147
+ this.dialogs = {
3148
+ widgets: new panels.dialog.widgets(),
3149
+ row: new panels.dialog.row(),
3150
+ prebuilt: new panels.dialog.prebuilt()
3151
+ };
3152
+
3153
+ // Set the builder for each dialog and render it.
3154
+ _.each( this.dialogs, function ( p, i, d ) {
3155
+ d[i].setBuilder( builder );
3156
+ } );
3157
+
3158
+ this.dialogs.row.setRowDialogType( 'create' );
3159
+
3160
+ // This handles a new row being added to the collection - we'll display it in the interface
3161
+ this.model.rows.on( 'add', this.onAddRow, this );
3162
+
3163
+ // Reflow the entire builder when ever the
3164
+ $( window ).resize( function ( e ) {
3165
+ if ( e.target === window ) {
3166
+ builder.trigger( 'builder_resize' );
3167
+ }
3168
+ } );
3169
+
3170
+ // When the data changes in the model, store it in the field
3171
+ this.model.on( 'change:data load_panels_data', this.storeModelData, this );
3172
+
3173
+ // Handle a content change
3174
+ this.on( 'content_change', this.handleContentChange, this );
3175
+ this.on( 'display_builder', this.handleDisplayBuilder, this );
3176
+ this.on( 'builder_rendered builder_resize', this.handleBuilderSizing, this );
3177
+ this.model.on( 'change:data load_panels_data', this.toggleWelcomeDisplay, this );
3178
+
3179
+ // Create the context menu for this builder
3180
+ this.menu = new panels.utils.menu( {} );
3181
+ this.menu.on( 'activate_context', this.activateContextMenu, this );
3182
+
3183
+ return this;
3184
+ },
3185
+
3186
+ /**
3187
+ * Render the builder interface.
3188
+ *
3189
+ * @return {panels.view.builder}
3190
+ */
3191
+ render: function () {
3192
+ // this.$el.html( this.template() );
3193
+ this.setElement( this.template() );
3194
+ this.$el
3195
+ .attr( 'id', 'siteorigin-panels-builder-' + this.cid )
3196
+ .addClass( 'so-builder-container' );
3197
+
3198
+ this.trigger( 'builder_rendered' );
3199
+
3200
+ return this;
3201
+ },
3202
+
3203
+ /**
3204
+ * Attach the builder to the given container
3205
+ *
3206
+ * @param container
3207
+ * @returns {panels.view.builder}
3208
+ */
3209
+ attach: function ( options ) {
3210
+
3211
+ options = _.extend( {
3212
+ type: '',
3213
+ container: false,
3214
+ dialog: false
3215
+ }, options );
3216
+
3217
+ if ( options.dialog ) {
3218
+ // We're going to add this to a dialog
3219
+ this.dialog = new panels.dialog.builder();
3220
+ this.dialog.builder = this;
3221
+ } else {
3222
+ // Attach this in the standard way
3223
+ this.$el.appendTo( options.container );
3224
+ this.metabox = options.container.closest( '.postbox' );
3225
+ this.initSortable();
3226
+ this.trigger( 'attached_to_container', options.container );
3227
+ }
3228
+
3229
+ // Store the builder type
3230
+ this.builderType = options.type;
3231
+
3232
+ return this;
3233
+ },
3234
+
3235
+ /**
3236
+ * This will move the Page Builder meta box into the editor if we're in the post/page edit interface.
3237
+ *
3238
+ * @returns {panels.view.builder}
3239
+ */
3240
+ attachToEditor: function () {
3241
+ if ( this.editorType !== 'tinymce' ) {
3242
+ return this;
3243
+ }
3244
+
3245
+ this.attachedToEditor = true;
3246
+ var metabox = this.metabox;
3247
+ var thisView = this;
3248
+
3249
+ // Handle switching between the page builder and other tabs
3250
+ $( '#wp-content-wrap .wp-editor-tabs' )
3251
+ .find( '.wp-switch-editor' )
3252
+ .click( function ( e ) {
3253
+ e.preventDefault();
3254
+ $( '#wp-content-editor-container, #post-status-info' ).show();
3255
+ // metabox.hide();
3256
+ $( '#wp-content-wrap' ).removeClass( 'panels-active' );
3257
+ $( '#content-resize-handle' ).show();
3258
+ thisView.trigger( 'hide_builder' );
3259
+ } ).end()
3260
+ .append(
3261
+ $( '<a id="content-panels" class="hide-if-no-js wp-switch-editor switch-panels">' + metabox.find( '.hndle span' ).html() + '</a>' )
3262
+ .click( function ( e ) {
3263
+ // Switch to the Page Builder interface
3264
+ e.preventDefault();
3265
+
3266
+ var $$ = jQuery( this );
3267
+
3268
+ // Hide the standard content editor
3269
+ $( '#wp-content-wrap, #post-status-info' ).hide();
3270
+
3271
+ // Show page builder and the inside div
3272
+ metabox.show().find( '> .inside' ).show();
3273
+
3274
+ // Triggers full refresh
3275
+ $( window ).resize();
3276
+ $( document ).scroll();
3277
+
3278
+ thisView.trigger( 'display_builder' );
3279
+
3280
+ } )
3281
+ );
3282
+
3283
+ // Switch back to the standard editor
3284
+ metabox.find( '.so-switch-to-standard' ).click( function ( e ) {
3285
+ e.preventDefault();
3286
+
3287
+ if ( ! confirm( panelsOptions.loc.confirm_stop_builder ) ) {
3288
+ return;
3289
+ }
3290
+
3291
+ // User is switching to the standard visual editor
3292
+ thisView.addHistoryEntry( 'back_to_editor' );
3293
+ thisView.model.loadPanelsData( false );
3294
+
3295
+ // Switch back to the standard editor
3296
+ $( '#wp-content-wrap, #post-status-info' ).show();
3297
+ metabox.hide();
3298
+
3299
+ // Resize to trigger reflow of WordPress editor stuff
3300
+ $( window ).resize();
3301
+ } ).show();
3302
+
3303
+ // Move the panels box into a tab of the content editor
3304
+ metabox.insertAfter( '#wp-content-wrap' ).hide().addClass( 'attached-to-editor' );
3305
+
3306
+ // Switch to the Page Builder interface as soon as we load the page if there are widgets
3307
+ var data = this.model.get( 'data' );
3308
+ if ( (
3309
+ ! _.isEmpty( data.widgets )
3310
+ ) || (
3311
+ ! _.isEmpty( data.grids )
3312
+ ) ) {
3313
+ $( '#content-panels.switch-panels' ).click();
3314
+ }
3315
+
3316
+ // We will also make this sticky if its attached to an editor.
3317
+ var stickToolbar = function () {
3318
+ var toolbar = thisView.$( '.so-builder-toolbar' );
3319
+
3320
+ if ( thisView.$el.hasClass( 'so-display-narrow' ) ) {
3321
+ // In this case, we don't want to stick the toolbar.
3322
+ toolbar.css( {
3323
+ top: 0,
3324
+ left: 0,
3325
+ width: '100%',
3326
+ position: 'absolute'
3327
+ } );
3328
+ thisView.$el.css( 'padding-top', toolbar.outerHeight() );
3329
+ return;
3330
+ }
3331
+
3332
+ var newTop = $( window ).scrollTop() - thisView.$el.offset().top;
3333
+
3334
+ if ( $( '#wpadminbar' ).css( 'position' ) === 'fixed' ) {
3335
+ newTop += $( '#wpadminbar' ).outerHeight();
3336
+ }
3337
+
3338
+ var limits = {
3339
+ top: 0,
3340
+ bottom: thisView.$el.outerHeight() - toolbar.outerHeight() + 20
3341
+ };
3342
+
3343
+ if ( newTop > limits.top && newTop < limits.bottom ) {
3344
+ if ( toolbar.css( 'position' ) !== 'fixed' ) {
3345
+ // The toolbar needs to stick to the top, over the interface
3346
+ toolbar.css( {
3347
+ top: $( '#wpadminbar' ).outerHeight(),
3348
+ left: thisView.$el.offset().left,
3349
+ width: thisView.$el.outerWidth(),
3350
+ position: 'fixed'
3351
+ } );
3352
+ }
3353
+ } else {
3354
+ // The toolbar needs to be at the top or bottom of the interface
3355
+ toolbar.css( {
3356
+ top: Math.min( Math.max( newTop, 0 ), thisView.$el.outerHeight() - toolbar.outerHeight() + 20 ),
3357
+ left: 0,
3358
+ width: '100%',
3359
+ position: 'absolute'
3360
+ } );
3361
+ }
3362
+
3363
+ thisView.$el.css( 'padding-top', toolbar.outerHeight() );
3364
+ };
3365
+
3366
+ this.on( 'builder_resize', stickToolbar, this );
3367
+ $( document ).scroll( stickToolbar );
3368
+ stickToolbar();
3369
+
3370
+ return this;
3371
+ },
3372
+
3373
+ /**
3374
+ * Initialize the row sortables
3375
+ */
3376
+ initSortable: function () {
3377
+ // Create the sortable for the rows
3378
+ var $el = this.$el;
3379
+ var builderView = this;
3380
+
3381
+ this.rowsSortable = this.$( '.so-rows-container' ).sortable( {
3382
+ appendTo: '#wpwrap',
3383
+ items: '.so-row-container',
3384
+ handle: '.so-row-move',
3385
+ axis: 'y',
3386
+ tolerance: 'pointer',
3387
+ scroll: false,
3388
+ stop: function ( e ) {
3389
+ builderView.addHistoryEntry( 'row_moved' );
3390
+
3391
+ // Sort the rows collection after updating all the indexes.
3392
+ builderView.sortCollections();
3393
+ }
3394
+ } );
3395
+ },
3396
+
3397
+ /**
3398
+ * Refresh the row sortable
3399
+ */
3400
+ refreshSortable: function () {
3401
+ // Refresh the sortable to account for the new row
3402
+ if ( ! _.isNull( this.rowsSortable ) ) {
3403
+ this.rowsSortable.sortable( 'refresh' );
3404
+ }
3405
+ },
3406
+
3407
+ /**
3408
+ * Set the field that's used to store the data
3409
+ * @param field
3410
+ */
3411
+ setDataField: function ( field, options ) {
3412
+ options = _.extend( {
3413
+ load: true
3414
+ }, options );
3415
+
3416
+ this.dataField = field;
3417
+ this.dataField.data( 'builder', this );
3418
+
3419
+ if ( options.load && field.val() !== '' ) {
3420
+ var data = this.dataField.val();
3421
+ try {
3422
+ data = JSON.parse( data );
3423
+ }
3424
+ catch ( err ) {
3425
+ data = {};
3426
+ }
3427
+
3428
+ this.model.loadPanelsData( data );
3429
+ this.currentData = data;
3430
+ this.toggleWelcomeDisplay();
3431
+ this.sortCollections();
3432
+ }
3433
+
3434
+ return this;
3435
+ },
3436
+
3437
+ /**
3438
+ * Store the model data in the data html field set in this.setDataField.
3439
+ */
3440
+ storeModelData: function () {
3441
+ var data = JSON.stringify( this.model.get( 'data' ) );
3442
+
3443
+ if ( $( this.dataField ).val() !== data ) {
3444
+ // If the data is different, set it and trigger a content_change event
3445
+ $( this.dataField ).val( data );
3446
+ $( this.dataField ).trigger( 'change' );
3447
+ this.trigger( 'content_change' );
3448
+ }
3449
+ },
3450
+
3451
+ /**
3452
+ * HAndle the visual side of adding a new row to the builder.
3453
+ *
3454
+ * @param row
3455
+ * @param collection
3456
+ * @param options
3457
+ */
3458
+ onAddRow: function ( row, collection, options ) {
3459
+ options = _.extend( {noAnimate: false}, options );
3460
+ // Create a view for the row
3461
+ var rowView = new panels.view.row( {model: row} );
3462
+ rowView.builder = this;
3463
+ rowView.render();
3464
+
3465
+ // Attach the row elements to this builder
3466
+ if ( _.isUndefined( options.at ) || collection.length <= 1 ) {
3467
+ // Insert this at the end of the widgets container
3468
+ rowView.$el.appendTo( this.$( '.so-rows-container' ) );
3469
+ } else {
3470
+ // We need to insert this at a specific position
3471
+ rowView.$el.insertAfter(
3472
+ this.$( '.so-rows-container .so-row-container' ).eq( options.at - 1 )
3473
+ );
3474
+ }
3475
+
3476
+ if ( options.noAnimate === false ) {
3477
+ rowView.visualCreate();
3478
+ }
3479
+
3480
+ this.refreshSortable();
3481
+ rowView.resize();
3482
+ },
3483
+
3484
+ /**
3485
+ * Display the dialog to add a new widget.
3486
+ *
3487
+ * @returns {boolean}
3488
+ */
3489
+ displayAddWidgetDialog: function () {
3490
+ this.dialogs.widgets.openDialog();
3491
+ },
3492
+
3493
+ /**
3494
+ * Display the dialog to add a new row.
3495
+ *
3496
+ * @returns {boolean}
3497
+ */
3498
+ displayAddRowDialog: function () {
3499
+ this.dialogs.row.openDialog();
3500
+ this.dialogs.row.setRowModel(); // Set this to an empty row model
3501
+ },
3502
+
3503
+ /**
3504
+ * Display the dialog to add prebuilt layouts.
3505
+ *
3506
+ * @returns {boolean}
3507
+ */
3508
+ displayAddPrebuiltDialog: function () {
3509
+ this.dialogs.prebuilt.openDialog();
3510
+ },
3511
+
3512
+ /**
3513
+ * Display the history dialog.
3514
+ *
3515
+ * @returns {boolean}
3516
+ */
3517
+ displayHistoryDialog: function () {
3518
+ this.dialogs.history.openDialog();
3519
+ },
3520
+
3521
+ /**
3522
+ * Get the model for the currently selected cell
3523
+ */
3524
+ getActiveCell: function ( options ) {
3525
+ options = _.extend( {
3526
+ createCell: true,
3527
+ defaultPosition: 'first'
3528
+ }, options );
3529
+
3530
+ if ( this.$( '.so-cells .cell' ).length === 0 ) {
3531
+
3532
+ if ( options.createCell ) {
3533
+ // Create a row with a single cell
3534
+ this.model.addRow( [1], {noAnimate: true} );
3535
+ } else {
3536
+ return null;
3537
+ }
3538
+
3539
+ }
3540
+
3541
+ var activeCell = this.$( '.so-cells .cell.cell-selected' );
3542
+
3543
+ if ( activeCell.length === 0 ) {
3544
+ if ( options.defaultPosition === 'last' ) {
3545
+ activeCell = this.$( '.so-cells .cell' ).first();
3546
+ } else {
3547
+ activeCell = this.$( '.so-cells .cell' ).last();
3548
+ }
3549
+ }
3550
+
3551
+ return activeCell.data( 'view' ).model;
3552
+ },
3553
+
3554
+ /**
3555
+ * Sort all widget and row collections based on their dom position
3556
+ */
3557
+ sortCollections: function () {
3558
+
3559
+ // Give the widgets their indexes
3560
+ this.$( '.so-widget' ).each( function ( i ) {
3561
+ var $$ = $( this );
3562
+ $$.data( 'view' ).model.indexes = {
3563
+ builder: i,
3564
+ cell: $$.index()
3565
+ };
3566
+ } );
3567
+
3568
+ // Give the cells their indexes
3569
+ this.$( '.so-cells .cell' ).each( function ( i ) {
3570
+ var $$ = $( this );
3571
+ $$.data( 'view' ).model.indexes = {
3572
+ builder: i,
3573
+ row: $$.index()
3574
+ };
3575
+ } );
3576
+
3577
+ // Give the rows their indexes
3578
+ this.$( '.so-row-container' ).each( function ( i ) {
3579
+ var $$ = $( this );
3580
+ $$.data( 'view' ).model.indexes = {
3581
+ builder: i,
3582
+ };
3583
+ } );
3584
+
3585
+
3586
+ // Sort the rows by their visual index
3587
+ this.model.rows.sort();
3588
+
3589
+ // Sort the widget collections by their visual index
3590
+ this.model.rows.each( function ( row ) {
3591
+ row.cells.each( function ( cell ) {
3592
+ cell.widgets.sort();
3593
+ } );
3594
+ } );
3595
+
3596
+ // Update the builder model to reflect the newly ordered data.
3597
+ this.model.refreshPanelsData();
3598
+ },
3599
+
3600
+ /**
3601
+ * Add a live editor
3602
+ *
3603
+ * @returns {panels.view.builder}
3604
+ */
3605
+ addLiveEditor: function ( postId ) {
3606
+ // Create the live editor and set the builder to this.
3607
+ this.liveEditor = new panels.view.liveEditor( {builder: this} );
3608
+ this.liveEditor.setPostId( postId );
3609
+
3610
+ // Display the live editor button in the toolbar
3611
+ if ( this.liveEditor.hasPreviewUrl() ) {
3612
+ this.$( '.so-builder-toolbar .so-live-editor' ).show();
3613
+ }
3614
+
3615
+ return this;
3616
+ },
3617
+
3618
+ /**
3619
+ * Show the current live editor
3620
+ */
3621
+ displayLiveEditor: function () {
3622
+ if ( _.isUndefined( this.liveEditor ) ) {
3623
+ return;
3624
+ }
3625
+
3626
+ this.liveEditor.open();
3627
+ },
3628
+
3629
+ /**
3630
+ * Add the history browser.
3631
+ *
3632
+ * @return {panels.view.builder}
3633
+ */
3634
+ addHistoryBrowser: function () {
3635
+ this.dialogs.history = new panels.dialog.history();
3636
+ this.dialogs.history.builder = this;
3637
+ this.dialogs.history.entries.builder = this.model;
3638
+
3639
+ // Set the revert entry
3640
+ this.dialogs.history.setRevertEntry( this.model );
3641
+
3642
+ // Display the live editor button in the toolbar
3643
+ this.$( '.so-builder-toolbar .so-history' ).show();
3644
+ },
3645
+
3646
+ /**
3647
+ * Add an entry.
3648
+ *
3649
+ * @param text
3650
+ * @param data
3651
+ */
3652
+ addHistoryEntry: function ( text, data ) {
3653
+ if ( _.isUndefined( data ) ) {
3654
+ data = null;
3655
+ }
3656
+
3657
+ if ( ! _.isUndefined( this.dialogs.history ) ) {
3658
+ this.dialogs.history.entries.addEntry( text, data );
3659
+ }
3660
+ },
3661
+
3662
+ /**
3663
+ * Handle a change of the content
3664
+ */
3665
+ handleContentChange: function () {
3666
+
3667
+ // Make sure we actually need to copy content.
3668
+ if ( panelsOptions.copy_content && this.attachedToEditor && this.$el.is( ':visible' ) ) {
3669
+
3670
+ // We're going to create a copy of page builder content into the post content
3671
+ $.post(
3672
+ panelsOptions.ajaxurl,
3673
+ {
3674
+ action: 'so_panels_builder_content',
3675
+ panels_data: JSON.stringify( this.model.getPanelsData() ),
3676
+ post_id: this.postId
3677
+ },
3678
+ function ( content ) {
3679
+
3680
+ // Strip all the known layout divs
3681
+ var t = $( '<div />' ).html( content );
3682
+ t.find( 'div' ).each( function () {
3683
+ var c = $( this ).contents();
3684
+ $( this ).replaceWith( c );
3685
+ } );
3686
+
3687
+ content = t.html()
3688
+ .replace( /[\r\n]+/g, "\n" )
3689
+ .replace( /\n\s+/g, "\n" )
3690
+ .trim();
3691
+
3692
+ this.updateEditorContent( content );
3693
+ }.bind( this )
3694
+ );
3695
+ }
3696
+ },
3697
+
3698
+ /**
3699
+ * Update editor content with the given content.
3700
+ *
3701
+ * @param content
3702
+ */
3703
+ updateEditorContent: function ( content ) {
3704
+ // Switch back to the standard editor
3705
+ if ( this.editorType !== 'tinymce' || _.isUndefined( tinyMCE ) || _.isNull( tinyMCE.get( "content" ) ) ) {
3706
+ var $editor = $( this.editorId );
3707
+ $editor.val( content ).trigger( 'change' ).trigger( 'keyup' );
3708
+ } else {
3709
+ var contentEd = tinyMCE.get( "content" );
3710
+
3711
+ contentEd.setContent( content );
3712
+
3713
+ contentEd.fire( 'change' );
3714
+ contentEd.fire( 'keyup' );
3715
+ }
3716
+
3717
+ this.triggerYoastSeoChange();
3718
+ },
3719
+
3720
+ /**
3721
+ * Trigger a change on Yoast SEO
3722
+ */
3723
+ triggerYoastSeoChange: function () {
3724
+ if ( $( '#yoast_wpseo_focuskw_text_input' ).length ) {
3725
+ var element = document.getElementById( 'yoast_wpseo_focuskw_text_input' ), event;
3726
+
3727
+ if ( document.createEvent ) {
3728
+ event = document.createEvent( "HTMLEvents" );
3729
+ event.initEvent( "keyup", true, true );
3730
+ } else {
3731
+ event = document.createEventObject();
3732
+ event.eventType = "keyup";
3733
+ }
3734
+
3735
+ event.eventName = "keyup";
3736
+
3737
+ if ( document.createEvent ) {
3738
+ element.dispatchEvent( event );
3739
+ } else {
3740
+ element.fireEvent( "on" + event.eventType, event );
3741
+ }
3742
+ }
3743
+ },
3744
+
3745
+ /**
3746
+ * Handle displaying the builder
3747
+ */
3748
+ handleDisplayBuilder: function () {
3749
+ var editorContent = '';
3750
+ var editor;
3751
+
3752
+ if ( ! _.isUndefined( tinyMCE ) ) {
3753
+ editor = tinyMCE.get( 'content' );
3754
+ }
3755
+ if ( editor && _.isFunction( editor.getContent ) ) {
3756
+ editorContent = editor.getContent();
3757
+ } else {
3758
+ editorContent = $( 'textarea#content' ).val();
3759
+ }
3760
+
3761
+ if ( _.isEmpty( this.model.get( 'data' ) ) && editorContent !== '' ) {
3762
+ // Confirm that the user wants to copy their content to Page Builder.
3763
+ if ( ! confirm( panelsOptions.loc.confirm_use_builder ) ) {
3764
+ return;
3765
+ }
3766
+
3767
+ var widgetClass = '';
3768
+ // There is a small chance a theme will have removed this, so check
3769
+ if ( ! _.isUndefined( panelsOptions.widgets.SiteOrigin_Widget_Editor_Widget ) ) {
3770
+ widgetClass = 'SiteOrigin_Widget_Editor_Widget';
3771
+ }
3772
+ else if ( ! _.isUndefined( panelsOptions.widgets.WP_Widget_Text ) ) {
3773
+ widgetClass = 'WP_Widget_Text';
3774
+ }
3775
+
3776
+ if ( widgetClass === '' ) {
3777
+ return;
3778
+ }
3779
+
3780
+ // Create the existing page content in a single widget
3781
+ this.model.loadPanelsData( {
3782
+ grid_cells: [{grid: 0, weight: 1}],
3783
+ grids: [{cells: 1}],
3784
+ widgets: [
3785
+ {
3786
+ filter: "1",
3787
+ text: editorContent,
3788
+ title: "",
3789
+ type: "visual",
3790
+ panels_info: {
3791
+ class: widgetClass,
3792
+ raw: false,
3793
+ grid: 0,
3794
+ cell: 0
3795
+ }
3796
+ }
3797
+ ]
3798
+ } );
3799
+ this.model.trigger( 'change' );
3800
+ this.model.trigger( 'change:data' );
3801
+ }
3802
+ },
3803
+
3804
+ handleBuilderSizing: function () {
3805
+ var width = this.$el.width();
3806
+
3807
+ if ( ! width ) {
3808
+ return this;
3809
+ }
3810
+
3811
+ if ( width < 480 ) {
3812
+ this.$el.addClass( 'so-display-narrow' );
3813
+ } else {
3814
+ this.$el.removeClass( 'so-display-narrow' );
3815
+ }
3816
+
3817
+ },
3818
+
3819
+ /**
3820
+ * Set the parent dialog for all the dialogs in this builder.
3821
+ *
3822
+ * @param text
3823
+ * @param dialog
3824
+ */
3825
+ setDialogParents: function ( text, dialog ) {
3826
+ _.each( this.dialogs, function ( p, i, d ) {
3827
+ d[i].setParent( text, dialog );
3828
+ } );
3829
+
3830
+ // For any future dialogs
3831
+ this.on( 'add_dialog', function ( newDialog ) {
3832
+ newDialog.setParent( text, dialog );
3833
+ }, this );
3834
+ },
3835
+
3836
+ /**
3837
+ * This shows or hides the welcome display depending on whether there are any rows in the collection.
3838
+ */
3839
+ toggleWelcomeDisplay: function () {
3840
+ if ( ! this.model.rows.isEmpty() ) {
3841
+ this.$( '.so-panels-welcome-message' ).hide();
3842
+ } else {
3843
+ this.$( '.so-panels-welcome-message' ).show();
3844
+ }
3845
+ },
3846
+
3847
+ activateContextMenu: function ( e, menu ) {
3848
+ var builder = this;
3849
+
3850
+ // Of all the visible builders, find the topmost
3851
+ var topmostBuilder = $( '.siteorigin-panels-builder:visible' )
3852
+ .sort( function ( a, b ) {
3853
+ return $( a ).zIndex() > $( b ).zIndex() ? 1 : - 1;
3854
+ } )
3855
+ .last();
3856
+
3857
+ // Only run this if its element is the topmost builder
3858
+ if ( builder.$el.is( topmostBuilder ) ) {
3859
+ // Get the element we're currently hovering over
3860
+ var over = $( [] )
3861
+ .add( builder.$( '.so-rows-container > .so-row-container' ) )
3862
+ .add( builder.$( '.so-cells > .cell' ) )
3863
+ .add( builder.$( '.cell-wrapper > .so-widget' ) )
3864
+ .filter( function ( i ) {
3865
+ return menu.isOverEl( $( this ), e );
3866
+ } );
3867
+
3868
+ var activeView = over.last().data( 'view' );
3869
+ if ( activeView !== undefined && activeView.buildContextualMenu !== undefined ) {
3870
+ // We'll pass this to the current active view so it can popular the contextual menu
3871
+ activeView.buildContextualMenu( e, menu );
3872
+ }
3873
+ }
3874
+ },
3875
+
3876
+ /**
3877
+ * Lock window scrolling for the main overlay
3878
+ */
3879
+ lockPageScroll: function () {
3880
+ if ( $( 'body' ).css( 'overflow' ) === 'hidden' ) {
3881
+ return;
3882
+ }
3883
+
3884
+ // lock scroll position, but retain settings for later
3885
+ var scrollPosition = [
3886
+ self.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
3887
+ self.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
3888
+ ];
3889
+
3890
+ $( 'body' )
3891
+ .data( {
3892
+ 'scroll-position': scrollPosition
3893
+ } )
3894
+ .css( 'overflow', 'hidden' );
3895
+ window.scrollTo( scrollPosition[0], scrollPosition[1] );
3896
+ },
3897
+
3898
+ /**
3899
+ * Unlock window scrolling
3900
+ */
3901
+ unlockPageScroll: function () {
3902
+ if ( $( 'body' ).css( 'overflow' ) !== 'hidden' ) {
3903
+ return;
3904
+ }
3905
+
3906
+ // Check that there are no more dialogs or a live editor
3907
+ if ( ! $( '.so-panels-dialog-wrapper' ).is( ':visible' ) && ! $( '.so-panels-live-editor' ).is( ':visible' ) ) {
3908
+ $( 'body' ).css( 'overflow', 'visible' );
3909
+ var scrollPosition = $( 'body' ).data( 'scroll-position' );
3910
+ window.scrollTo( scrollPosition[0], scrollPosition[1] );
3911
+ }
3912
+ }
3913
+
3914
+ } );
3915
+
3916
+ },{}],20:[function(require,module,exports){
3917
+ var panels = window.panels, $ = jQuery;
3918
+
3919
+ module.exports = Backbone.View.extend( {
3920
+ template: _.template( $( '#siteorigin-panels-builder-cell' ).html().panelsProcessTemplate() ),
3921
+ events: {
3922
+ 'click .cell-wrapper': 'handleCellClick'
3923
+ },
3924
+
3925
+ /* The row view that this cell is a part of */
3926
+ row: null,
3927
+ widgetSortable: null,
3928
+
3929
+ initialize: function () {
3930
+ this.model.widgets.on( 'add', this.onAddWidget, this );
3931
+ },
3932
+
3933
+ /**
3934
+ * Render the actual cell
3935
+ */
3936
+ render: function () {
3937
+ var templateArgs = {
3938
+ weight: this.model.get( 'weight' ),
3939
+ totalWeight: this.row.model.cells.totalWeight()
3940
+ };
3941
+
3942
+ this.setElement( this.template( templateArgs ) );
3943
+ this.$el.data( 'view', this );
3944
+
3945
+ // Now lets render any widgets that are currently in the row
3946
+ var thisView = this;
3947
+ this.model.widgets.each( function ( widget ) {
3948
+ var widgetView = new panels.view.widget( {model: widget} );
3949
+ widgetView.cell = thisView;
3950
+ widgetView.render();
3951
+
3952
+ widgetView.$el.appendTo( thisView.$( '.widgets-container' ) );
3953
+ } );
3954
+
3955
+ this.initSortable();
3956
+ this.initResizable();
3957
+
3958
+ return this;
3959
+ },
3960
+
3961
+ /**
3962
+ * Initialize the widget sortable
3963
+ */
3964
+ initSortable: function () {
3965
+ var cellView = this;
3966
+
3967
+ // Go up the view hierarchy until we find the ID attribute
3968
+ var builderID = cellView.row.builder.$el.attr( 'id' );
3969
+
3970
+ // Create a widget sortable that's connected with all other cells
3971
+ this.widgetSortable = this.$( '.widgets-container' ).sortable( {
3972
+ placeholder: "so-widget-sortable-highlight",
3973
+ connectWith: '#' + builderID + ' .so-cells .cell .widgets-container',
3974
+ tolerance: 'pointer',
3975
+ scroll: false,
3976
+ over: function ( e, ui ) {
3977
+ // This will make all the rows in the current builder resize
3978
+ cellView.row.builder.trigger( 'widget_sortable_move' );
3979
+ },
3980
+ stop: function ( e, ui ) {
3981
+ cellView.row.builder.addHistoryEntry( 'widget_moved' );
3982
+
3983
+ var widget = $( ui.item ).data( 'view' );
3984
+ var targetCell = $( ui.item ).closest( '.cell' ).data( 'view' );
3985
+
3986
+ // Move the model and the view to the new cell
3987
+ widget.model.moveToCell( targetCell.model );
3988
+ widget.cell = targetCell;
3989
+
3990
+ cellView.row.builder.sortCollections();
3991
+ },
3992
+ helper: function ( e, el ) {
3993
+ var helper = el.clone()
3994
+ .css( {
3995
+ 'width': el.outerWidth(),
3996
+ 'z-index': 10000,
3997
+ 'position': 'fixed'
3998
+ } )
3999
+ .addClass( 'widget-being-dragged' ).appendTo( 'body' );
4000
+
4001
+ // Center the helper to the mouse cursor.
4002
+ if ( el.outerWidth() > 720 ) {
4003
+ helper.animate( {
4004
+ 'margin-left': e.pageX - el.offset().left - (
4005
+ 480 / 2
4006
+ ),
4007
+ 'width': 480
4008
+ }, 'fast' );
4009
+ }
4010
+
4011
+ return helper;
4012
+ }
4013
+ } );
4014
+ },
4015
+
4016
+ /**
4017
+ * Refresh the widget sortable when a new widget is added
4018
+ */
4019
+ refreshSortable: function () {
4020
+ this.widgetSortable.sortable( 'refresh' );
4021
+ },
4022
+
4023
+ /**
4024
+ * This will make the cell resizble
4025
+ */
4026
+ initResizable: function () {
4027
+ // var neighbor = this.$el.previous().data('view');
4028
+ var handle = this.$( '.resize-handle' ).css( 'position', 'absolute' );
4029
+ var container = this.row.$el;
4030
+ var cellView = this;
4031
+
4032
+ // The view of the cell to the left is stored when dragging starts.
4033
+ var previousCell;
4034
+
4035
+ handle.draggable( {
4036
+ axis: 'x',
4037
+ containment: container,
4038
+ start: function ( e, ui ) {
4039
+ // Set the containment to the cell parent
4040
+ previousCell = cellView.$el.prev().data( 'view' );
4041
+ if ( _.isUndefined( previousCell ) ) {
4042
+ return;
4043
+ }
4044
+
4045
+ // Create the clone for the current cell
4046
+ var newCellClone = cellView.$el.clone().appendTo( ui.helper ).css( {
4047
+ position: 'absolute',
4048
+ top: '0',
4049
+ width: cellView.$el.outerWidth(),
4050
+ left: 5,
4051
+ height: cellView.$el.outerHeight()
4052
+ } );
4053
+ newCellClone.find( '.resize-handle' ).remove();
4054
+
4055
+ // Create the clone for the previous cell
4056
+ var prevCellClone = previousCell.$el.clone().appendTo( ui.helper ).css( {
4057
+ position: 'absolute',
4058
+ top: '0',
4059
+ width: previousCell.$el.outerWidth(),
4060
+ right: 5,
4061
+ height: previousCell.$el.outerHeight()
4062
+ } );
4063
+ prevCellClone.find( '.resize-handle' ).remove();
4064
+
4065
+ $( this ).data( {
4066
+ 'newCellClone': newCellClone,
4067
+ 'prevCellClone': prevCellClone
4068
+ } );
4069
+ },
4070
+ drag: function ( e, ui ) {
4071
+ // Calculate the new cell and previous cell widths as a percent
4072
+ var containerWidth = cellView.row.$el.width() + 10;
4073
+ var ncw = cellView.model.get( 'weight' ) - (
4074
+ (
4075
+ ui.position.left + handle.outerWidth() / 2
4076
+ ) / containerWidth
4077
+ );
4078
+ var pcw = previousCell.model.get( 'weight' ) + (
4079
+ (
4080
+ ui.position.left + handle.outerWidth() / 2
4081
+ ) / containerWidth
4082
+ );
4083
+
4084
+ $( this ).data( 'newCellClone' ).css( 'width', containerWidth * ncw )
4085
+ .find( '.preview-cell-weight' ).html( Math.round( ncw * 1000 ) / 10 );
4086
+
4087
+ $( this ).data( 'prevCellClone' ).css( 'width', containerWidth * pcw )
4088
+ .find( '.preview-cell-weight' ).html( Math.round( pcw * 1000 ) / 10 );
4089
+ },
4090
+ stop: function ( e, ui ) {
4091
+ // Remove the clones
4092
+ $( this ).data( 'newCellClone' ).remove();
4093
+ $( this ).data( 'prevCellClone' ).remove();
4094
+
4095
+ var containerWidth = cellView.row.$el.width() + 10;
4096
+ var ncw = cellView.model.get( 'weight' ) - (
4097
+ (
4098
+ ui.position.left + handle.outerWidth() / 2
4099
+ ) / containerWidth
4100
+ );
4101
+ var pcw = previousCell.model.get( 'weight' ) + (
4102
+ (
4103
+ ui.position.left + handle.outerWidth() / 2
4104
+ ) / containerWidth
4105
+ );
4106
+
4107
+ if ( ncw > 0.02 && pcw > 0.02 ) {
4108
+ cellView.row.builder.addHistoryEntry( 'cell_resized' );
4109
+ cellView.model.set( 'weight', ncw );
4110
+ previousCell.model.set( 'weight', pcw );
4111
+ cellView.row.resize();
4112
+ }
4113
+
4114
+ ui.helper.css( 'left', - handle.outerWidth() / 2 );
4115
+
4116
+ // Refresh the panels data
4117
+ cellView.row.builder.model.refreshPanelsData();
4118
+ }
4119
+ } );
4120
+
4121
+ },
4122
+
4123
+ /**
4124
+ * This is triggered when ever a widget is added to the row collection.
4125
+ *
4126
+ * @param widget
4127
+ */
4128
+ onAddWidget: function ( widget, collection, options ) {
4129
+ options = _.extend( {noAnimate: false}, options );
4130
+
4131
+ // Create the view for the widget
4132
+ var view = new panels.view.widget( {
4133
+ model: widget
4134
+ } );
4135
+ view.cell = this;
4136
+
4137
+ if ( _.isUndefined( widget.isDuplicate ) ) {
4138
+ widget.isDuplicate = false;
4139
+ }
4140
+
4141
+ // Render and load the form if this is a duplicate
4142
+ view.render( {
4143
+ 'loadForm': widget.isDuplicate
4144
+ } );
4145
+
4146
+ if ( _.isUndefined( options.at ) || collection.length <= 1 ) {
4147
+ // Insert this at the end of the widgets container
4148
+ view.$el.appendTo( this.$( '.widgets-container' ) );
4149
+ } else {
4150
+ // We need to insert this at a specific position
4151
+ view.$el.insertAfter(
4152
+ this.$( '.widgets-container .so-widget' ).eq( options.at - 1 )
4153
+ );
4154
+ }
4155
+
4156
+ if ( options.noAnimate === false ) {
4157
+ // We need an animation
4158
+ view.visualCreate();
4159
+ }
4160
+
4161
+ this.refreshSortable();
4162
+ this.row.resize();
4163
+ },
4164
+
4165
+ /**
4166
+ * Handle this cell being clicked on
4167
+ *
4168
+ * @param e
4169
+ * @returns {boolean}
4170
+ */
4171
+ handleCellClick: function ( e ) {
4172
+ var cells = this.$el.closest( '.so-rows-container' ).find( '.so-cells .cell' ).removeClass( 'cell-selected' );
4173
+ $( e.target ).parent().addClass( 'cell-selected' );
4174
+ },
4175
+
4176
+ /**
4177
+ * Build up the contextual menu for a cell
4178
+ *
4179
+ * @param e
4180
+ * @param menu
4181
+ */
4182
+ buildContextualMenu: function ( e, menu ) {
4183
+ var thisView = this;
4184
+ menu.addSection(
4185
+ {
4186
+ sectionTitle: panelsOptions.loc.contextual.add_widget_cell,
4187
+ searchPlaceholder: panelsOptions.loc.contextual.search_widgets,
4188
+ defaultDisplay: panelsOptions.contextual.default_widgets
4189
+ },
4190
+ panelsOptions.widgets,
4191
+ function ( c ) {
4192
+ thisView.row.builder.addHistoryEntry( 'widget_added' );
4193
+
4194
+ var widget = new panels.model.widget( {
4195
+ class: c
4196
+ } );
4197
+
4198
+ // Add the widget to the cell model
4199
+ widget.cell = thisView.model;
4200
+ widget.cell.widgets.add( widget );
4201
+
4202
+ thisView.row.builder.model.refreshPanelsData();
4203
+ }
4204
+ );
4205
+
4206
+ this.row.buildContextualMenu( e, menu );
4207
+ }
4208
+ } );
4209
+
4210
+ },{}],21:[function(require,module,exports){
4211
+ var panels = window.panels, $ = jQuery;
4212
+
4213
+ module.exports = Backbone.View.extend( {
4214
+ dialogTemplate: _.template( $( '#siteorigin-panels-dialog' ).html().panelsProcessTemplate() ),
4215
+ dialogTabTemplate: _.template( $( '#siteorigin-panels-dialog-tab' ).html().panelsProcessTemplate() ),
4216
+
4217
+ tabbed: false,
4218
+ rendered: false,
4219
+ builder: false,
4220
+ className: 'so-panels-dialog-wrapper',
4221
+ dialogClass: '',
4222
+ parentDialog: false,
4223
+ dialogOpen: false,
4224
+
4225
+ events: {
4226
+ 'click .so-close': 'closeDialog',
4227
+ 'click .so-nav.so-previous': 'navToPrevious',
4228
+ 'click .so-nav.so-next': 'navToNext'
4229
+ },
4230
+
4231
+ initialize: function () {
4232
+ // The first time this dialog is opened, render it
4233
+ this.once( 'open_dialog', this.render );
4234
+ this.once( 'open_dialog', this.attach );
4235
+ this.once( 'open_dialog', this.setDialogClass );
4236
+
4237
+ this.trigger( 'initialize_dialog', this );
4238
+
4239
+ if ( ! _.isUndefined( this.initializeDialog ) ) {
4240
+ this.initializeDialog();
4241
+ }
4242
+ },
4243
+
4244
+ /**
4245
+ * Returns the next dialog in the sequence. Should be overwritten by a child dialog.
4246
+ * @returns {null}
4247
+ */
4248
+ getNextDialog: function () {
4249
+ return null;
4250
+ },
4251
+
4252
+ /**
4253
+ * Returns the previous dialog in this sequence. Should be overwritten by child dialog.
4254
+ * @returns {null}
4255
+ */
4256
+ getPrevDialog: function () {
4257
+ return null;
4258
+ },
4259
+
4260
+ /**
4261
+ * Adds a dialog class to uniquely identify this dialog type
4262
+ */
4263
+ setDialogClass: function () {
4264
+ if ( this.dialogClass !== '' ) {
4265
+ this.$( '.so-panels-dialog' ).addClass( this.dialogClass );
4266
+ }
4267
+ },
4268
+
4269
+ /**
4270
+ * Set the builder that controls this dialog.
4271
+ * @param {panels.view.builder} builder
4272
+ */
4273
+ setBuilder: function ( builder ) {
4274
+ this.builder = builder;
4275
+
4276
+ // Trigger an add dialog event on the builder so it can modify the dialog in any way
4277
+ builder.trigger( 'add_dialog', this, this.builder );
4278
+
4279
+ return this;
4280
+ },
4281
+
4282
+ /**
4283
+ * Attach the dialog to the window
4284
+ */
4285
+ attach: function () {
4286
+ this.$el.appendTo( 'body' );
4287
+
4288
+ return this;
4289
+ },
4290
+
4291
+ /**
4292
+ * Converts an HTML representation of the dialog into arguments for a dialog box
4293
+ * @param html HTML for the dialog
4294
+ * @param args Arguments passed to the template
4295
+ * @returns {}
4296
+ */
4297
+ parseDialogContent: function ( html, args ) {
4298
+ // Add a CID
4299
+ args = _.extend( {cid: this.cid}, args );
4300
+
4301
+
4302
+ var c = $( (
4303
+ _.template( html.panelsProcessTemplate() )
4304
+ )( args ) );
4305
+ var r = {
4306
+ title: c.find( '.title' ).html(),
4307
+ buttons: c.find( '.buttons' ).html(),
4308
+ content: c.find( '.content' ).html()
4309
+ };
4310
+
4311
+ if ( c.has( '.left-sidebar' ) ) {
4312
+ r.left_sidebar = c.find( '.left-sidebar' ).html();
4313
+ }
4314
+
4315
+ if ( c.has( '.right-sidebar' ) ) {
4316
+ r.right_sidebar = c.find( '.right-sidebar' ).html();
4317
+ }
4318
+
4319
+ return r;
4320
+
4321
+ },
4322
+
4323
+ /**
4324
+ * Render the dialog and initialize the tabs
4325
+ *
4326
+ * @param attributes
4327
+ * @returns {panels.view.dialog}
4328
+ */
4329
+ renderDialog: function ( attributes ) {
4330
+ this.$el.html( this.dialogTemplate( attributes ) ).hide();
4331
+ this.$el.data( 'view', this );
4332
+ this.$el.addClass( 'so-panels-dialog-wrapper' );
4333
+
4334
+ if ( this.parentDialog !== false ) {
4335
+ // Add a link to the parent dialog as a sort of crumbtrail.
4336
+ var thisDialog = this;
4337
+ var dialogParent = $( '<h3 class="so-parent-link"></h3>' ).html( this.parentDialog.text + '<div class="so-separator"></div>' );
4338
+ dialogParent.click( function ( e ) {
4339
+ e.preventDefault();
4340
+ thisDialog.closeDialog();
4341
+ thisDialog.parentDialog.openDialog();
4342
+ } );
4343
+ this.$( '.so-title-bar' ).prepend( dialogParent );
4344
+ }
4345
+
4346
+ return this;
4347
+ },
4348
+
4349
+ /**
4350
+ * Initialize the sidebar tabs
4351
+ */
4352
+ initTabs: function () {
4353
+ var tabs = this.$( '.so-sidebar-tabs li a' );
4354
+
4355
+ if ( tabs.length === 0 ) {
4356
+ return this;
4357
+ }
4358
+
4359
+ var thisDialog = this;
4360
+ tabs.click( function ( e ) {
4361
+ e.preventDefault();
4362
+ var $$ = jQuery( this );
4363
+
4364
+ thisDialog.$( '.so-sidebar-tabs li' ).removeClass( 'tab-active' );
4365
+ thisDialog.$( '.so-content .so-content-tabs > *' ).hide();
4366
+
4367
+ $$.parent().addClass( 'tab-active' );
4368
+
4369
+ var url = $$.attr( 'href' );
4370
+ if ( ! _.isUndefined( url ) && url.charAt( 0 ) === '#' ) {
4371
+ // Display the new tab
4372
+ var tabName = url.split( '#' )[1];
4373
+ thisDialog.$( '.so-content .so-content-tabs .tab-' + tabName ).show();
4374
+ }
4375
+
4376
+ // This lets other dialogs implement their own custom handlers
4377
+ thisDialog.trigger( 'tab_click', $$ );
4378
+
4379
+ } );
4380
+
4381
+ // Trigger a click on the first tab
4382
+ this.$( '.so-sidebar-tabs li a' ).first().click();
4383
+ return this;
4384
+ },
4385
+
4386
+ initToolbar: function () {
4387
+ // Trigger simplified click event for elements marked as toolbar buttons.
4388
+ var buttons = this.$( '.so-toolbar .so-buttons .so-toolbar-button' );
4389
+ buttons.click( function ( e ) {
4390
+ e.preventDefault();
4391
+
4392
+ this.trigger( 'button_click', $( e.currentTarget ) );
4393
+ }.bind( this ) );
4394
+
4395
+ // Handle showing and hiding the dropdown list items
4396
+ var $dropdowns = this.$( '.so-toolbar .so-buttons .so-dropdown-button' );
4397
+ $dropdowns.click( function ( e ) {
4398
+ e.preventDefault();
4399
+ var $dropdownButton = $( e.currentTarget );
4400
+ var $dropdownList = $dropdownButton.siblings( '.so-dropdown-links-wrapper' );
4401
+ if ( $dropdownList.is( '.hidden' ) ) {
4402
+ $dropdownList.removeClass( 'hidden' );
4403
+ } else {
4404
+ $dropdownList.addClass( 'hidden' );
4405
+ }
4406
+
4407
+ }.bind( this ) );
4408
+
4409
+ // Hide dropdown list on click anywhere, unless it's a dropdown option which requires confirmation in it's
4410
+ // unconfirmed state.
4411
+ $( 'html' ).click( function ( e ) {
4412
+ this.$( '.so-dropdown-links-wrapper' ).not( '.hidden' ).each( function ( index, el ) {
4413
+ var $dropdownList = $( el );
4414
+ var $trgt = $( e.target );
4415
+ if ( $trgt.length === 0 || ! (
4416
+ (
4417
+ $trgt.is( '.so-needs-confirm' ) && ! $trgt.is( '.so-confirmed' )
4418
+ ) || $trgt.is( '.so-dropdown-button' )
4419
+ ) ) {
4420
+ $dropdownList.addClass( 'hidden' );
4421
+ }
4422
+ } )
4423
+ }.bind( this ) );
4424
+ },
4425
+
4426
+ /**
4427
+ * Quickly setup the dialog by opening and closing it.
4428
+ */
4429
+ setupDialog: function () {
4430
+ this.openDialog();
4431
+ this.closeDialog();
4432
+ },
4433
+
4434
+ /**
4435
+ * Refresh the next and previous buttons.
4436
+ */
4437
+ refreshDialogNav: function () {
4438
+ this.$( '.so-title-bar .so-nav' ).show().removeClass( 'so-disabled' );
4439
+
4440
+ // Lets also hide the next and previous if we don't have a next and previous dialog
4441
+ var nextDialog = this.getNextDialog();
4442
+ var nextButton = this.$( '.so-title-bar .so-next' );
4443
+
4444
+ var prevDialog = this.getPrevDialog();
4445
+ var prevButton = this.$( '.so-title-bar .so-previous' );
4446
+
4447
+ if ( nextDialog === null ) {
4448
+ nextButton.hide();
4449
+ }
4450
+ else if ( nextDialog === false ) {
4451
+ nextButton.addClass( 'so-disabled' );
4452
+ }
4453
+
4454
+ if ( prevDialog === null ) {
4455
+ prevButton.hide();
4456
+ }
4457
+ else if ( prevDialog === false ) {
4458
+ prevButton.addClass( 'so-disabled' );
4459
+ }
4460
+ },
4461
+
4462
+ /**
4463
+ * Open the dialog
4464
+ */
4465
+ openDialog: function ( options ) {
4466
+ options = _.extend( {
4467
+ silent: false
4468
+ }, options );
4469
+
4470
+ if ( ! options.silent ) {
4471
+ this.trigger( 'open_dialog' );
4472
+ }
4473
+
4474
+ this.dialogOpen = true;
4475
+
4476
+ this.refreshDialogNav();
4477
+
4478
+ // Stop scrolling for the main body
4479
+ this.builder.lockPageScroll();
4480
+
4481
+ // Start listen for keyboard keypresses.
4482
+ $( window ).on( 'keyup', this.keyboardListen );
4483
+
4484
+ this.$el.show();
4485
+
4486
+ if ( ! options.silent ) {
4487
+ // This triggers once everything is visible
4488
+ this.trigger( 'open_dialog_complete' );
4489
+ this.builder.trigger( 'open_dialog', this );
4490
+ }
4491
+ },
4492
+
4493
+ /**
4494
+ * Close the dialog
4495
+ *
4496
+ * @param e
4497
+ * @returns {boolean}
4498
+ */
4499
+ closeDialog: function ( options ) {
4500
+ options = _.extend( {
4501
+ silent: false
4502
+ }, options );
4503
+
4504
+ if ( ! options.silent ) {
4505
+ this.trigger( 'close_dialog' );
4506
+ }
4507
+
4508
+ this.dialogOpen = false;
4509
+
4510
+ this.$el.hide();
4511
+ this.builder.unlockPageScroll();
4512
+
4513
+ // Stop listen for keyboard keypresses.
4514
+ $( window ).off( 'keyup', this.keyboardListen );
4515
+
4516
+ if ( ! options.silent ) {
4517
+ // This triggers once everything is hidden
4518
+ this.trigger( 'close_dialog_complete' );
4519
+ this.builder.trigger( 'close_dialog', this );
4520
+ }
4521
+ },
4522
+
4523
+ /**
4524
+ * Keyboard events handler
4525
+ */
4526
+ keyboardListen: function ( e ) {
4527
+ // [Esc] to close
4528
+ if ( e.which === 27 ) {
4529
+ $( '.so-panels-dialog-wrapper .so-close' ).trigger( 'click' );
4530
+ }
4531
+ },
4532
+
4533
+ /**
4534
+ * Navigate to the previous dialog
4535
+ */
4536
+ navToPrevious: function () {
4537
+ this.closeDialog();
4538
+
4539
+ var prev = this.getPrevDialog();
4540
+ if ( prev !== null && prev !== false ) {
4541
+ prev.openDialog();
4542
+ }
4543
+ },
4544
+
4545
+ /**
4546
+ * Navigate to the next dialog
4547
+ */
4548
+ navToNext: function () {
4549
+ this.closeDialog();
4550
+
4551
+ var next = this.getNextDialog();
4552
+ if ( next !== null && next !== false ) {
4553
+ next.openDialog();
4554
+ }
4555
+ },
4556
+
4557
+ /**
4558
+ * Get the values from the form and convert them into a data array
4559
+ */
4560
+ getFormValues: function ( formSelector ) {
4561
+ if ( _.isUndefined( formSelector ) ) {
4562
+ formSelector = '.so-content';
4563
+ }
4564
+
4565
+ var $f = this.$( formSelector );
4566
+
4567
+ var data = {}, parts;
4568
+
4569
+ // Find all the named fields in the form
4570
+ $f.find( '[name]' ).each( function () {
4571
+ var $$ = jQuery( this );
4572
+
4573
+ var name = /([A-Za-z_]+)\[(.*)\]/.exec( $$.attr( 'name' ) );
4574
+ if ( name === undefined ) {
4575
+ return true;
4576
+ }
4577
+
4578
+ // Create an array with the parts of the name
4579
+ if ( _.isUndefined( name[2] ) ) {
4580
+ parts = $$.attr( 'name' );
4581
+ } else {
4582
+ parts = name[2].split( '][' );
4583
+ parts.unshift( name[1] );
4584
+ }
4585
+
4586
+ parts = parts.map( function ( e ) {
4587
+ if ( ! isNaN( parseFloat( e ) ) && isFinite( e ) ) {
4588
+ return parseInt( e );
4589
+ } else {
4590
+ return e;
4591
+ }
4592
+ } );
4593
+
4594
+ var sub = data;
4595
+ var fieldValue = null;
4596
+
4597
+ var fieldType = (
4598
+ _.isString( $$.attr( 'type' ) ) ? $$.attr( 'type' ).toLowerCase() : false
4599
+ );
4600
+
4601
+ // First we need to get the value from the field
4602
+ if ( fieldType === 'checkbox' ) {
4603
+ if ( $$.is( ':checked' ) ) {
4604
+ fieldValue = $$.val() !== '' ? $$.val() : true;
4605
+ } else {
4606
+ fieldValue = null;
4607
+ }
4608
+ }
4609
+ else if ( fieldType === 'radio' ) {
4610
+ if ( $$.is( ':checked' ) ) {
4611
+ fieldValue = $$.val();
4612
+ } else {
4613
+ //skip over unchecked radios
4614
+ return;
4615
+ }
4616
+ }
4617
+ else if ( $$.prop( 'tagName' ) === 'TEXTAREA' && $$.hasClass( 'wp-editor-area' ) ) {
4618
+ // This is a TinyMCE editor, so we'll use the tinyMCE object to get the content
4619
+ var editor = null;
4620
+ if ( ! _.isUndefined( tinyMCE ) ) {
4621
+ editor = tinyMCE.get( $$.attr( 'id' ) );
4622
+ }
4623
+
4624
+ if ( editor !== null && _.isFunction( editor.getContent ) && ! editor.isHidden() ) {
4625
+ fieldValue = editor.getContent();
4626
+ } else {
4627
+ fieldValue = $$.val();
4628
+ }
4629
+ }
4630
+ else if ( $$.prop( 'tagName' ) === 'SELECT' ) {
4631
+ var selected = $$.find( 'option:selected' );
4632
+
4633
+ if ( selected.length === 1 ) {
4634
+ fieldValue = $$.find( 'option:selected' ).val();
4635
+ }
4636
+ else if ( selected.length > 1 ) {
4637
+ // This is a mutli-select field
4638
+ fieldValue = _.map( $$.find( 'option:selected' ), function ( n, i ) {
4639
+ return $( n ).val();
4640
+ } );
4641
+ }
4642
+
4643
+ } else {
4644
+ // This is a fallback that will work for most fields
4645
+ fieldValue = $$.val();
4646
+ }
4647
+
4648
+ // Now, we need to filter this value if necessary
4649
+ if ( ! _.isUndefined( $$.data( 'panels-filter' ) ) ) {
4650
+ switch ( $$.data( 'panels-filter' ) ) {
4651
+ case 'json_parse':
4652
+ // Attempt to parse the JSON value of this field
4653
+ try {
4654
+ fieldValue = JSON.parse( fieldValue );
4655
+ }
4656
+ catch ( err ) {
4657
+ fieldValue = '';
4658
+ }
4659
+ break;
4660
+ }
4661
+ }
4662
+
4663
+ // Now convert this into an array
4664
+ if ( fieldValue !== null ) {
4665
+ for ( var i = 0; i < parts.length; i ++ ) {
4666
+ if ( i === parts.length - 1 ) {
4667
+ if ( parts[i] === '' ) {
4668
+ // This needs to be an array
4669
+ sub.push( fieldValue );
4670
+ } else {
4671
+ sub[parts[i]] = fieldValue;
4672
+ }
4673
+ } else {
4674
+ if ( _.isUndefined( sub[parts[i]] ) ) {
4675
+ if ( parts[i + 1] === '' ) {
4676
+ sub[parts[i]] = [];
4677
+ } else {
4678
+ sub[parts[i]] = {};
4679
+ }
4680
+ }
4681
+ sub = sub[parts[i]];
4682
+ }
4683
+ }
4684
+ }
4685
+
4686
+ } ); // End of each through input fields
4687
+
4688
+ return data;
4689
+ },
4690
+
4691
+ /**
4692
+ * Set a status message for the dialog
4693
+ */
4694
+ setStatusMessage: function ( message, loading ) {
4695
+ this.$( '.so-toolbar .so-status' ).html( message );
4696
+ if ( ! _.isUndefined( loading ) && loading ) {
4697
+ this.$( '.so-toolbar .so-status' ).addClass( 'so-panels-loading' );
4698
+ }
4699
+ },
4700
+
4701
+ /**
4702
+ * Set the parent after.
4703
+ */
4704
+ setParent: function ( text, dialog ) {
4705
+ this.parentDialog = {
4706
+ text: text,
4707
+ dialog: dialog
4708
+ };
4709
+ }
4710
+ } );
4711
+
4712
+ },{}],22:[function(require,module,exports){
4713
+ var panels = window.panels, $ = jQuery;
4714
+
4715
+ module.exports = Backbone.View.extend( {
4716
+ template: _.template( $( '#siteorigin-panels-live-editor' ).html().panelsProcessTemplate() ),
4717
+
4718
+ postId: false,
4719
+ previewScrollTop: 0,
4720
+ loadTimes: [],
4721
+ previewFrameId: 1,
4722
+ previewIframe: null,
4723
+
4724
+ events: {
4725
+ 'click .live-editor-close': 'close',
4726
+ 'click .live-editor-collapse': 'collapse',
4727
+ 'click .live-editor-mode': 'mobileToggle'
4728
+ },
4729
+
4730
+ initialize: function ( options ) {
4731
+ this.builder = options.builder;
4732
+ this.builder.model.on( 'refresh_panels_data', this.handleRefreshData, this );
4733
+ this.builder.model.on( 'load_panels_data', this.handleLoadData, this );
4734
+ },
4735
+
4736
+ /**
4737
+ * Render the live editor
4738
+ */
4739
+ render: function () {
4740
+ this.setElement( this.template() );
4741
+ this.$el.hide();
4742
+ var thisView = this;
4743
+
4744
+ var isMouseDown = false;
4745
+
4746
+ $( document )
4747
+ .mousedown( function () {
4748
+ isMouseDown = true;
4749
+ } )
4750
+ .mouseup( function () {
4751
+ isMouseDown = false;
4752
+ } );
4753
+
4754
+ // Handle highlighting the relevant widget in the live editor preview
4755
+ thisView.$el.on( 'mouseenter', '.so-widget-wrapper', function () {
4756
+ var $$ = $( this ),
4757
+ previewWidget = $( this ).data( 'live-editor-preview-widget' );
4758
+
4759
+ if ( ! isMouseDown && previewWidget !== undefined && previewWidget.length && ! thisView.$( '.so-preview-overlay' ).is( ':visible' ) ) {
4760
+ thisView.highlightElement( previewWidget );
4761
+ thisView.scrollToElement( previewWidget );
4762
+ }
4763
+ } );
4764
+
4765
+ thisView.$el.on( 'mouseleave', '.so-widget-wrapper', function () {
4766
+ thisView.resetHighlights();
4767
+ } );
4768
+
4769
+ thisView.builder.on( 'open_dialog', function () {
4770
+ thisView.resetHighlights();
4771
+ } );
4772
+
4773
+ return this;
4774
+ },
4775
+
4776
+ /**
4777
+ * Attach the live editor to the document
4778
+ */
4779
+ attach: function () {
4780
+ this.$el.appendTo( 'body' );
4781
+ },
4782
+
4783
+ setPostId: function ( postId ) {
4784
+ this.postId = postId;
4785
+ },
4786
+
4787
+ /**
4788
+ * Display the live editor
4789
+ */
4790
+ open: function () {
4791
+ if ( this.$el.html() === '' ) {
4792
+ this.render();
4793
+ }
4794
+ if ( this.$el.closest( 'body' ).length === 0 ) {
4795
+ this.attach();
4796
+ }
4797
+
4798
+ // Disable page scrolling
4799
+ this.builder.lockPageScroll();
4800
+
4801
+ if ( this.$el.is( ':visible' ) ) {
4802
+ return this;
4803
+ }
4804
+
4805
+ // Refresh the preview display
4806
+ this.$el.show();
4807
+ this.refreshPreview( this.builder.model.getPanelsData() );
4808
+
4809
+ this.originalContainer = this.builder.$el.parent();
4810
+ this.builder.$el.appendTo( this.$( '.so-live-editor-builder' ) );
4811
+ this.builder.$( '.so-tool-button.so-live-editor' ).hide();
4812
+ this.builder.trigger( 'builder_resize' );
4813
+
4814
+
4815
+ if( $('#original_post_status' ).val() === 'auto-draft' && ! this.autoSaved ) {
4816
+ // The live editor requires a saved draft post, so we'll create one for auto-draft posts
4817
+ var thisView = this;
4818
+
4819
+ if ( wp.autosave ) {
4820
+ // Set a temporary post title so the autosave triggers properly
4821
+ if( $('#title[name="post_title"]' ).val() === '' ) {
4822
+ $('#title[name="post_title"]' ).val( panelsOptions.loc.draft ).trigger('keydown');
4823
+ }
4824
+
4825
+ $( document ).one( 'heartbeat-tick.autosave', function(){
4826
+ thisView.autoSaved = true;
4827
+ thisView.refreshPreview( thisView.builder.model.getPanelsData() );
4828
+ } );
4829
+ wp.autosave.server.triggerSave();
4830
+ }
4831
+ }
4832
+ },
4833
+
4834
+ /**
4835
+ * Close the live editor
4836
+ */
4837
+ close: function () {
4838
+ if ( ! this.$el.is( ':visible' ) ) {
4839
+ return this;
4840
+ }
4841
+
4842
+ this.$el.hide();
4843
+ this.builder.unlockPageScroll();
4844
+
4845
+ // Move the builder back to its original container
4846
+ this.builder.$el.appendTo( this.originalContainer );
4847
+ this.builder.$( '.so-tool-button.so-live-editor' ).show();
4848
+ this.builder.trigger( 'builder_resize' );
4849
+ },
4850
+
4851
+ /**
4852
+ * Collapse the live editor
4853
+ */
4854
+ collapse: function () {
4855
+ this.$el.toggleClass( 'so-collapsed' );
4856
+
4857
+ var text = this.$( '.live-editor-collapse span' );
4858
+ text.html( text.data( this.$el.hasClass( 'so-collapsed' ) ? 'expand' : 'collapse' ) );
4859
+ },
4860
+
4861
+ /**
4862
+ * Create an overlay in the preview.
4863
+ *
4864
+ * @param over
4865
+ * @return {*|Object} The item we're hovering over.
4866
+ */
4867
+ highlightElement: function ( over ) {
4868
+ if( ! _.isUndefined( this.resetHighlightTimeout ) ) {
4869
+ clearTimeout( this.resetHighlightTimeout );
4870
+ }
4871
+
4872
+ // Remove any old overlays
4873
+
4874
+ var body = this.previewIframe.contents().find( 'body' );
4875
+ body.find( '.panel-grid .panel-grid-cell .so-panel' )
4876
+ .filter( function () {
4877
+ // Filter to only include non nested
4878
+ return $( this ).parents( '.widget_siteorigin-panels-builder' ).length === 0;
4879
+ } )
4880
+ .not( over )
4881
+ .addClass( 'so-panels-faded' );
4882
+
4883
+ over.removeClass( 'so-panels-faded' ).addClass( 'so-panels-highlighted' );
4884
+ },
4885
+
4886
+ /**
4887
+ * Reset highlights in the live preview
4888
+ */
4889
+ resetHighlights: function() {
4890
+
4891
+ var body = this.previewIframe.contents().find( 'body' );
4892
+ this.resetHighlightTimeout = setTimeout( function(){
4893
+ body.find( '.panel-grid .panel-grid-cell .so-panel' )
4894
+ .removeClass( 'so-panels-faded so-panels-highlighted' );
4895
+ }, 100 );
4896
+ },
4897
+
4898
+ /**
4899
+ * Scroll over an element in the live preview
4900
+ * @param over
4901
+ */
4902
+ scrollToElement: function( over ) {
4903
+ var contentWindow = this.$( '.so-preview iframe' )[0].contentWindow;
4904
+ contentWindow.liveEditorScrollTo( over );
4905
+ },
4906
+
4907
+ handleRefreshData: function ( newData, args ) {
4908
+ if ( ! this.$el.is( ':visible' ) ) {
4909
+ return this;
4910
+ }
4911
+
4912
+ this.refreshPreview( newData );
4913
+ },
4914
+
4915
+ handleLoadData: function () {
4916
+ if ( ! this.$el.is( ':visible' ) ) {
4917
+ return this;
4918
+ }
4919
+
4920
+ this.refreshPreview( this.builder.model.getPanelsData() );
4921
+ },
4922
+
4923
+ /**
4924
+ * Refresh the Live Editor preview.
4925
+ * @returns {exports}
4926
+ */
4927
+ refreshPreview: function ( data ) {
4928
+ var loadTimePrediction = this.loadTimes.length ?
4929
+ _.reduce( this.loadTimes, function ( memo, num ) {
4930
+ return memo + num;
4931
+ }, 0 ) / this.loadTimes.length : 1000;
4932
+
4933
+ // Store the last preview iframe position
4934
+ if( ! _.isNull( this.previewIframe ) ) {
4935
+ if ( ! this.$( '.so-preview-overlay' ).is( ':visible' ) ) {
4936
+ this.previewScrollTop = this.previewIframe.contents().scrollTop();
4937
+ }
4938
+ }
4939
+
4940
+ // Add a loading bar
4941
+ this.$( '.so-preview-overlay' ).show();
4942
+ this.$( '.so-preview-overlay .so-loading-bar' )
4943
+ .clearQueue()
4944
+ .css( 'width', '0%' )
4945
+ .animate( {width: '100%'}, parseInt( loadTimePrediction ) + 100 );
4946
+
4947
+
4948
+ this.postToIframe(
4949
+ { live_editor_panels_data: JSON.stringify( data ) },
4950
+ this.$el.data('preview-url'),
4951
+ this.$('.so-preview')
4952
+ );
4953
+
4954
+ this.previewIframe.data( 'load-start', new Date().getTime() );
4955
+ },
4956
+
4957
+ /**
4958
+ * Use a temporary form to post data to an iframe.
4959
+ *
4960
+ * @param data The data to send
4961
+ * @param url The preview URL
4962
+ * @param target The target iframe
4963
+ */
4964
+ postToIframe: function( data, url, target ){
4965
+ // Store the old preview
4966
+
4967
+ if( ! _.isNull( this.previewIframe ) ) {
4968
+ this.previewIframe.remove();
4969
+ }
4970
+
4971
+ var iframeId = 'siteorigin-panels-live-preview-' + this.previewFrameId;
4972
+
4973
+ // Remove the old preview frame
4974
+ this.previewIframe = $('<iframe src="javascript:false;" />')
4975
+ .attr( {
4976
+ 'id' : iframeId,
4977
+ 'name' : iframeId,
4978
+ } )
4979
+ .appendTo( target )
4980
+
4981
+ this.setupPreviewFrame( this.previewIframe );
4982
+
4983
+ // We can use a normal POST form submit
4984
+ var tempForm = $('<form id="soPostToPreviewFrame" method="post" />')
4985
+ .attr( {
4986
+ id: iframeId,
4987
+ target: this.previewIframe.attr('id'),
4988
+ action: url
4989
+ } )
4990
+ .appendTo( 'body' );
4991
+
4992
+ $.each( data, function( name, value ){
4993
+ $('<input type="hidden" />')
4994
+ .attr( {
4995
+ name: name,
4996
+ value: value
4997
+ } )
4998
+ .appendTo( tempForm );
4999
+ } );
5000
+
5001
+ tempForm
5002
+ .submit()
5003
+ .remove();
5004
+
5005
+ this.previewFrameId++;
5006
+
5007
+ return this.previewIframe;
5008
+ },
5009
+
5010
+ setupPreviewFrame: function( iframe ){
5011
+ var thisView = this;
5012
+ iframe
5013
+ .data( 'iframeready', false )
5014
+ .on( 'iframeready', function () {
5015
+ var $$ = $( this ),
5016
+ $iframeContents = $$.contents();
5017
+
5018
+ if( $$.data( 'iframeready' ) ) {
5019
+ // Skip this if the iframeready function has already run
5020
+ return;
5021
+ }
5022
+
5023
+ $$.data( 'iframeready', true );
5024
+
5025
+ if ( $$.data( 'load-start' ) !== undefined ) {
5026
+ thisView.loadTimes.unshift( new Date().getTime() - $$.data( 'load-start' ) );
5027
+
5028
+ if ( ! _.isEmpty( thisView.loadTimes ) ) {
5029
+ thisView.loadTimes = thisView.loadTimes.slice( 0, 4 );
5030
+ }
5031
+ }
5032
+
5033
+ setTimeout( function(){
5034
+ // Scroll to the correct position
5035
+ $iframeContents.scrollTop( thisView.previewScrollTop );
5036
+ thisView.$( '.so-preview-overlay' ).hide();
5037
+ }, 100 );
5038
+
5039
+ // Lets find all the first level grids. This is to account for the Page Builder layout widget.
5040
+ $iframeContents.find( '.panel-grid .panel-grid-cell .so-panel' )
5041
+ .filter( function () {
5042
+ // Filter to only include non nested
5043
+ return $( this ).parents( '.widget_siteorigin-panels-builder' ).length === 0;
5044
+ } )
5045
+ .each( function ( i, el ) {
5046
+ var $$ = $( el );
5047
+ var widgetEdit = thisView.$( '.so-live-editor-builder .so-widget-wrapper' ).eq( $$.data( 'index' ) );
5048
+
5049
+ widgetEdit.data( 'live-editor-preview-widget', $$ );
5050
+
5051
+ $$
5052
+ .css( {
5053
+ 'cursor': 'pointer'
5054
+ } )
5055
+ .mouseenter( function () {
5056
+ widgetEdit.parent().addClass( 'so-hovered' );
5057
+ thisView.highlightElement( $$ );
5058
+ } )
5059
+ .mouseleave( function () {
5060
+ widgetEdit.parent().removeClass( 'so-hovered' );
5061
+ thisView.resetHighlights();
5062
+ } )
5063
+ .click( function ( e ) {
5064
+ e.preventDefault();
5065
+ // When we click a widget, send that click to the form
5066
+ widgetEdit.find( '.title h4' ).click();
5067
+ } );
5068
+ } );
5069
+
5070
+ // Prevent default clicks
5071
+ $iframeContents.find( "a" ).css( {'pointer-events': 'none'} ).click( function ( e ) {
5072
+ e.preventDefault();
5073
+ } );
5074
+
5075
+ } )
5076
+ .on( 'load', function(){
5077
+ var $$ = $( this );
5078
+ if( ! $$.data( 'iframeready' ) ) {
5079
+ $$.trigger('iframeready');
5080
+ }
5081
+ } );
5082
+ },
5083
+
5084
+ /**
5085
+ * Return true if the live editor has a valid preview URL.
5086
+ * @return {boolean}
5087
+ */
5088
+ hasPreviewUrl: function () {
5089
+ return this.$( 'form.live-editor-form' ).attr( 'action' ) !== '';
5090
+ },
5091
+
5092
+ mobileToggle: function( e ){
5093
+ var button = $( e.currentTarget );
5094
+ this.$('.live-editor-mode' ).not( button ).removeClass('so-active');
5095
+ button.addClass( 'so-active' );
5096
+
5097
+ this.$el
5098
+ .removeClass( 'live-editor-desktop-mode live-editor-tablet-mode live-editor-mobile-mode' )
5099
+ .addClass( 'live-editor-' + button.data( 'mode' ) + '-mode' );
5100
+
5101
+ }
5102
+ } );
5103
+
5104
+ },{}],23:[function(require,module,exports){
5105
+ var panels = window.panels, $ = jQuery;
5106
+
5107
+ module.exports = Backbone.View.extend( {
5108
+ template: _.template( $( '#siteorigin-panels-builder-row' ).html().panelsProcessTemplate() ),
5109
+
5110
+ events: {
5111
+ 'click .so-row-settings': 'editSettingsHandler',
5112
+ 'click .so-row-duplicate': 'duplicateHandler',
5113
+ 'click .so-row-delete': 'confirmedDeleteHandler'
5114
+ },
5115
+
5116
+ builder: null,
5117
+ dialog: null,
5118
+
5119
+ /**
5120
+ * Initialize the row view
5121
+ */
5122
+ initialize: function () {
5123
+
5124
+ this.model.cells.on( 'add', this.handleCellAdd, this );
5125
+ this.model.cells.on( 'remove', this.handleCellRemove, this );
5126
+ this.model.on( 'reweight_cells', this.resize, this );
5127
+
5128
+ this.model.on( 'destroy', this.onModelDestroy, this );
5129
+ this.model.on( 'visual_destroy', this.visualDestroyModel, this );
5130
+
5131
+ var thisView = this;
5132
+ this.model.cells.each( function ( cell ) {
5133
+ thisView.listenTo( cell.widgets, 'add', thisView.resize );
5134
+ } );
5135
+
5136
+ // When ever a new cell is added, listen to it for new widgets
5137
+ this.model.cells.on( 'add', function ( cell ) {
5138
+ thisView.listenTo( cell.widgets, 'add', thisView.resize );
5139
+ }, this );
5140
+
5141
+ },
5142
+
5143
+ /**
5144
+ * Render the row.
5145
+ *
5146
+ * @returns {panels.view.row}
5147
+ */
5148
+ render: function () {
5149
+ this.setElement( this.template() );
5150
+ this.$el.data( 'view', this );
5151
+
5152
+ // Create views for the cells in this row
5153
+ var thisView = this;
5154
+ this.model.cells.each( function ( cell ) {
5155
+ var cellView = new panels.view.cell( {
5156
+ model: cell
5157
+ } );
5158
+ cellView.row = thisView;
5159
+ cellView.render();
5160
+ cellView.$el.appendTo( thisView.$( '.so-cells' ) );
5161
+ } );
5162
+
5163
+ // Resize the rows when ever the widget sortable moves
5164
+ this.builder.on( 'widget_sortable_move', this.resize, this );
5165
+ this.builder.on( 'builder_resize', this.resize, this );
5166
+
5167
+ this.resize();
5168
+
5169
+ return this;
5170
+ },
5171
+
5172
+ /**
5173
+ * Give a visual indication of the creation of this row
5174
+ */
5175
+ visualCreate: function () {
5176
+ this.$el.hide().fadeIn( 'fast' );
5177
+ },
5178
+
5179
+ /**
5180
+ * Visually resize the row so that all cell heights are the same and the widths so that they balance to 100%
5181
+ *
5182
+ * @param e
5183
+ */
5184
+ resize: function ( e ) {
5185
+ // Don't resize this
5186
+ if ( ! this.$el.is( ':visible' ) ) {
5187
+ return;
5188
+ }
5189
+
5190
+ // Reset everything to have an automatic height
5191
+ this.$( '.so-cells .cell-wrapper' ).css( 'min-height', 0 );
5192
+
5193
+ // We'll tie the values to the row view, to prevent issue with values going to different rows
5194
+ var height = 0;
5195
+ this.$( '.so-cells .cell' ).each( function () {
5196
+ height = Math.max(
5197
+ height,
5198
+ $( this ).height()
5199
+ );
5200
+
5201
+ $( this ).css( 'width', (
5202
+ $( this ).data( 'view' ).model.get( 'weight' ) * 100
5203
+ ) + "%" );
5204
+ } );
5205
+
5206
+ // Resize all the grids and cell wrappers
5207
+ this.$( '.so-cells .cell-wrapper' ).css( 'min-height', Math.max( height, 64 ) );
5208
+ },
5209
+
5210
+ /**
5211
+ * Remove the view from the dom.
5212
+ */
5213
+ onModelDestroy: function () {
5214
+ this.remove();
5215
+ },
5216
+
5217
+ /**
5218
+ * Fade out the view and destroy the model
5219
+ */
5220
+ visualDestroyModel: function () {
5221
+ this.builder.addHistoryEntry( 'row_deleted' );
5222
+ var thisView = this;
5223
+ this.$el.fadeOut( 'normal', function () {
5224
+ thisView.model.destroy();
5225
+ thisView.builder.model.refreshPanelsData();
5226
+ } );
5227
+ },
5228
+
5229
+ /**
5230
+ * Duplicate this row.
5231
+ *
5232
+ * @return {boolean}
5233
+ */
5234
+ duplicateHandler: function () {
5235
+ this.builder.addHistoryEntry( 'row_duplicated' );
5236
+
5237
+ var duplicateRow = this.model.clone( this.builder.model );
5238
+
5239
+ this.builder.model.rows.add( duplicateRow, {
5240
+ at: this.builder.model.rows.indexOf( this.model ) + 1
5241
+ } );
5242
+
5243
+ this.builder.model.refreshPanelsData();
5244
+ },
5245
+
5246
+ /**
5247
+ * Handles deleting the row with a confirmation.
5248
+ */
5249
+ confirmedDeleteHandler: function ( e ) {
5250
+ var $$ = jQuery( e.target );
5251
+
5252
+ // The user clicked on the dashicon
5253
+ if ( $$.hasClass( 'dashicons' ) ) {
5254
+ $$ = $.parent();
5255
+ }
5256
+
5257
+ if ( $$.hasClass( 'so-confirmed' ) ) {
5258
+ this.visualDestroyModel();
5259
+ } else {
5260
+ var originalText = $$.html();
5261
+
5262
+ $$.addClass( 'so-confirmed' ).html(
5263
+ '<span class="dashicons dashicons-yes"></span>' + panelsOptions.loc.dropdown_confirm
5264
+ );
5265
+
5266
+ setTimeout( function () {
5267
+ $$.removeClass( 'so-confirmed' ).html( originalText );
5268
+ }, 2500 );
5269
+ }
5270
+ },
5271
+
5272
+ /**
5273
+ * Handle displaying the settings dialog
5274
+ */
5275
+ editSettingsHandler: function () {
5276
+ // Lets open up an instance of the settings dialog
5277
+ if ( this.dialog === null ) {
5278
+ // Create the dialog
5279
+ this.dialog = new panels.dialog.row();
5280
+ this.dialog.setBuilder( this.builder ).setRowModel( this.model );
5281
+ }
5282
+
5283
+ this.dialog.openDialog();
5284
+ },
5285
+
5286
+ /**
5287
+ * Handle deleting this entire row.
5288
+ */
5289
+ deleteHandler: function () {
5290
+ this.model.destroy();
5291
+ },
5292
+
5293
+ /**
5294
+ * Handle a new cell being added to this row view. For now we'll assume the new cell is always last
5295
+ */
5296
+ handleCellAdd: function ( cell ) {
5297
+ var cellView = new panels.view.cell( {
5298
+ model: cell
5299
+ } );
5300
+ cellView.row = this;
5301
+ cellView.render();
5302
+ cellView.$el.appendTo( this.$( '.so-cells' ) );
5303
+ },
5304
+
5305
+ /**
5306
+ * Handle a cell being removed from this row view
5307
+ */
5308
+ handleCellRemove: function ( cell ) {
5309
+ // Find the view that ties in to the cell we're removing
5310
+ this.$( '.so-cells > .cell' ).each( function () {
5311
+ var view = $( this ).data( 'view' );
5312
+ if ( _.isUndefined( view ) ) {
5313
+ return;
5314
+ }
5315
+
5316
+ if ( view.model.cid === cell.cid ) {
5317
+ // Remove this view
5318
+ view.remove();
5319
+ }
5320
+ } );
5321
+ },
5322
+
5323
+ /**
5324
+ * Build up the contextual menu for a row
5325
+ *
5326
+ * @param e
5327
+ * @param menu
5328
+ */
5329
+ buildContextualMenu: function ( e, menu ) {
5330
+ var thisView = this;
5331
+
5332
+ var options = [];
5333
+ for ( var i = 1; i < 5; i ++ ) {
5334
+ options.push( {
5335
+ title: i + ' ' + panelsOptions.loc.contextual.column
5336
+ } );
5337
+ }
5338
+
5339
+ menu.addSection(
5340
+ {
5341
+ sectionTitle: panelsOptions.loc.contextual.add_row,
5342
+ search: false
5343
+ },
5344
+ options,
5345
+ function ( c ) {
5346
+ thisView.builder.addHistoryEntry( 'row_added' );
5347
+
5348
+ var columns = Number( c ) + 1;
5349
+ var weights = [];
5350
+ for ( var i = 0; i < columns; i ++ ) {
5351
+ weights.push( 100 / columns );
5352
+ }
5353
+
5354
+ // Create the actual row
5355
+ var newRow = new panels.model.row( {
5356
+ collection: thisView.collection
5357
+ } );
5358
+
5359
+ newRow.setCells( weights );
5360
+ newRow.builder = thisView.builder;
5361
+
5362
+ thisView.builder.model.rows.add( newRow, {
5363
+ at: thisView.builder.model.rows.indexOf( thisView.model ) + 1
5364
+ } );
5365
+
5366
+ thisView.builder.model.refreshPanelsData();
5367
+ }
5368
+ );
5369
+
5370
+ menu.addSection(
5371
+ {
5372
+ sectionTitle: panelsOptions.loc.contextual.row_actions,
5373
+ search: false,
5374
+ },
5375
+ {
5376
+ 'edit': {
5377
+ title: panelsOptions.loc.contextual.row_edit
5378
+ },
5379
+ 'duplicate': {
5380
+ title: panelsOptions.loc.contextual.row_duplicate
5381
+ },
5382
+ 'delete': {
5383
+ title: panelsOptions.loc.contextual.row_delete,
5384
+ confirm: true
5385
+ },
5386
+ },
5387
+ function ( c ) {
5388
+ switch ( c ) {
5389
+ case 'edit':
5390
+ thisView.editSettingsHandler();
5391
+ break;
5392
+ case 'duplicate':
5393
+ thisView.duplicateHandler();
5394
+ break;
5395
+ case 'delete':
5396
+ thisView.visualDestroyModel();
5397
+ break;
5398
+ }
5399
+ }
5400
+ );
5401
+ }
5402
+
5403
+ } );
5404
+
5405
+ },{}],24:[function(require,module,exports){
5406
+ var panels = window.panels, $ = jQuery;
5407
+
5408
+ module.exports = Backbone.View.extend( {
5409
+
5410
+ stylesLoaded: false,
5411
+
5412
+ initialize: function () {
5413
+
5414
+ },
5415
+
5416
+ /**
5417
+ * Render the visual styles object.
5418
+ *
5419
+ * @param type
5420
+ * @param postId
5421
+ */
5422
+ render: function ( stylesType, postId, args ) {
5423
+ if ( _.isUndefined( stylesType ) ) {
5424
+ return;
5425
+ }
5426
+
5427
+ // Add in the default args
5428
+ args = _.extend( {
5429
+ builderType: '',
5430
+ dialog: null
5431
+ }, args );
5432
+
5433
+ this.$el.addClass( 'so-visual-styles' );
5434
+
5435
+ // Load the form
5436
+ var thisView = this;
5437
+ $.post(
5438
+ panelsOptions.ajaxurl,
5439
+ {
5440
+ action: 'so_panels_style_form',
5441
+ type: stylesType,
5442
+ style: this.model.get( 'style' ),
5443
+ args: JSON.stringify( {
5444
+ builderType: args.builderType
5445
+ } ),
5446
+ postId: postId
5447
+ },
5448
+ function ( response ) {
5449
+ thisView.$el.html( response );
5450
+ thisView.setupFields();
5451
+ thisView.stylesLoaded = true;
5452
+ thisView.trigger( 'styles_loaded', ! _.isEmpty( response ) );
5453
+ if ( ! _.isNull( args.dialog ) ) {
5454
+ args.dialog.trigger( 'styles_loaded', ! _.isEmpty( response ) );
5455
+ }
5456
+ }
5457
+ );
5458
+
5459
+ return this;
5460
+ },
5461
+
5462
+ /**
5463
+ * Attach the style view to the DOM.
5464
+ *
5465
+ * @param wrapper
5466
+ */
5467
+ attach: function ( wrapper ) {
5468
+ wrapper.append( this.$el );
5469
+ },
5470
+
5471
+ /**
5472
+ * Detach the styles view from the DOM
5473
+ */
5474
+ detach: function () {
5475
+ this.$el.detach();
5476
+ },
5477
+
5478
+ /**
5479
+ * Setup all the fields
5480
+ */
5481
+ setupFields: function () {
5482
+
5483
+ // Set up the sections as collapsible
5484
+ this.$( '.style-section-wrapper' ).each( function () {
5485
+ var $s = $( this );
5486
+
5487
+ $s.find( '.style-section-head' ).click( function ( e ) {
5488
+ e.preventDefault();
5489
+ $s.find( '.style-section-fields' ).slideToggle( 'fast' );
5490
+ } );
5491
+ } );
5492
+
5493
+ // Set up the color fields
5494
+ if ( ! _.isUndefined( $.fn.wpColorPicker ) ) {
5495
+ if ( _.isObject( panelsOptions.wpColorPickerOptions.palettes ) && ! $.isArray( panelsOptions.wpColorPickerOptions.palettes ) ) {
5496
+ panelsOptions.wpColorPickerOptions.palettes = $.map( panelsOptions.wpColorPickerOptions.palettes, function ( el ) {
5497
+ return el;
5498
+ } );
5499
+ }
5500
+ this.$( '.so-wp-color-field' ).wpColorPicker( panelsOptions.wpColorPickerOptions );
5501
+ }
5502
+
5503
+ // Set up the image select fields
5504
+ this.$( '.style-field-image' ).each( function () {
5505
+ var frame = null;
5506
+ var $s = $( this );
5507
+
5508
+ $s.find( '.so-image-selector' ).click( function ( e ) {
5509
+ e.preventDefault();
5510
+
5511
+ if ( frame === null ) {
5512
+ // Create the media frame.
5513
+ frame = wp.media( {
5514
+ // Set the title of the modal.
5515
+ title: 'choose',
5516
+
5517
+ // Tell the modal to show only images.
5518
+ library: {
5519
+ type: 'image'
5520
+ },
5521
+
5522
+ // Customize the submit button.
5523
+ button: {
5524
+ // Set the text of the button.
5525
+ text: 'Done',
5526
+ close: true
5527
+ }
5528
+ } );
5529
+
5530
+ frame.on( 'select', function () {
5531
+ var attachment = frame.state().get( 'selection' ).first().attributes;
5532
+
5533
+ var url = attachment.url;
5534
+ if ( ! _.isUndefined( attachment.sizes ) ) {
5535
+ try {
5536
+ url = attachment.sizes.thumbnail.url;
5537
+ }
5538
+ catch ( e ) {
5539
+ // We'll use the full image instead
5540
+ url = attachment.sizes.full.url;
5541
+ }
5542
+ }
5543
+ $s.find( '.current-image' ).css( 'background-image', 'url(' + url + ')' );
5544
+
5545
+ // Store the ID
5546
+ $s.find( 'input' ).val( attachment.id )
5547
+ } );
5548
+ }
5549
+
5550
+ frame.open();
5551
+
5552
+ } );
5553
+
5554
+ // Handle clicking on remove
5555
+ $s.find( '.remove-image' ).click( function ( e ) {
5556
+ e.preventDefault();
5557
+ $s.find( '.current-image' ).css( 'background-image', 'none' );
5558
+ $s.find( 'input' ).val( '' );
5559
+ } );
5560
+ } );
5561
+
5562
+ // Set up all the measurement fields
5563
+ this.$( '.style-field-measurement' ).each( function () {
5564
+ var $$ = jQuery( this );
5565
+
5566
+ var text = $$.find( 'input[type="text"]' );
5567
+ var unit = $$.find( 'select' );
5568
+ var hidden = $$.find( 'input[type="hidden"]' );
5569
+
5570
+ // Load the value from the hidden field
5571
+ if ( hidden.val() !== '' ) {
5572
+ var re = /(?:([0-9\.,]+)(.*))+/;
5573
+ var valueList = hidden.val().split( ' ' );
5574
+ var valueListValue = [];
5575
+ for ( var i in valueList ) {
5576
+ var match = re.exec( valueList[i] );
5577
+ if ( _.isNull( match ) && ! _.isUndefined( match[1] ) && ! _.isUndefined( match[2] ) ) {
5578
+ valueListValue.push( match[1] );
5579
+ unit.val( match[2] );
5580
+ }
5581
+ }
5582
+ text.val( valueListValue.join( ' ' ) );
5583
+ }
5584
+
5585
+ var setVal = function () {
5586
+ var fullString = text
5587
+ .val()
5588
+ .split( ' ' )
5589
+ .filter( function ( value ) {
5590
+ return value !== ''
5591
+ } )
5592
+ .map( function ( value ) {
5593
+ return value + unit.val();
5594
+ } )
5595
+ .join( ' ' );
5596
+ hidden.val( fullString );
5597
+ };
5598
+
5599
+ // Set the value when ever anything changes
5600
+ text.keyup( setVal ).change( setVal );
5601
+ unit.change( setVal );
5602
+ } );
5603
+ }
5604
+
5605
+ } );
5606
+
5607
+ },{}],25:[function(require,module,exports){
5608
+ var panels = window.panels, $ = jQuery;
5609
+
5610
+ module.exports = Backbone.View.extend( {
5611
+ template: _.template( $( '#siteorigin-panels-builder-widget' ).html().panelsProcessTemplate() ),
5612
+
5613
+ // The cell view that this widget belongs to
5614
+ cell: null,
5615
+
5616
+ // The edit dialog
5617
+ dialog: null,
5618
+
5619
+ events: {
5620
+ 'click .widget-edit': 'editHandler',
5621
+ 'click .title h4': 'editHandler',
5622
+ 'click .actions .widget-duplicate': 'duplicateHandler',
5623
+ 'click .actions .widget-delete': 'deleteHandler'
5624
+ },
5625
+
5626
+ /**
5627
+ * Initialize the widget
5628
+ */
5629
+ initialize: function () {
5630
+ // The 2 user actions on the model that this view will handle.
5631
+ this.model.on( 'user_edit', this.editHandler, this ); // When a user wants to edit the widget model
5632
+ this.model.on( 'user_duplicate', this.duplicateHandler, this ); // When a user wants to duplicate the widget model
5633
+ this.model.on( 'destroy', this.onModelDestroy, this );
5634
+ this.model.on( 'visual_destroy', this.visualDestroyModel, this );
5635
+
5636
+ this.model.on( 'change:values', this.onModelChange, this );
5637
+ },
5638
+
5639
+ /**
5640
+ * Render the widget
5641
+ */
5642
+ render: function ( options ) {
5643
+ options = _.extend( {'loadForm': false}, options );
5644
+
5645
+ this.setElement( this.template( {
5646
+ title: this.model.getWidgetField( 'title' ),
5647
+ description: this.model.getTitle()
5648
+ } ) );
5649
+
5650
+ this.$el.data( 'view', this );
5651
+
5652
+ if ( _.size( this.model.get( 'values' ) ) === 0 || options.loadForm ) {
5653
+ // If this widget doesn't have a value, create a form and save it
5654
+ var dialog = this.getEditDialog();
5655
+
5656
+ // Save the widget as soon as the form is loaded
5657
+ dialog.once( 'form_loaded', dialog.saveWidget, dialog );
5658
+
5659
+ // Setup the dialog to load the form
5660
+ dialog.setupDialog();
5661
+ }
5662
+
5663
+ return this;
5664
+ },
5665
+
5666
+ /**
5667
+ * Display an animation that implies creation using a visual animation
5668
+ */
5669
+ visualCreate: function () {
5670
+ this.$el.hide().fadeIn( 'fast' );
5671
+ },
5672
+
5673
+ /**
5674
+ * Get the dialog view of the form that edits this widget
5675
+ *
5676
+ * @returns {null}
5677
+ */
5678
+ getEditDialog: function () {
5679
+ if ( this.dialog === null ) {
5680
+ this.dialog = new panels.dialog.widget( {
5681
+ model: this.model
5682
+ } );
5683
+ this.dialog.setBuilder( this.cell.row.builder );
5684
+
5685
+ // Store the widget view
5686
+ this.dialog.widgetView = this;
5687
+ }
5688
+ return this.dialog;
5689
+ },
5690
+
5691
+ /**
5692
+ * Handle clicking on edit widget.
5693
+ *
5694
+ * @returns {boolean}
5695
+ */
5696
+ editHandler: function () {
5697
+ // Create a new dialog for editing this
5698
+ this.getEditDialog().openDialog();
5699
+ },
5700
+
5701
+ /**
5702
+ * Handle clicking on duplicate.
5703
+ *
5704
+ * @returns {boolean}
5705
+ */
5706
+ duplicateHandler: function () {
5707
+ // Add the history entry
5708
+ this.cell.row.builder.addHistoryEntry( 'widget_duplicated' );
5709
+
5710
+ // Create the new widget and connect it to the widget collection for the current row
5711
+ var newWidget = this.model.clone( this.model.cell );
5712
+
5713
+ this.cell.model.widgets.add( newWidget, {
5714
+ // Add this after the existing model
5715
+ at: this.model.collection.indexOf( this.model ) + 1
5716
+ } );
5717
+
5718
+ this.cell.row.builder.model.refreshPanelsData();
5719
+ },
5720
+
5721
+ /**
5722
+ * Handle clicking on delete.
5723
+ *
5724
+ * @returns {boolean}
5725
+ */
5726
+ deleteHandler: function () {
5727
+ this.model.trigger( 'visual_destroy' );
5728
+ },
5729
+
5730
+ onModelChange: function () {
5731
+ // Update the description when ever the model changes
5732
+ this.$( '.description' ).html( this.model.getTitle() );
5733
+ },
5734
+
5735
+ /**
5736
+ * When the model is destroyed, fade it out
5737
+ */
5738
+ onModelDestroy: function () {
5739
+ this.remove();
5740
+ },
5741
+
5742
+ /**
5743
+ * Visually destroy a model
5744
+ */
5745
+ visualDestroyModel: function () {
5746
+ // Add the history entry
5747
+ this.cell.row.builder.addHistoryEntry( 'widget_deleted' );
5748
+
5749
+ var thisView = this;
5750
+ this.$el.fadeOut( 'fast', function () {
5751
+ thisView.cell.row.resize();
5752
+ thisView.model.destroy();
5753
+ thisView.cell.row.builder.model.refreshPanelsData();
5754
+ thisView.remove();
5755
+ } );
5756
+ },
5757
+
5758
+ /**
5759
+ * Build up the contextual menu for a widget
5760
+ *
5761
+ * @param e
5762
+ * @param menu
5763
+ */
5764
+ buildContextualMenu: function ( e, menu ) {
5765
+ var thisView = this;
5766
+
5767
+ menu.addSection(
5768
+ {
5769
+ sectionTitle: panelsOptions.loc.contextual.add_widget_below,
5770
+ searchPlaceholder: panelsOptions.loc.contextual.search_widgets,
5771
+ defaultDisplay: panelsOptions.contextual.default_widgets
5772
+ },
5773
+ panelsOptions.widgets,
5774
+ function ( c ) {
5775
+ thisView.cell.row.builder.addHistoryEntry( 'widget_added' );
5776
+
5777
+ var widget = new panels.model.widget( {
5778
+ class: c
5779
+ } );
5780
+ widget.cell = thisView.cell.model;
5781
+
5782
+ // Insert the new widget below
5783
+ thisView.cell.model.widgets.add( widget, {
5784
+ // Add this after the existing model
5785
+ at: thisView.model.collection.indexOf( thisView.model ) + 1
5786
+ } );
5787
+
5788
+ thisView.cell.row.builder.model.refreshPanelsData();
5789
+ }
5790
+ );
5791
+
5792
+ menu.addSection(
5793
+ {
5794
+ sectionTitle: panelsOptions.loc.contextual.widget_actions,
5795
+ search: false,
5796
+ },
5797
+ {
5798
+ 'edit': {
5799
+ title: panelsOptions.loc.contextual.widget_edit
5800
+ },
5801
+ 'duplicate': {
5802
+ title: panelsOptions.loc.contextual.widget_duplicate
5803
+ },
5804
+ 'delete': {
5805
+ title: panelsOptions.loc.contextual.widget_delete,
5806
+ confirm: true
5807
+ },
5808
+ },
5809
+ function ( c ) {
5810
+ switch ( c ) {
5811
+ case 'edit':
5812
+ thisView.editHandler();
5813
+ break;
5814
+ case 'duplicate':
5815
+ thisView.duplicateHandler();
5816
+ break;
5817
+ case 'delete':
5818
+ thisView.visualDestroyModel();
5819
+ break;
5820
+ }
5821
+
5822
+ thisView.cell.row.builder.model.refreshPanelsData();
5823
+ }
5824
+ );
5825
+
5826
+ // Lets also add the contextual menu for the entire row
5827
+ this.cell.row.buildContextualMenu( e, menu );
5828
+ }
5829
+
5830
+ } );
5831
+
5832
+ },{}]},{},[12]);
js/siteorigin-panels-24.min.js ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ !function e(t,i,s){function l(n,a){if(!i[n]){if(!t[n]){var r="function"==typeof require&&require;if(!a&&r)return r(n,!0);if(o)return o(n,!0);var d=new Error("Cannot find module '"+n+"'");throw d.code="MODULE_NOT_FOUND",d}var c=i[n]={exports:{}};t[n][0].call(c.exports,function(e){var i=t[n][1][e];return l(i?i:e)},c,c.exports,e,t,i,s)}return i[n].exports}for(var o="function"==typeof require&&require,n=0;n<s.length;n++)l(s[n]);return l}({1:[function(e,t,i){var s=window.panels;t.exports=Backbone.Collection.extend({model:s.model.cell,initialize:function(){},totalWeight:function(){var e=0;return this.each(function(t){e+=t.get("weight")}),e},comparator:function(e){return _.isNull(e.indexes)?null:e.indexes.builder}})},{}],2:[function(e,t,i){var s=window.panels;t.exports=Backbone.Collection.extend({model:s.model.historyEntry,builder:null,maxSize:12,initialize:function(){this.on("add",this.onAddEntry,this)},addEntry:function(e,t){_.isEmpty(t)&&(t=this.builder.getPanelsData());var i=new s.model.historyEntry({text:e,data:JSON.stringify(t),time:parseInt((new Date).getTime()/1e3),collection:this});this.add(i)},onAddEntry:function(e){if(this.models.length>1){var t=this.at(this.models.length-2);(e.get("text")===t.get("text")&&e.get("time")-t.get("time")<15||e.get("data")===t.get("data"))&&(this.remove(e),t.set("count",t.get("count")+1))}for(;this.models.length>this.maxSize;)this.shift()}})},{}],3:[function(e,t,i){var s=window.panels;t.exports=Backbone.Collection.extend({model:s.model.row,empty:function(){for(var e;;){if(e=this.collection.first(),!e)break;e.destroy()}},comparator:function(e){return _.isNull(e.indexes)?null:e.indexes.builder}})},{}],4:[function(e,t,i){var s=window.panels;t.exports=Backbone.Collection.extend({model:s.model.widget,initialize:function(){},comparator:function(e){return _.isNull(e.indexes)?null:e.indexes.builder}})},{}],5:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=s.view.dialog.extend({dialogClass:"so-panels-dialog-add-builder",render:function(){this.renderDialog(this.parseDialogContent(l("#siteorigin-panels-dialog-builder").html(),{})),this.$(".so-content .siteorigin-panels-builder").append(this.builder.$el)},initializeDialog:function(){var e=this;this.once("open_dialog_complete",function(){e.builder.initSortable()}),this.on("open_dialog_complete",function(){e.builder.trigger("builder_resize")})}})},{}],6:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=s.view.dialog.extend({historyEntryTemplate:_.template(l("#siteorigin-panels-dialog-history-entry").html().panelsProcessTemplate()),entries:{},currentEntry:null,revertEntry:null,selectedEntry:null,previewScrollTop:null,dialogClass:"so-panels-dialog-history",events:{"click .so-close":"closeDialog","click .so-restore":"restoreSelectedEntry"},initializeDialog:function(){this.entries=new s.collection.historyEntries,this.on("open_dialog",this.setCurrentEntry,this),this.on("open_dialog",this.renderHistoryEntries,this)},render:function(){var e=this;this.renderDialog(this.parseDialogContent(l("#siteorigin-panels-dialog-history").html(),{})),this.$("iframe.siteorigin-panels-history-iframe").load(function(){var t=l(this);t.show(),t.contents().scrollTop(e.previewScrollTop)})},setRevertEntry:function(e){this.revertEntry=new s.model.historyEntry({data:JSON.stringify(e.getPanelsData()),time:parseInt((new Date).getTime()/1e3)})},setCurrentEntry:function(){this.currentEntry=new s.model.historyEntry({data:JSON.stringify(this.builder.model.getPanelsData()),time:parseInt((new Date).getTime()/1e3)}),this.selectedEntry=this.currentEntry,this.previewEntry(this.currentEntry),this.$(".so-buttons .so-restore").addClass("disabled")},renderHistoryEntries:function(){var e=this,t=this.$(".history-entries").empty();this.currentEntry.get("data")===this.revertEntry.get("data")&&_.isEmpty(this.entries.models)||l(this.historyEntryTemplate({title:panelsOptions.loc.history.revert,count:1})).data("historyEntry",this.revertEntry).prependTo(t),this.entries.each(function(i){var s=e.historyEntryTemplate({title:panelsOptions.loc.history[i.get("text")],count:i.get("count")});l(s).data("historyEntry",i).prependTo(t)}),l(this.historyEntryTemplate({title:panelsOptions.loc.history.current,count:1})).data("historyEntry",this.currentEntry).addClass("so-selected").prependTo(t),t.find(".history-entry").click(function(){var i=jQuery(this);t.find(".history-entry").not(i).removeClass("so-selected"),i.addClass("so-selected");var s=i.data("historyEntry");e.selectedEntry=s,e.selectedEntry.cid!==e.currentEntry.cid?e.$(".so-buttons .so-restore").removeClass("disabled"):e.$(".so-buttons .so-restore").addClass("disabled"),e.previewEntry(s)}),this.updateEntryTimes()},previewEntry:function(e){var t=this.$("iframe.siteorigin-panels-history-iframe");t.hide(),this.previewScrollTop=t.contents().scrollTop(),this.$('form.history-form input[name="live_editor_panels_data"]').val(e.get("data")),this.$("form.history-form").submit()},restoreSelectedEntry:function(){return this.$(".so-buttons .so-restore").hasClass("disabled")?!1:this.currentEntry.get("data")===this.selectedEntry.get("data")?(this.closeDialog(),!1):("restore"!==this.selectedEntry.get("text")&&this.builder.addHistoryEntry("restore",this.builder.model.getPanelsData()),this.builder.model.loadPanelsData(JSON.parse(this.selectedEntry.get("data"))),this.closeDialog(),!1)},updateEntryTimes:function(){var e=this;this.$(".history-entries .history-entry").each(function(){var t=jQuery(this),i=t.find(".timesince"),s=t.data("historyEntry");i.html(e.timeSince(s.get("time")))})},timeSince:function(e){var t,i=parseInt((new Date).getTime()/1e3)-e,s=[];return i>3600&&(t=Math.floor(i/3600),1===t?s.push(panelsOptions.loc.time.hour.replace("%d",t)):s.push(panelsOptions.loc.time.hours.replace("%d",t)),i-=3600*t),i>60&&(t=Math.floor(i/60),1===t?s.push(panelsOptions.loc.time.minute.replace("%d",t)):s.push(panelsOptions.loc.time.minutes.replace("%d",t)),i-=60*t),i>0&&(1===i?s.push(panelsOptions.loc.time.second.replace("%d",i)):s.push(panelsOptions.loc.time.seconds.replace("%d",i))),_.isEmpty(s)?panelsOptions.loc.time.now:panelsOptions.loc.time.ago.replace("%s",s.slice(0,2).join(", "))}})},{}],7:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=s.view.dialog.extend({directoryTemplate:_.template(l("#siteorigin-panels-directory-items").html().panelsProcessTemplate()),builder:null,dialogClass:"so-panels-dialog-prebuilt-layouts",layoutCache:{},currentTab:!1,directoryPage:1,events:{"click .so-close":"closeDialog","click .so-sidebar-tabs li a":"tabClickHandler","click .so-content .layout":"layoutClickHandler","keyup .so-sidebar-search":"searchHandler","click .so-screenshot, .so-title":"directoryItemClickHandler"},initializeDialog:function(){var e=this;this.on("open_dialog",function(){e.$(".so-sidebar-tabs li a").first().click(),e.$(".so-status").removeClass("so-panels-loading")}),this.on("button_click",this.toolbarButtonClick,this)},render:function(){this.renderDialog(this.parseDialogContent(l("#siteorigin-panels-dialog-prebuilt").html(),{})),this.initToolbar()},tabClickHandler:function(e){e.preventDefault(),this.selectedLayoutItem=null,this.uploadedLayout=null,this.updateButtonState(!1),this.$(".so-sidebar-tabs li").removeClass("tab-active");var t=l(e.target),i=t.attr("href").split("#")[1];t.parent().addClass("tab-active");var s=this;this.$(".so-content").empty(),s.currentTab=i,"import"==i?this.displayImportExport():this.displayLayoutDirectory("",1,i),s.$(".so-sidebar-search").val("")},displayImportExport:function(){var e=this.$(".so-content").empty().removeClass("so-panels-loading");e.html(l("#siteorigin-panels-dialog-prebuilt-importexport").html());var t=this,i=t.$(".import-upload-ui").hide(),s=new plupload.Uploader({runtimes:"html5,silverlight,flash,html4",browse_button:i.find(".file-browse-button").get(0),container:i.get(0),drop_element:i.find(".drag-upload-area").get(0),file_data_name:"panels_import_data",multiple_queues:!1,max_file_size:panelsOptions.plupload.max_file_size,url:panelsOptions.plupload.url,flash_swf_url:panelsOptions.plupload.flash_swf_url,silverlight_xap_url:panelsOptions.plupload.silverlight_xap_url,filters:[{title:panelsOptions.plupload.filter_title,extensions:"json"}],multipart_params:{action:"so_panels_import_layout"},init:{PostInit:function(e){e.features.dragdrop&&i.addClass("has-drag-drop"),i.show().find(".progress-precent").css("width","0%")},FilesAdded:function(e){i.find(".file-browse-button").blur(),i.find(".drag-upload-area").removeClass("file-dragover"),i.find(".progress-bar").fadeIn("fast"),t.$(".js-so-selected-file").text(panelsOptions.loc.prebuilt_loading),e.start()},UploadProgress:function(e,t){i.find(".progress-precent").css("width",t.percent+"%")},FileUploaded:function(e,s,l){var o=JSON.parse(l.response);_.isUndefined(o.widgets)?alert(panelsOptions.plupload.error_message):(t.uploadedLayout=o,i.find(".progress-bar").hide(),t.$(".js-so-selected-file").text(panelsOptions.loc.ready_to_insert.replace("%s",s.name)),t.updateButtonState(!0))},Error:function(){alert(panelsOptions.plupload.error_message)}}});s.init(),i.find(".drag-upload-area").on("dragover",function(){l(this).addClass("file-dragover")}).on("dragleave",function(){l(this).removeClass("file-dragover")}),e.find(".so-export").submit(function(e){var i=jQuery(this);i.find('input[name="panels_export_data"]').val(JSON.stringify(t.builder.model.getPanelsData()))})},displayLayoutDirectory:function(e,t,i){var s=this,o=this.$(".so-content").empty().addClass("so-panels-loading");return void 0===e&&(e=""),void 0===t&&(t=1),void 0===i&&(i="directory"),"directory"!==i||panelsOptions.directory_enabled?void l.get(panelsOptions.ajaxurl,{action:"so_panels_layouts_query",search:e,page:t,type:i},function(n){if(s.currentTab===i){o.removeClass("so-panels-loading").html(s.directoryTemplate(n));var a=o.find(".so-previous"),r=o.find(".so-next");1>=t?a.addClass("button-disabled"):a.click(function(i){i.preventDefault(),s.displayLayoutDirectory(e,t-1,s.currentTab)}),t===n.max_num_pages||0===n.max_num_pages?r.addClass("button-disabled"):r.click(function(i){i.preventDefault(),s.displayLayoutDirectory(e,t+1,s.currentTab)}),o.find(".so-screenshot").each(function(){var e=l(this),t=e.find(".so-screenshot-wrapper");if(t.css("height",t.width()/4*3+"px").addClass("so-loading"),""!==e.data("src"))var i=l("<img/>").attr("src",e.data("src")).load(function(){t.removeClass("so-loading").css("height","auto"),i.appendTo(t).hide().fadeIn("fast")});else l("<img/>").attr("src",panelsOptions.prebuiltDefaultScreenshot).appendTo(t).hide().fadeIn("fast")}),o.find(".so-directory-browse").html(n.title)}},"json"):(o.removeClass("so-panels-loading").html(l("#siteorigin-panels-directory-enable").html()),void o.find(".so-panels-enable-directory").click(function(i){i.preventDefault(),l.get(panelsOptions.ajaxurl,{action:"so_panels_directory_enable"},function(){}),panelsOptions.directory_enabled=!0,o.addClass("so-panels-loading"),s.displayLayoutDirectory(e,t)}))},directoryItemClickHandler:function(e){var t=this.$(e.target).closest(".so-directory-item");this.$(".so-directory-items").find(".selected").removeClass("selected"),t.addClass("selected"),this.selectedLayoutItem={lid:t.data("layout-id"),type:t.data("layout-type")},this.updateButtonState(!0)},toolbarButtonClick:function(e){if(!this.canAddLayout())return!1;var t=e.data("value");if(_.isUndefined(t))return!1;if(this.updateButtonState(!1),e.hasClass("so-needs-confirm")&&!e.hasClass("so-confirmed")){if(this.updateButtonState(!0),e.hasClass("so-confirming"))return;e.addClass("so-confirming");var i=e.html();return e.html('<span class="dashicons dashicons-yes"></span>'+e.data("confirm")),setTimeout(function(){e.removeClass("so-confirmed").html(i)},2500),setTimeout(function(){e.removeClass("so-confirming"),e.addClass("so-confirmed")},200),!1}this.addingLayout=!0,"import"===this.currentTab?this.addLayoutToBuilder(this.uploadedLayout,t):this.loadSelectedLayout().then(function(e){this.addLayoutToBuilder(e,t)}.bind(this))},canAddLayout:function(){return(this.selectedLayoutItem||this.uploadedLayout)&&!this.addingLayout},loadSelectedLayout:function(){this.setStatusMessage(panelsOptions.loc.prebuilt_loading,!0);var e=_.extend(this.selectedLayoutItem,{action:"so_panels_get_layout"}),t=new l.Deferred;return l.get(panelsOptions.ajaxurl,e,function(e){void 0!==e.error?(alert(e.error),t.reject(e)):(this.setStatusMessage("",!1),t.resolve(e))}.bind(this)),t.promise()},searchHandler:function(e){13===e.keyCode&&this.displayLayoutDirectory(l(e.currentTarget).val(),1,this.currentTab)},updateButtonState:function(e){e=e&&(this.selectedLayoutItem||this.uploadedLayout);var t=this.$(".so-import-layout");t.prop("disabled",!e),e?t.removeClass("disabled"):t.addClass("disabled")},addLayoutToBuilder:function(e,t){this.builder.addHistoryEntry("prebuilt_loaded"),this.builder.model.loadPanelsData(e,t),this.addingLayout=!1,this.closeDialog()}})},{}],8:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=s.view.dialog.extend({cellPreviewTemplate:_.template(l("#siteorigin-panels-dialog-row-cell-preview").html().panelsProcessTemplate()),events:{"click .so-close":"closeDialog","click .so-toolbar .so-save":"saveHandler","click .so-toolbar .so-insert":"insertHandler","click .so-toolbar .so-delete":"deleteHandler","click .so-toolbar .so-duplicate":"duplicateHandler","change .row-set-form > *":"setCellsFromForm","click .row-set-form button.set-row":"setCellsFromForm"},dialogClass:"so-panels-dialog-row-edit",styleType:"row",dialogType:"edit",row:{cells:[],style:{}},initializeDialog:function(){this.on("open_dialog",function(){_.isUndefined(this.model)||_.isEmpty(this.model.cells)?this.setRowModel(null):this.setRowModel(this.model),this.regenerateRowPreview()},this),this.row={cells:[.5,.5],style:{}},this.dialogFormsLoaded=0;var e=this;this.on("form_loaded styles_loaded",function(){this.dialogFormsLoaded++,2===this.dialogFormsLoaded&&e.updateModel({refreshArgs:{silent:!0}})})},setRowDialogType:function(e){this.dialogType=e},render:function(e){if(this.renderDialog(this.parseDialogContent(l("#siteorigin-panels-dialog-row").html(),{dialogType:this.dialogType})),"edit"===this.dialogType){this.styles=new s.view.styles,this.styles.model=this.model,this.styles.render("row",l("#post_ID").val(),{builderType:this.builder.builderType,dialog:this});var t=this.$(".so-sidebar.so-right-sidebar");this.styles.attach(t),this.styles.on("styles_loaded",function(e){e?t.removeClass("so-panels-loading"):(t.closest(".so-panels-dialog").removeClass("so-panels-dialog-has-right-sidebar"),t.remove())},this),t.addClass("so-panels-loading")}_.isUndefined(this.model)||this.$("input.so-row-field").val(this.model.cells.length);return this.$("input.so-row-field").keyup(function(){l(this).trigger("change")}),this},setRowModel:function(e){return this.model=e,_.isEmpty(this.model)?this:(this.row={cells:this.model.cells.map(function(e){return e.get("weight")}),style:{}},this.$("input.so-row-field").val(this.model.cells.length),this)},regenerateRowPreview:function(){var e=this,t=this.$(".row-preview");t.empty();var i;_.each(this.row.cells,function(s,o){var n=l(this.cellPreviewTemplate({weight:s}));t.append(n);var a,r=n.prev();r.length&&(a=l('<div class="resize-handle"></div>'),a.appendTo(n).dblclick(function(){var t=e.row.cells[o]+e.row.cells[o-1];e.row.cells[o]=e.row.cells[o-1]=t/2,e.scaleRowWidths()}),a.draggable({axis:"x",containment:t,start:function(e,t){var i=n.clone().appendTo(t.helper).css({position:"absolute",top:"0",width:n.outerWidth(),left:6,height:n.outerHeight()});i.find(".resize-handle").remove();var s=r.clone().appendTo(t.helper).css({position:"absolute",top:"0",width:r.outerWidth(),right:6,height:r.outerHeight()});s.find(".resize-handle").remove(),l(this).data({newCellClone:i,prevCellClone:s}),n.find("> .preview-cell-in").css("visibility","hidden"),r.find("> .preview-cell-in").css("visibility","hidden")},drag:function(i,s){var n=e.row.cells[o]-(s.position.left+6)/t.width(),a=e.row.cells[o-1]+(s.position.left+6)/t.width();s.helper.offset().left-t.offset().left-6;l(this).data("newCellClone").css("width",t.width()*n).find(".preview-cell-weight").html(Math.round(1e3*n)/10),l(this).data("prevCellClone").css("width",t.width()*a).find(".preview-cell-weight").html(Math.round(1e3*a)/10)},stop:function(i,s){l(this).data("newCellClone").remove(),l(this).data("prevCellClone").remove(),n.find(".preview-cell-in").css("visibility","visible"),r.find(".preview-cell-in").css("visibility","visible");var a=s.position.left+6,d=a/t.width();e.row.cells[o]-d>.02&&e.row.cells[o-1]+d>.02&&(e.row.cells[o]-=d,e.row.cells[o-1]+=d),e.scaleRowWidths(),s.helper.css("left",-6)}})),n.find(".preview-cell-weight").click(function(s){e.$(".resize-handle").css("pointer-event","none").draggable("disable"),t.find(".preview-cell-weight").each(function(){var s=jQuery(this).hide();l('<input type="text" class="preview-cell-weight-input no-user-interacted" />').val(parseFloat(s.html())).insertAfter(s).focus(function(){clearTimeout(i)}).keyup(function(e){9!==e.keyCode&&l(this).removeClass("no-user-interacted"),13===e.keyCode&&(e.preventDefault(),l(this).blur())}).keydown(function(e){if(9===e.keyCode){e.preventDefault();var i=t.find(".preview-cell-weight-input"),s=i.index(l(this));s===i.length-1?i.eq(0).focus().select():i.eq(s+1).focus().select()}}).blur(function(){t.find(".preview-cell-weight-input").each(function(t,i){isNaN(parseFloat(l(i).val()))&&l(i).val(Math.floor(1e3*e.row.cells[t])/10)}),i=setTimeout(function(){if(0===t.find(".preview-cell-weight-input").legnth)return!1;var i=[],s=[],o=0,n=0;if(t.find(".preview-cell-weight-input").each(function(t,a){var r=parseFloat(l(a).val());r=isNaN(r)?1/e.row.cells.length:Math.round(10*r)/1e3;var d=!l(a).hasClass("no-user-interacted");i.push(r),s.push(d),d?o+=r:n+=r}),o>0&&n>0&&1-o>0)for(var a=0;a<i.length;a++)s[a]||(i[a]=i[a]/n*(1-o));var r=_.reduce(i,function(e,t){return e+t});i=i.map(function(e){return e/r}),Math.min.apply(Math,i)>.01&&(e.row.cells=i),t.find(".preview-cell").each(function(t,i){l(i).animate({width:Math.round(1e3*e.row.cells[t])/10+"%"},250),l(i).find(".preview-cell-weight-input").val(Math.round(1e3*e.row.cells[t])/10)}),t.find(".preview-cell").css("overflow","visible"),setTimeout(function(){e.regenerateRowPreview()},260)},100)}).click(function(){l(this).select()})}),l(this).siblings(".preview-cell-weight-input").select()})},this),this.trigger("form_loaded",this)},scaleRowWidths:function(){var e=this;this.$(".row-preview .preview-cell").each(function(t,i){l(i).css("width",100*e.row.cells[t]+"%").find(".preview-cell-weight").html(Math.round(1e3*e.row.cells[t])/10)})},setCellsFromForm:function(){var e={cells:parseInt(this.$('.row-set-form input[name="cells"]').val()),ratio:parseFloat(this.$('.row-set-form select[name="ratio"]').val()),direction:this.$('.row-set-form select[name="ratio_direction"]').val()};_.isNaN(e.cells)&&(e.cells=1),isNaN(e.ratio)&&(e.ratio=1),e.cells<1?(e.cells=1,this.$('.row-set-form input[name="cells"]').val(e.cells)):e.cells>10&&(e.cells=10,this.$('.row-set-form input[name="cells"]').val(e.cells)),this.$('.row-set-form input[name="ratio"]').val(e.ratio);for(var t=[],i=this.row.cells.length!==e.cells,s=1,o=0;o<e.cells;o++)t.push(s),s*=e.ratio;var n=_.reduce(t,function(e,t){return e+t});if(t=_.map(t,function(e){return e/n}),t=_.filter(t,function(e){return e>.01}),"left"===e.direction&&(t=t.reverse()),this.row.cells=t,i)this.regenerateRowPreview();else{var a=this;this.$(".preview-cell").each(function(e,t){l(t).animate({width:Math.round(1e3*a.row.cells[e])/10+"%"},250),l(t).find(".preview-cell-weight").html(Math.round(1e3*a.row.cells[e])/10)}),this.$(".preview-cell").css("overflow","visible"),setTimeout(function(){a.regenerateRowPreview()},260)}this.$(".row-set-form .so-button-row-set").removeClass("button-primary")},tabClickHandler:function(e){"#row-layout"===e.attr("href")?this.$(".so-panels-dialog").addClass("so-panels-dialog-has-right-sidebar"):this.$(".so-panels-dialog").removeClass("so-panels-dialog-has-right-sidebar")},updateModel:function(e){if(e=_.extend({refresh:!0,refreshArgs:null},e),_.isUndefined(this.model)||this.model.setCells(this.row.cells),!_.isUndefined(this.styles)&&this.styles.stylesLoaded){var t={};try{t=this.getFormValues(".so-sidebar .so-visual-styles").style}catch(i){}this.model.set("style",t)}e.refresh&&this.builder.model.refreshPanelsData(e.refreshArgs)},insertHandler:function(){this.builder.addHistoryEntry("row_added"),this.model=new s.model.row,this.updateModel();var e=this.builder.getActiveCell({createCell:!1,defaultPosition:"last"}),t={};return null!==e&&(t.at=this.builder.model.rows.indexOf(e.row)+1),this.model.collection=this.builder.model.rows,this.builder.model.rows.add(this.model,t),this.closeDialog(),this.builder.model.refreshPanelsData(),!1},saveHandler:function(){return this.builder.addHistoryEntry("row_edited"),this.updateModel(),this.closeDialog(),this.builder.model.refreshPanelsData(),!1},deleteHandler:function(){return this.model.trigger("visual_destroy"),this.closeDialog({silent:!0}),!1},duplicateHandler:function(){this.builder.addHistoryEntry("row_duplicated");var e=this.model.clone(this.builder.model);return this.builder.model.rows.add(e,{at:this.builder.model.rows.indexOf(this.model)+1}),this.closeDialog({silent:!0}),!1}})},{}],9:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=s.view.dialog.extend({builder:null,sidebarWidgetTemplate:_.template(l("#siteorigin-panels-dialog-widget-sidebar-widget").html().panelsProcessTemplate()),dialogClass:"so-panels-dialog-edit-widget",widgetView:!1,savingWidget:!1,events:{"click .so-close":"saveHandler","click .so-nav.so-previous":"navToPrevious","click .so-nav.so-next":"navToNext","click .so-toolbar .so-delete":"deleteHandler","click .so-toolbar .so-duplicate":"duplicateHandler"},initializeDialog:function(){var e=this;this.model.on("change:values",this.handleChangeValues,this),this.model.on("destroy",this.remove,this),this.dialogFormsLoaded=0,this.on("form_loaded styles_loaded",function(){this.dialogFormsLoaded++,2===this.dialogFormsLoaded&&e.updateModel({refreshArgs:{silent:!0}})})},render:function(){this.renderDialog(this.parseDialogContent(l("#siteorigin-panels-dialog-widget").html(),{})),this.loadForm(),_.isUndefined(panelsOptions.widgets[this.model.get("class")])?this.$(".so-title .widget-name").html(panelsOptions.loc.missing_widget.title):this.$(".so-title .widget-name").html(panelsOptions.widgets[this.model.get("class")].title),this.styles=new s.view.styles,this.styles.model=this.model,this.styles.render("widget",l("#post_ID").val(),{builderType:this.builder.builderType,dialog:this});var e=this.$(".so-sidebar.so-right-sidebar");this.styles.attach(e),this.styles.on("styles_loaded",function(t){t?e.removeClass("so-panels-loading"):(e.closest(".so-panels-dialog").removeClass("so-panels-dialog-has-right-sidebar"),e.remove())},this),e.addClass("so-panels-loading")},getPrevDialog:function(){var e=this.builder.$(".so-cells .cell .so-widget");if(e.length<=1)return!1;var t=e.index(this.widgetView.$el);if(0===t)return!1;var i=e.eq(t-1).data("view");return _.isUndefined(i)?!1:i.getEditDialog()},getNextDialog:function(){var e=this.builder.$(".so-cells .cell .so-widget");if(e.length<=1)return!1;var t=e.index(this.widgetView.$el);if(t===e.length-1)return!1;var i=e.eq(t+1).data("view");return _.isUndefined(i)?!1:i.getEditDialog()},loadForm:function(){if(this.$("> *").length){var e=this;this.$(".so-content").addClass("so-panels-loading");var t={action:"so_panels_widget_form",widget:this.model.get("class"),instance:JSON.stringify(this.model.get("values")),raw:this.model.get("raw")};l.post(panelsOptions.ajaxurl,t,function(t){var i=t.replace(/{\$id}/g,e.model.cid);e.$(".so-content").removeClass("so-panels-loading").html(i),e.trigger("form_loaded",e),e.$(".panel-dialog").trigger("panelsopen"),e.on("close_dialog",e.updateModel,e)},"html")}},updateModel:function(e){if(e=_.extend({refresh:!0,refreshArgs:null},e),this.savingWidget=!0,!this.model.get("missing")){var t=this.getFormValues();_.isUndefined(t.widgets)?t={}:(t=t.widgets,t=t[Object.keys(t)[0]]),this.model.setValues(t),this.model.set("raw",!0)}if(this.styles.stylesLoaded){var i={};try{i=this.getFormValues(".so-sidebar .so-visual-styles").style}catch(s){}this.model.set("style",i)}this.savingWidget=!1,e.refresh&&this.builder.model.refreshPanelsData(e.refreshArgs)},handleChangeValues:function(){this.savingWidget||this.loadForm()},saveHandler:function(){this.builder.addHistoryEntry("widget_edited"),this.closeDialog()},deleteHandler:function(){return this.model.trigger("visual_destroy"),this.closeDialog({silent:!0}),this.builder.model.refreshPanelsData(),!1},duplicateHandler:function(){return this.model.trigger("user_duplicate"),this.closeDialog({silent:!0}),this.builder.model.refreshPanelsData(),!1}})},{}],10:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=s.view.dialog.extend({builder:null,widgetTemplate:_.template(l("#siteorigin-panels-dialog-widgets-widget").html().panelsProcessTemplate()),filter:{},dialogClass:"so-panels-dialog-add-widget",events:{"click .so-close":"closeDialog","click .widget-type":"widgetClickHandler","keyup .so-sidebar-search":"searchHandler"},initializeDialog:function(){this.on("open_dialog",function(){this.filter.search="",this.filterWidgets(this.filter)},this),this.on("open_dialog_complete",function(){this.$(".so-sidebar-search").val("").focus(),this.balanceWidgetHeights()}),this.on("tab_click",this.tabClickHandler,this)},render:function(){this.renderDialog(this.parseDialogContent(l("#siteorigin-panels-dialog-widgets").html(),{})),_.each(panelsOptions.widgets,function(e){var t=l(this.widgetTemplate({title:e.title,description:e.description}));_.isUndefined(e.icon)&&(e.icon="dashicons dashicons-admin-generic"),l('<span class="widget-icon" />').addClass(e.icon).prependTo(t.find(".widget-type-wrapper")),t.data("class",e["class"]).appendTo(this.$(".widget-type-list"))},this);var e=this.$(".so-sidebar-tabs");_.each(panelsOptions.widget_dialog_tabs,function(t){l(this.dialogTabTemplate({title:t.title})).data({message:t.message,filter:t.filter}).appendTo(e)},this),this.initTabs();var t=this;l(window).resize(function(){t.balanceWidgetHeights()})},tabClickHandler:function(e){this.filter=e.parent().data("filter"),this.filter.search=this.$(".so-sidebar-search").val();var t=e.parent().data("message");return _.isEmpty(t)&&(t=""),this.$(".so-toolbar .so-status").html(t),this.filterWidgets(this.filter),!1},searchHandler:function(e){this.filter.search=l(e.target).val(),this.filterWidgets(this.filter)},filterWidgets:function(e){_.isUndefined(e)&&(e={}),_.isUndefined(e.groups)&&(e.groups=""),this.$(".widget-type-list .widget-type").each(function(){var t,i=l(this),s=i.data("class"),o=_.isUndefined(panelsOptions.widgets[s])?null:panelsOptions.widgets[s];t=_.isEmpty(e.groups)?!0:null===o||_.isEmpty(_.intersection(e.groups,panelsOptions.widgets[s].groups))?!1:!0,t&&(_.isUndefined(e.search)||""===e.search||-1===o.title.toLowerCase().indexOf(e.search.toLowerCase())&&(t=!1)),t?i.show():i.hide()}),this.balanceWidgetHeights()},widgetClickHandler:function(e){this.builder.addHistoryEntry("widget_added");var t=l(e.currentTarget),i=new s.model.widget({"class":t.data("class")});i.cell=this.builder.getActiveCell(),i.cell.widgets.add(i),this.closeDialog(),this.builder.model.refreshPanelsData()},balanceWidgetHeights:function(e){var t=[[]],i=null,s=Math.round(this.$(".widget-type").parent().width()/this.$(".widget-type").width());this.$(".widget-type").css("clear","none").filter(":visible").each(function(e,t){e%s===0&&0!==e&&l(t).css("clear","both")}),this.$(".widget-type-wrapper").css("height","auto").filter(":visible").each(function(e,s){var o=l(s);null!==i&&i.position().top!==o.position().top&&(t[t.length]=[]),i=o,t[t.length-1].push(o)}),_.each(t,function(e,t){var i=_.max(e.map(function(e){return e.height()}));_.each(e,function(e){e.height(i)})})}})},{}],11:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=function(){return this.each(function(){var e=jQuery(this),t=e.closest("form").find(".widget-id").val();if(_.isUndefined(t)||!(t.indexOf("__i__")>-1)){var i=new s.model.builder,o=new s.view.builder({model:i}),n=e.closest(".so-panels-dialog-wrapper").data("view");_.isUndefined(n)||(n.on("close_dialog",function(){i.refreshPanelsData()}),n.on("open_dialog_complete",function(){o.trigger("builder_resize")}),n.model.on("destroy",function(){i.emptyRows().destroy()}),o.setDialogParents(panelsOptions.loc.layout_widget,n));var a=Boolean(e.closest(".widget-content").length);o.render().attach({container:e,dialog:a,type:e.data("type")}).setDataField(e.find("input.panels-data")),a?(o.setDialogParents(panelsOptions.loc.layout_widget,o.dialog),e.find(".siteorigin-panels-display-builder").click(function(){o.dialog.openDialog()})):e.find(".siteorigin-panels-display-builder").parent().remove(),l(document).trigger("panels_setup",o)}})}},{}],12:[function(e,t,i){String.prototype.panelsProcessTemplate=function(){var e=this;return e=e.replace(/{{%/g,"<%"),e=e.replace(/%}}/g,"%>"),e=e.trim()};var s={};window.panels=s,window.siteoriginPanels=s,s.model={},s.model.widget=e("./model/widget"),s.model.cell=e("./model/cell"),s.model.row=e("./model/row"),s.model.builder=e("./model/builder"),s.model.historyEntry=e("./model/history-entry"),s.collection={},s.collection.widgets=e("./collection/widgets"),s.collection.cells=e("./collection/cells"),s.collection.rows=e("./collection/rows"),s.collection.historyEntries=e("./collection/history-entries"),s.view={},s.view.widget=e("./view/widget"),s.view.cell=e("./view/cell"),s.view.row=e("./view/row"),s.view.builder=e("./view/builder"),s.view.dialog=e("./view/dialog"),s.view.styles=e("./view/styles"),s.view.liveEditor=e("./view/live-editor"),s.dialog={},s.dialog.builder=e("./dialog/builder"),s.dialog.widgets=e("./dialog/widgets"),s.dialog.widget=e("./dialog/widget"),s.dialog.prebuilt=e("./dialog/prebuilt"),s.dialog.row=e("./dialog/row"),s.dialog.history=e("./dialog/history"),s.utils={},s.utils.menu=e("./utils/menu"),jQuery.fn.soPanelsSetupBuilderWidget=e("./jquery/setup-builder-widget"),jQuery(function(e){var t,i,s,l,o,n,a;if(e("#siteorigin-panels-metabox").length&&e("form#post").length)t=e("#siteorigin-panels-metabox"),i=e("#siteorigin-panels-metabox .siteorigin-panels-data-field"),s=e("form#post"),l="tinymce",o="#content",n=e("#post_ID").val(),a="editor_attached";else if(e(".siteorigin-panels-builder-form").length){var r=e(".siteorigin-panels-builder-form");t=r.find(".siteorigin-panels-builder-container"),i=r.find('input[name="panels_data"]'),s=r,o="#post_content",n=e("#panels-home-page").data("post-id"),a=r.data("type")}if(!_.isUndefined(t)){var d=window.siteoriginPanels,c=new d.model.builder,h={editorType:l,postId:n,editorId:o,builderType:a},u=new d.view.builder({model:c,config:h});u.render().attach({container:t,type:a}).setDataField(i).attachToEditor().addLiveEditor(n).addHistoryBrowser(),s.submit(function(e){c.refreshPanelsData()}),t.removeClass("so-panels-loading"),e(document).trigger("panels_setup",u,window.panels)}e(document).on("widget-added",function(t,i){e(i).find(".siteorigin-page-builder-widget").soPanelsSetupBuilderWidget()}),e("body").hasClass("wp-customizer")||e(function(){e(".siteorigin-page-builder-widget").soPanelsSetupBuilderWidget()})})},{"./collection/cells":1,"./collection/history-entries":2,"./collection/rows":3,"./collection/widgets":4,"./dialog/builder":5,"./dialog/history":6,"./dialog/prebuilt":7,"./dialog/row":8,"./dialog/widget":9,"./dialog/widgets":10,"./jquery/setup-builder-widget":11,"./model/builder":13,"./model/cell":14,"./model/history-entry":15,"./model/row":16,"./model/widget":17,"./utils/menu":18,"./view/builder":19,"./view/cell":20,"./view/dialog":21,"./view/live-editor":22,"./view/row":23,"./view/styles":24,"./view/widget":25}],13:[function(e,t,i){t.exports=Backbone.Model.extend({layoutPosition:{BEFORE:"before",AFTER:"after",REPLACE:"replace"},rows:{},defaults:{data:{widgets:[],grids:[],grid_cells:[]}},
2
+ initialize:function(){this.rows=new panels.collection.rows},addRow:function(e,t){t=_.extend({noAnimate:!1},t);var i=new panels.model.row({collection:this.rows});return i.setCells(e),i.builder=this,this.rows.add(i,t),i},loadPanelsData:function(e,t){t===this.layoutPosition.BEFORE?e=this.concatPanelsData(e,this.getPanelsData()):t===this.layoutPosition.AFTER&&(e=this.concatPanelsData(this.getPanelsData(),e)),this.emptyRows(),this.set("data",JSON.parse(JSON.stringify(e)),{silent:!0});var i=[];if(_.isUndefined(e.grid_cells))return void this.trigger("load_panels_data");for(var s,l=0;l<e.grid_cells.length;l++)s=parseInt(e.grid_cells[l].grid),_.isUndefined(i[s])&&(i[s]=[]),i[s].push(parseFloat(e.grid_cells[l].weight));var o=this;_.each(i,function(t,i){var s=o.addRow(t,{noAnimate:!0});_.isUndefined(e.grids[i].style)||s.set("style",e.grids[i].style)}),_.isUndefined(e.widgets)||(_.each(e.widgets,function(e){try{var t=null;_.isUndefined(e.panels_info)?(t=e.info,delete e.info):(t=e.panels_info,delete e.panels_info);var i=o.rows.at(parseInt(t.grid)),s=i.cells.at(parseInt(t.cell)),l=new panels.model.widget({"class":t["class"],values:e});_.isUndefined(t.style)||l.set("style",t.style),l.cell=s,s.widgets.add(l,{noAnimate:!0})}catch(n){}}),this.trigger("load_panels_data"))},concatPanelsData:function(e,t){if(_.isUndefined(t)||_.isUndefined(t.grids)||_.isEmpty(t.grids)||_.isUndefined(t.grid_cells)||_.isEmpty(t.grid_cells))return e;if(_.isUndefined(e)||_.isUndefined(e.grids)||_.isEmpty(e.grids))return t;var i=e.grids.length,s=_.isUndefined(e.widgets)?0:e.widgets.length,l={grids:[],grid_cells:[],widgets:[]};l.grids=e.grids.concat(t.grids),_.isUndefined(e.grid_cells)||(l.grid_cells=e.grid_cells.slice()),_.isUndefined(e.widgets)||(l.widgets=e.widgets.slice());var o;for(o=0;o<t.grid_cells.length;o++){var n=t.grid_cells[o];n.grid=parseInt(n.grid)+i,l.grid_cells.push(n)}if(!_.isUndefined(t.widgets))for(o=0;o<t.widgets.length;o++){var a=t.widgets[o];a.panels_info.grid=parseInt(a.panels_info.grid)+i,a.panels_info.id=parseInt(a.panels_info.id)+s,l.widgets.push(a)}return l},getPanelsData:function(){var e={widgets:[],grids:[],grid_cells:[]},t=0;return this.rows.each(function(i,s){i.cells.each(function(i,l){i.widgets.each(function(i,o){var n=_.extend(_.clone(i.get("values")),{panels_info:{"class":i.get("class"),raw:i.get("raw"),grid:s,cell:l,id:t++,style:i.get("style")}});e.widgets.push(n)}),e.grid_cells.push({grid:s,weight:i.get("weight")})}),e.grids.push({cells:i.cells.length,style:i.get("style")})}),e},refreshPanelsData:function(e){e=_.extend({silent:!1},e);var t=this.get("data"),i=this.getPanelsData();this.set("data",i,{silent:!0}),e.silent||JSON.stringify(i)===JSON.stringify(t)||(this.trigger("change"),this.trigger("change:data"),this.trigger("refresh_panels_data",i,e))},emptyRows:function(){return _.invoke(this.rows.toArray(),"destroy"),this.rows.reset(),this},isValidLayoutPosition:function(e){return e===this.layoutPosition.BEFORE||e===this.layoutPosition.AFTER||e===this.layoutPosition.REPLACE}})},{}],14:[function(e,t,i){t.exports=Backbone.Model.extend({widgets:{},row:null,defaults:{weight:0},indexes:null,initialize:function(){this.widgets=new panels.collection.widgets,this.on("destroy",this.onDestroy,this)},onDestroy:function(){_.invoke(this.widgets.toArray(),"destroy"),this.widgets.reset()},clone:function(e,t){_.isUndefined(e)&&(e=this.row),t=_.extend({cloneWidgets:!0},t);var i=new this.constructor(this.attributes);return i.set("collection",e.cells,{silent:!0}),i.row=e,t.cloneWidgets&&this.widgets.each(function(e){i.widgets.add(e.clone(i,t),{silent:!0})}),i}})},{}],15:[function(e,t,i){t.exports=Backbone.Model.extend({defaults:{text:"",data:"",time:null,count:1}})},{}],16:[function(e,t,i){t.exports=Backbone.Model.extend({cells:{},builder:null,defaults:{style:{}},indexes:null,initialize:function(){this.cells=new panels.collection.cells,this.on("destroy",this.onDestroy,this)},setCells:function(e){var t=this;if(_.isEmpty(this.cells))_.each(e,function(e){var i=new panels.model.cell({weight:e,collection:t.cells});i.row=t,t.cells.add(i)});else{if(e.length>this.cells.length)for(var i=this.cells.length;i<e.length;i++){var s=new panels.model.cell({weight:e[e.length+i],collection:t.cells});s.row=this,t.cells.add(s)}else if(e.length<this.cells.length){var l=this.cells.at(e.length-1);_.each(this.cells.slice(e.length,this.cells.length),function(e){for(var t=e.widgets.models.slice(0),i=0;i<t.length;i++)t[i].moveToCell(l,{silent:!1});e.destroy()})}this.cells.each(function(t,i){t.set("weight",e[i])})}this.reweightCells()},reweightCells:function(){var e=0;this.cells.each(function(t){e+=t.get("weight")}),this.cells.each(function(t){t.set("weight",t.get("weight")/e)}),this.trigger("reweight_cells")},onDestroy:function(){_.invoke(this.cells.toArray(),"destroy"),this.cells.reset()},clone:function(e,t){_.isUndefined(e)&&(e=this.builder),t=_.extend({cloneCells:!0},t);var i=new this.constructor(this.attributes);return i.set("collection",e.rows,{silent:!0}),i.builder=e,t.cloneCells&&this.cells.each(function(e){i.cells.add(e.clone(i,t),{silent:!0})}),i}})},{}],17:[function(e,t,i){t.exports=Backbone.Model.extend({cell:null,defaults:{"class":null,missing:!1,values:{},raw:!1,styles:{}},indexes:null,initialize:function(){var e=this.get("class");(_.isUndefined(panelsOptions.widgets[e])||!panelsOptions.widgets[e].installed)&&this.set("missing",!0)},getWidgetField:function(e){return _.isUndefined(panelsOptions.widgets[this.get("class")])?"title"===e||"description"===e?panelsOptions.loc.missing_widget[e]:"":panelsOptions.widgets[this.get("class")][e]},moveToCell:function(e,t){return t=_.extend({silent:!0},t),this.cell.cid===e.cid?!1:(this.cell=e,this.collection.remove(this,t),e.widgets.add(this,t),!0)},triggerEdit:function(){this.trigger("user_edit",this)},triggerDuplicate:function(){this.trigger("user_duplicate",this)},setValues:function(e){var t=!1;JSON.stringify(e)!==JSON.stringify(this.get("values"))&&(t=!0),this.set("values",e,{silent:!0}),t&&(this.trigger("change",this),this.trigger("change:values"))},clone:function(e,t){_.isUndefined(e)&&(e=this.cell);var i=new this.constructor(this.attributes),s=JSON.parse(JSON.stringify(this.get("values"))),l=function(e){return _.each(e,function(t,i){_.isString(i)&&"_"===i[0]?delete e[i]:_.isObject(e[i])&&l(e[i])}),e};return s=l(s),"SiteOrigin_Panels_Widgets_Layout"===this.get("class")&&(s.builder_id=Math.random().toString(36).substr(2)),i.set("values",s,{silent:!0}),i.set("collection",e.widgets,{silent:!0}),i.cell=e,i.isDuplicate=!0,i},getTitle:function(){var e=panelsOptions.widgets[this.get("class")];if(_.isUndefined(e))return this.get("class").replace(/_/g," ");if(!_.isUndefined(e.panels_title)&&e.panels_title===!1)return panelsOptions.widgets[this.get("class")].description;var t=this.get("values"),i=["title","text"];for(var s in t)t.hasOwnProperty(s)&&i.push(s);i=_.uniq(i);for(var l in i)if(!_.isUndefined(t[i[l]])&&_.isString(t[i[l]])&&""!==t[i[l]]&&"on"!==t[i[l]]&&"_"!==i[l][0]&&!jQuery.isNumeric(t[i[l]])){var o=t[i[l]];o=o.replace(/<\/?[^>]+(>|$)/g,"");var n=o.split(" ");return n=n.slice(0,20),n.join(" ")}return this.getWidgetField("description")}})},{}],18:[function(e,t,i){var s=(window.panels,jQuery);t.exports=Backbone.View.extend({wrapperTemplate:_.template(s("#siteorigin-panels-context-menu").html().panelsProcessTemplate()),sectionTemplate:_.template(s("#siteorigin-panels-context-menu-section").html().panelsProcessTemplate()),contexts:[],active:!1,events:{"keyup .so-search-wrapper input":"searchKeyUp"},initialize:function(){this.listenContextMenu(),this.render(),this.attach()},listenContextMenu:function(){var e=this;s(window).on("contextmenu",function(t){return e.active&&!e.isOverEl(e.$el,t)?(e.closeMenu(),e.active=!1,t.preventDefault(),!1):e.active?!0:(e.active=!1,e.trigger("activate_context",t,e),void(e.active&&(t.preventDefault(),e.openMenu({left:t.pageX,top:t.pageY}))))})},render:function(){this.setElement(this.wrapperTemplate())},attach:function(){this.$el.appendTo("body")},openMenu:function(e){this.trigger("open_menu"),s(window).on("keyup",{menu:this},this.keyboardListen),s(window).on("click",{menu:this},this.clickOutsideListen),this.$el.css("max-height",s(window).height()-20),e.left+this.$el.outerWidth()+10>=s(window).width()&&(e.left=s(window).width()-this.$el.outerWidth()-10),e.left<=0&&(e.left=10),e.top+this.$el.outerHeight()-s(window).scrollTop()+10>=s(window).height()&&(e.top=s(window).height()+s(window).scrollTop()-this.$el.outerHeight()-10),e.left<=0&&(e.left=10),this.$el.css({left:e.left+1,top:e.top+1}).show(),this.$(".so-search-wrapper input").focus()},closeMenu:function(){this.trigger("close_menu"),s(window).off("keyup",this.keyboardListen),s(window).off("click",this.clickOutsideListen),this.active=!1,this.$el.empty().hide()},keyboardListen:function(e){var t=e.data.menu;switch(e.which){case 27:t.closeMenu()}},clickOutsideListen:function(e){var t=e.data.menu;3!==e.which&&t.$el.is(":visible")&&!t.isOverEl(t.$el,e)&&t.closeMenu()},addSection:function(e,t,i){var l=this;e=_.extend({display:5,defaultDisplay:!1,search:!0,sectionTitle:"",searchPlaceholder:"",titleKey:"title"},e);var o=s(this.sectionTemplate({settings:e,items:t}));this.$el.append(o),o.find(".so-item:not(.so-confirm)").click(function(){var e=s(this);i(e.data("key")),l.closeMenu()}),o.find(".so-item.so-confirm").click(function(){var e=s(this);return e.hasClass("so-confirming")?(i(e.data("key")),void l.closeMenu()):(e.data("original-text",e.html()).addClass("so-confirming").html('<span class="dashicons dashicons-yes"></span> '+panelsOptions.loc.dropdown_confirm),void setTimeout(function(){e.removeClass("so-confirming"),e.html(e.data("original-text"))},2500))}),o.data("settings",e).find(".so-search-wrapper input").trigger("keyup"),this.active=!0},searchKeyUp:function(e){var t=s(e.currentTarget),i=t.closest(".so-section"),l=i.data("settings");if(38===e.which||40===e.which){var o=i.find("ul li:visible"),n=o.filter(".so-active").eq(0);if(n.length){o.removeClass("so-active");var a=o.index(n);38===e.which?n=0>a-1?o.last():o.eq(a-1):40===e.which&&(n=a+1>=o.length?o.first():o.eq(a+1))}else 38===e.which?n=o.last():40===e.which&&(n=o.first());return n.addClass("so-active"),!1}if(13===e.which)return 1===i.find("ul li:visible").length?(i.find("ul li:visible").trigger("click"),!1):(i.find("ul li.so-active:visible").trigger("click"),!1);if(""===t.val())if(l.defaultDisplay){i.find(".so-item").hide();for(var r=0;r<l.defaultDisplay.length;r++)i.find('.so-item[data-key="'+l.defaultDisplay[r]+'"]').show()}else i.find(".so-item").show();else i.find(".so-item").hide().each(function(){var e=s(this);-1!==e.html().toLowerCase().indexOf(t.val().toLowerCase())&&e.show()});i.find(".so-item:visible:gt("+(l.display-1)+")").hide(),0===i.find(".so-item:visible").length&&""!==t.val()?i.find(".so-no-results").show():i.find(".so-no-results").hide()},isOverEl:function(e,t){var i=[[e.offset().left,e.offset().top],[e.offset().left+e.outerWidth(),e.offset().top+e.outerHeight()]];return t.pageX>=i[0][0]&&t.pageX<=i[1][0]&&t.pageY>=i[0][1]&&t.pageY<=i[1][1]}})},{}],19:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({editorType:null,postId:null,editorId:null,template:_.template(l("#siteorigin-panels-builder").html().panelsProcessTemplate()),dialogs:{},rowsSortable:null,dataField:!1,currentData:"",attachedToEditor:!1,liveEditor:void 0,menu:!1,builderType:"",events:{"click .so-tool-button.so-widget-add":"displayAddWidgetDialog","click .so-tool-button.so-row-add":"displayAddRowDialog","click .so-tool-button.so-prebuilt-add":"displayAddPrebuiltDialog","click .so-tool-button.so-history":"displayHistoryDialog","click .so-tool-button.so-live-editor":"displayLiveEditor"},rows:null,initialize:function(e){var t=this;return _.isUndefined(e.config)||(this.editorType=e.config.editorType,this.editorId=e.config.editorId,this.builderType=e.config.builderType,this.postId=e.config.postId),this.dialogs={widgets:new s.dialog.widgets,row:new s.dialog.row,prebuilt:new s.dialog.prebuilt},_.each(this.dialogs,function(e,i,s){s[i].setBuilder(t)}),this.dialogs.row.setRowDialogType("create"),this.model.rows.on("add",this.onAddRow,this),l(window).resize(function(e){e.target===window&&t.trigger("builder_resize")}),this.model.on("change:data load_panels_data",this.storeModelData,this),this.on("content_change",this.handleContentChange,this),this.on("display_builder",this.handleDisplayBuilder,this),this.on("builder_rendered builder_resize",this.handleBuilderSizing,this),this.model.on("change:data load_panels_data",this.toggleWelcomeDisplay,this),this.menu=new s.utils.menu({}),this.menu.on("activate_context",this.activateContextMenu,this),this},render:function(){return this.setElement(this.template()),this.$el.attr("id","siteorigin-panels-builder-"+this.cid).addClass("so-builder-container"),this.trigger("builder_rendered"),this},attach:function(e){return e=_.extend({type:"",container:!1,dialog:!1},e),e.dialog?(this.dialog=new s.dialog.builder,this.dialog.builder=this):(this.$el.appendTo(e.container),this.metabox=e.container.closest(".postbox"),this.initSortable(),this.trigger("attached_to_container",e.container)),this.builderType=e.type,this},attachToEditor:function(){if("tinymce"!==this.editorType)return this;this.attachedToEditor=!0;var e=this.metabox,t=this;l("#wp-content-wrap .wp-editor-tabs").find(".wp-switch-editor").click(function(e){e.preventDefault(),l("#wp-content-editor-container, #post-status-info").show(),l("#wp-content-wrap").removeClass("panels-active"),l("#content-resize-handle").show(),t.trigger("hide_builder")}).end().append(l('<a id="content-panels" class="hide-if-no-js wp-switch-editor switch-panels">'+e.find(".hndle span").html()+"</a>").click(function(i){i.preventDefault();jQuery(this);l("#wp-content-wrap, #post-status-info").hide(),e.show().find("> .inside").show(),l(window).resize(),l(document).scroll(),t.trigger("display_builder")})),e.find(".so-switch-to-standard").click(function(i){i.preventDefault(),confirm(panelsOptions.loc.confirm_stop_builder)&&(t.addHistoryEntry("back_to_editor"),t.model.loadPanelsData(!1),l("#wp-content-wrap, #post-status-info").show(),e.hide(),l(window).resize())}).show(),e.insertAfter("#wp-content-wrap").hide().addClass("attached-to-editor");var i=this.model.get("data");_.isEmpty(i.widgets)&&_.isEmpty(i.grids)||l("#content-panels.switch-panels").click();var s=function(){var e=t.$(".so-builder-toolbar");if(t.$el.hasClass("so-display-narrow"))return e.css({top:0,left:0,width:"100%",position:"absolute"}),void t.$el.css("padding-top",e.outerHeight());var i=l(window).scrollTop()-t.$el.offset().top;"fixed"===l("#wpadminbar").css("position")&&(i+=l("#wpadminbar").outerHeight());var s={top:0,bottom:t.$el.outerHeight()-e.outerHeight()+20};i>s.top&&i<s.bottom?"fixed"!==e.css("position")&&e.css({top:l("#wpadminbar").outerHeight(),left:t.$el.offset().left,width:t.$el.outerWidth(),position:"fixed"}):e.css({top:Math.min(Math.max(i,0),t.$el.outerHeight()-e.outerHeight()+20),left:0,width:"100%",position:"absolute"}),t.$el.css("padding-top",e.outerHeight())};return this.on("builder_resize",s,this),l(document).scroll(s),s(),this},initSortable:function(){var e=(this.$el,this);this.rowsSortable=this.$(".so-rows-container").sortable({appendTo:"#wpwrap",items:".so-row-container",handle:".so-row-move",axis:"y",tolerance:"pointer",scroll:!1,stop:function(t){e.addHistoryEntry("row_moved"),e.sortCollections()}})},refreshSortable:function(){_.isNull(this.rowsSortable)||this.rowsSortable.sortable("refresh")},setDataField:function(e,t){if(t=_.extend({load:!0},t),this.dataField=e,this.dataField.data("builder",this),t.load&&""!==e.val()){var i=this.dataField.val();try{i=JSON.parse(i)}catch(s){i={}}this.model.loadPanelsData(i),this.currentData=i,this.toggleWelcomeDisplay(),this.sortCollections()}return this},storeModelData:function(){var e=JSON.stringify(this.model.get("data"));l(this.dataField).val()!==e&&(l(this.dataField).val(e),l(this.dataField).trigger("change"),this.trigger("content_change"))},onAddRow:function(e,t,i){i=_.extend({noAnimate:!1},i);var l=new s.view.row({model:e});l.builder=this,l.render(),_.isUndefined(i.at)||t.length<=1?l.$el.appendTo(this.$(".so-rows-container")):l.$el.insertAfter(this.$(".so-rows-container .so-row-container").eq(i.at-1)),i.noAnimate===!1&&l.visualCreate(),this.refreshSortable(),l.resize()},displayAddWidgetDialog:function(){this.dialogs.widgets.openDialog()},displayAddRowDialog:function(){this.dialogs.row.openDialog(),this.dialogs.row.setRowModel()},displayAddPrebuiltDialog:function(){this.dialogs.prebuilt.openDialog()},displayHistoryDialog:function(){this.dialogs.history.openDialog()},getActiveCell:function(e){if(e=_.extend({createCell:!0,defaultPosition:"first"},e),0===this.$(".so-cells .cell").length){if(!e.createCell)return null;this.model.addRow([1],{noAnimate:!0})}var t=this.$(".so-cells .cell.cell-selected");return 0===t.length&&(t="last"===e.defaultPosition?this.$(".so-cells .cell").first():this.$(".so-cells .cell").last()),t.data("view").model},sortCollections:function(){this.$(".so-widget").each(function(e){var t=l(this);t.data("view").model.indexes={builder:e,cell:t.index()}}),this.$(".so-cells .cell").each(function(e){var t=l(this);t.data("view").model.indexes={builder:e,row:t.index()}}),this.$(".so-row-container").each(function(e){var t=l(this);t.data("view").model.indexes={builder:e}}),this.model.rows.sort(),this.model.rows.each(function(e){e.cells.each(function(e){e.widgets.sort()})}),this.model.refreshPanelsData()},addLiveEditor:function(e){return this.liveEditor=new s.view.liveEditor({builder:this}),this.liveEditor.setPostId(e),this.liveEditor.hasPreviewUrl()&&this.$(".so-builder-toolbar .so-live-editor").show(),this},displayLiveEditor:function(){_.isUndefined(this.liveEditor)||this.liveEditor.open()},addHistoryBrowser:function(){this.dialogs.history=new s.dialog.history,this.dialogs.history.builder=this,this.dialogs.history.entries.builder=this.model,this.dialogs.history.setRevertEntry(this.model),this.$(".so-builder-toolbar .so-history").show()},addHistoryEntry:function(e,t){_.isUndefined(t)&&(t=null),_.isUndefined(this.dialogs.history)||this.dialogs.history.entries.addEntry(e,t)},handleContentChange:function(){panelsOptions.copy_content&&this.attachedToEditor&&this.$el.is(":visible")&&l.post(panelsOptions.ajaxurl,{action:"so_panels_builder_content",panels_data:JSON.stringify(this.model.getPanelsData()),post_id:this.postId},function(e){var t=l("<div />").html(e);t.find("div").each(function(){var e=l(this).contents();l(this).replaceWith(e)}),e=t.html().replace(/[\r\n]+/g,"\n").replace(/\n\s+/g,"\n").trim(),this.updateEditorContent(e)}.bind(this))},updateEditorContent:function(e){if("tinymce"!==this.editorType||_.isUndefined(tinyMCE)||_.isNull(tinyMCE.get("content"))){var t=l(this.editorId);t.val(e).trigger("change").trigger("keyup")}else{var i=tinyMCE.get("content");i.setContent(e),i.fire("change"),i.fire("keyup")}this.triggerYoastSeoChange()},triggerYoastSeoChange:function(){if(l("#yoast_wpseo_focuskw_text_input").length){var e,t=document.getElementById("yoast_wpseo_focuskw_text_input");document.createEvent?(e=document.createEvent("HTMLEvents"),e.initEvent("keyup",!0,!0)):(e=document.createEventObject(),e.eventType="keyup"),e.eventName="keyup",document.createEvent?t.dispatchEvent(e):t.fireEvent("on"+e.eventType,e)}},handleDisplayBuilder:function(){var e,t="";if(_.isUndefined(tinyMCE)||(e=tinyMCE.get("content")),t=e&&_.isFunction(e.getContent)?e.getContent():l("textarea#content").val(),_.isEmpty(this.model.get("data"))&&""!==t){if(!confirm(panelsOptions.loc.confirm_use_builder))return;var i="";if(_.isUndefined(panelsOptions.widgets.SiteOrigin_Widget_Editor_Widget)?_.isUndefined(panelsOptions.widgets.WP_Widget_Text)||(i="WP_Widget_Text"):i="SiteOrigin_Widget_Editor_Widget",""===i)return;this.model.loadPanelsData({grid_cells:[{grid:0,weight:1}],grids:[{cells:1}],widgets:[{filter:"1",text:t,title:"",type:"visual",panels_info:{"class":i,raw:!1,grid:0,cell:0}}]}),this.model.trigger("change"),this.model.trigger("change:data")}},handleBuilderSizing:function(){var e=this.$el.width();return e?void(480>e?this.$el.addClass("so-display-narrow"):this.$el.removeClass("so-display-narrow")):this},setDialogParents:function(e,t){_.each(this.dialogs,function(i,s,l){l[s].setParent(e,t)}),this.on("add_dialog",function(i){i.setParent(e,t)},this)},toggleWelcomeDisplay:function(){this.model.rows.isEmpty()?this.$(".so-panels-welcome-message").show():this.$(".so-panels-welcome-message").hide()},activateContextMenu:function(e,t){var i=this,s=l(".siteorigin-panels-builder:visible").sort(function(e,t){return l(e).zIndex()>l(t).zIndex()?1:-1}).last();if(i.$el.is(s)){var o=l([]).add(i.$(".so-rows-container > .so-row-container")).add(i.$(".so-cells > .cell")).add(i.$(".cell-wrapper > .so-widget")).filter(function(i){return t.isOverEl(l(this),e)}),n=o.last().data("view");void 0!==n&&void 0!==n.buildContextualMenu&&n.buildContextualMenu(e,t)}},lockPageScroll:function(){if("hidden"!==l("body").css("overflow")){var e=[self.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft,self.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop];l("body").data({"scroll-position":e}).css("overflow","hidden"),window.scrollTo(e[0],e[1])}},unlockPageScroll:function(){if("hidden"===l("body").css("overflow")&&!l(".so-panels-dialog-wrapper").is(":visible")&&!l(".so-panels-live-editor").is(":visible")){l("body").css("overflow","visible");var e=l("body").data("scroll-position");window.scrollTo(e[0],e[1])}}})},{}],20:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({template:_.template(l("#siteorigin-panels-builder-cell").html().panelsProcessTemplate()),events:{"click .cell-wrapper":"handleCellClick"},row:null,widgetSortable:null,initialize:function(){this.model.widgets.on("add",this.onAddWidget,this)},render:function(){var e={weight:this.model.get("weight"),totalWeight:this.row.model.cells.totalWeight()};this.setElement(this.template(e)),this.$el.data("view",this);var t=this;return this.model.widgets.each(function(e){var i=new s.view.widget({model:e});i.cell=t,i.render(),i.$el.appendTo(t.$(".widgets-container"))}),this.initSortable(),this.initResizable(),this},initSortable:function(){var e=this,t=e.row.builder.$el.attr("id");this.widgetSortable=this.$(".widgets-container").sortable({placeholder:"so-widget-sortable-highlight",connectWith:"#"+t+" .so-cells .cell .widgets-container",tolerance:"pointer",scroll:!1,over:function(t,i){e.row.builder.trigger("widget_sortable_move")},stop:function(t,i){e.row.builder.addHistoryEntry("widget_moved");var s=l(i.item).data("view"),o=l(i.item).closest(".cell").data("view");s.model.moveToCell(o.model),s.cell=o,e.row.builder.sortCollections()},helper:function(e,t){var i=t.clone().css({width:t.outerWidth(),"z-index":1e4,position:"fixed"}).addClass("widget-being-dragged").appendTo("body");return t.outerWidth()>720&&i.animate({"margin-left":e.pageX-t.offset().left-240,width:480},"fast"),i}})},refreshSortable:function(){this.widgetSortable.sortable("refresh")},initResizable:function(){var e,t=this.$(".resize-handle").css("position","absolute"),i=this.row.$el,s=this;t.draggable({axis:"x",containment:i,start:function(t,i){if(e=s.$el.prev().data("view"),!_.isUndefined(e)){var o=s.$el.clone().appendTo(i.helper).css({position:"absolute",top:"0",width:s.$el.outerWidth(),left:5,height:s.$el.outerHeight()});o.find(".resize-handle").remove();var n=e.$el.clone().appendTo(i.helper).css({position:"absolute",top:"0",width:e.$el.outerWidth(),right:5,height:e.$el.outerHeight()});n.find(".resize-handle").remove(),l(this).data({newCellClone:o,prevCellClone:n})}},drag:function(i,o){var n=s.row.$el.width()+10,a=s.model.get("weight")-(o.position.left+t.outerWidth()/2)/n,r=e.model.get("weight")+(o.position.left+t.outerWidth()/2)/n;l(this).data("newCellClone").css("width",n*a).find(".preview-cell-weight").html(Math.round(1e3*a)/10),l(this).data("prevCellClone").css("width",n*r).find(".preview-cell-weight").html(Math.round(1e3*r)/10)},stop:function(i,o){l(this).data("newCellClone").remove(),l(this).data("prevCellClone").remove();var n=s.row.$el.width()+10,a=s.model.get("weight")-(o.position.left+t.outerWidth()/2)/n,r=e.model.get("weight")+(o.position.left+t.outerWidth()/2)/n;a>.02&&r>.02&&(s.row.builder.addHistoryEntry("cell_resized"),s.model.set("weight",a),e.model.set("weight",r),s.row.resize()),o.helper.css("left",-t.outerWidth()/2),s.row.builder.model.refreshPanelsData()}})},onAddWidget:function(e,t,i){i=_.extend({noAnimate:!1},i);var l=new s.view.widget({model:e});l.cell=this,_.isUndefined(e.isDuplicate)&&(e.isDuplicate=!1),l.render({loadForm:e.isDuplicate}),_.isUndefined(i.at)||t.length<=1?l.$el.appendTo(this.$(".widgets-container")):l.$el.insertAfter(this.$(".widgets-container .so-widget").eq(i.at-1)),i.noAnimate===!1&&l.visualCreate(),this.refreshSortable(),this.row.resize()},handleCellClick:function(e){this.$el.closest(".so-rows-container").find(".so-cells .cell").removeClass("cell-selected");l(e.target).parent().addClass("cell-selected")},buildContextualMenu:function(e,t){var i=this;t.addSection({sectionTitle:panelsOptions.loc.contextual.add_widget_cell,searchPlaceholder:panelsOptions.loc.contextual.search_widgets,defaultDisplay:panelsOptions.contextual.default_widgets},panelsOptions.widgets,function(e){i.row.builder.addHistoryEntry("widget_added");var t=new s.model.widget({"class":e});t.cell=i.model,t.cell.widgets.add(t),i.row.builder.model.refreshPanelsData()}),this.row.buildContextualMenu(e,t)}})},{}],21:[function(e,t,i){var s=(window.panels,jQuery);t.exports=Backbone.View.extend({dialogTemplate:_.template(s("#siteorigin-panels-dialog").html().panelsProcessTemplate()),dialogTabTemplate:_.template(s("#siteorigin-panels-dialog-tab").html().panelsProcessTemplate()),tabbed:!1,rendered:!1,builder:!1,className:"so-panels-dialog-wrapper",dialogClass:"",parentDialog:!1,dialogOpen:!1,events:{"click .so-close":"closeDialog","click .so-nav.so-previous":"navToPrevious","click .so-nav.so-next":"navToNext"},initialize:function(){this.once("open_dialog",this.render),this.once("open_dialog",this.attach),this.once("open_dialog",this.setDialogClass),this.trigger("initialize_dialog",this),_.isUndefined(this.initializeDialog)||this.initializeDialog()},getNextDialog:function(){return null},getPrevDialog:function(){return null},setDialogClass:function(){""!==this.dialogClass&&this.$(".so-panels-dialog").addClass(this.dialogClass)},setBuilder:function(e){return this.builder=e,e.trigger("add_dialog",this,this.builder),this},attach:function(){return this.$el.appendTo("body"),this},parseDialogContent:function(e,t){t=_.extend({cid:this.cid},t);var i=s(_.template(e.panelsProcessTemplate())(t)),l={title:i.find(".title").html(),buttons:i.find(".buttons").html(),content:i.find(".content").html()};return i.has(".left-sidebar")&&(l.left_sidebar=i.find(".left-sidebar").html()),i.has(".right-sidebar")&&(l.right_sidebar=i.find(".right-sidebar").html()),l},renderDialog:function(e){if(this.$el.html(this.dialogTemplate(e)).hide(),this.$el.data("view",this),this.$el.addClass("so-panels-dialog-wrapper"),this.parentDialog!==!1){var t=this,i=s('<h3 class="so-parent-link"></h3>').html(this.parentDialog.text+'<div class="so-separator"></div>');i.click(function(e){e.preventDefault(),t.closeDialog(),t.parentDialog.openDialog()}),this.$(".so-title-bar").prepend(i)}return this},initTabs:function(){var e=this.$(".so-sidebar-tabs li a");if(0===e.length)return this;var t=this;return e.click(function(e){e.preventDefault();var i=jQuery(this);t.$(".so-sidebar-tabs li").removeClass("tab-active"),t.$(".so-content .so-content-tabs > *").hide(),i.parent().addClass("tab-active");var s=i.attr("href");if(!_.isUndefined(s)&&"#"===s.charAt(0)){var l=s.split("#")[1];t.$(".so-content .so-content-tabs .tab-"+l).show()}t.trigger("tab_click",i)}),this.$(".so-sidebar-tabs li a").first().click(),this},initToolbar:function(){var e=this.$(".so-toolbar .so-buttons .so-toolbar-button");e.click(function(e){e.preventDefault(),this.trigger("button_click",s(e.currentTarget))}.bind(this));var t=this.$(".so-toolbar .so-buttons .so-dropdown-button");t.click(function(e){e.preventDefault();var t=s(e.currentTarget),i=t.siblings(".so-dropdown-links-wrapper");i.is(".hidden")?i.removeClass("hidden"):i.addClass("hidden")}.bind(this)),s("html").click(function(e){this.$(".so-dropdown-links-wrapper").not(".hidden").each(function(t,i){var l=s(i),o=s(e.target);0!==o.length&&(o.is(".so-needs-confirm")&&!o.is(".so-confirmed")||o.is(".so-dropdown-button"))||l.addClass("hidden")})}.bind(this))},setupDialog:function(){this.openDialog(),this.closeDialog()},refreshDialogNav:function(){this.$(".so-title-bar .so-nav").show().removeClass("so-disabled");var e=this.getNextDialog(),t=this.$(".so-title-bar .so-next"),i=this.getPrevDialog(),s=this.$(".so-title-bar .so-previous");null===e?t.hide():e===!1&&t.addClass("so-disabled"),null===i?s.hide():i===!1&&s.addClass("so-disabled")},openDialog:function(e){e=_.extend({silent:!1},e),e.silent||this.trigger("open_dialog"),this.dialogOpen=!0,this.refreshDialogNav(),this.builder.lockPageScroll(),s(window).on("keyup",this.keyboardListen),this.$el.show(),e.silent||(this.trigger("open_dialog_complete"),this.builder.trigger("open_dialog",this))},closeDialog:function(e){e=_.extend({silent:!1},e),e.silent||this.trigger("close_dialog"),this.dialogOpen=!1,this.$el.hide(),this.builder.unlockPageScroll(),s(window).off("keyup",this.keyboardListen),e.silent||(this.trigger("close_dialog_complete"),this.builder.trigger("close_dialog",this))},keyboardListen:function(e){27===e.which&&s(".so-panels-dialog-wrapper .so-close").trigger("click")},navToPrevious:function(){this.closeDialog();var e=this.getPrevDialog();null!==e&&e!==!1&&e.openDialog()},navToNext:function(){this.closeDialog();var e=this.getNextDialog();null!==e&&e!==!1&&e.openDialog()},getFormValues:function(e){_.isUndefined(e)&&(e=".so-content");var t,i=this.$(e),l={};return i.find("[name]").each(function(){var e=jQuery(this),i=/([A-Za-z_]+)\[(.*)\]/.exec(e.attr("name"));if(void 0===i)return!0;_.isUndefined(i[2])?t=e.attr("name"):(t=i[2].split("]["),t.unshift(i[1])),t=t.map(function(e){return!isNaN(parseFloat(e))&&isFinite(e)?parseInt(e):e});var o=l,n=null,a=_.isString(e.attr("type"))?e.attr("type").toLowerCase():!1;if("checkbox"===a)n=e.is(":checked")?""!==e.val()?e.val():!0:null;else if("radio"===a){if(!e.is(":checked"))return;n=e.val()}else if("TEXTAREA"===e.prop("tagName")&&e.hasClass("wp-editor-area")){var r=null;_.isUndefined(tinyMCE)||(r=tinyMCE.get(e.attr("id"))),n=null!==r&&_.isFunction(r.getContent)&&!r.isHidden()?r.getContent():e.val()}else if("SELECT"===e.prop("tagName")){var d=e.find("option:selected");1===d.length?n=e.find("option:selected").val():d.length>1&&(n=_.map(e.find("option:selected"),function(e,t){return s(e).val()}))}else n=e.val();if(!_.isUndefined(e.data("panels-filter")))switch(e.data("panels-filter")){case"json_parse":try{n=JSON.parse(n)}catch(c){n=""}}if(null!==n)for(var h=0;h<t.length;h++)h===t.length-1?""===t[h]?o.push(n):o[t[h]]=n:(_.isUndefined(o[t[h]])&&(""===t[h+1]?o[t[h]]=[]:o[t[h]]={}),o=o[t[h]])}),l},setStatusMessage:function(e,t){this.$(".so-toolbar .so-status").html(e),!_.isUndefined(t)&&t&&this.$(".so-toolbar .so-status").addClass("so-panels-loading")},setParent:function(e,t){this.parentDialog={text:e,dialog:t}}})},{}],22:[function(e,t,i){var s=(window.panels,jQuery);t.exports=Backbone.View.extend({template:_.template(s("#siteorigin-panels-live-editor").html().panelsProcessTemplate()),postId:!1,previewScrollTop:0,loadTimes:[],previewFrameId:1,previewIframe:null,events:{"click .live-editor-close":"close","click .live-editor-collapse":"collapse","click .live-editor-mode":"mobileToggle"},initialize:function(e){this.builder=e.builder,this.builder.model.on("refresh_panels_data",this.handleRefreshData,this),this.builder.model.on("load_panels_data",this.handleLoadData,this);
3
+ },render:function(){this.setElement(this.template()),this.$el.hide();var e=this,t=!1;return s(document).mousedown(function(){t=!0}).mouseup(function(){t=!1}),e.$el.on("mouseenter",".so-widget-wrapper",function(){var i=(s(this),s(this).data("live-editor-preview-widget"));t||void 0===i||!i.length||e.$(".so-preview-overlay").is(":visible")||(e.highlightElement(i),e.scrollToElement(i))}),e.$el.on("mouseleave",".so-widget-wrapper",function(){e.resetHighlights()}),e.builder.on("open_dialog",function(){e.resetHighlights()}),this},attach:function(){this.$el.appendTo("body")},setPostId:function(e){this.postId=e},open:function(){if(""===this.$el.html()&&this.render(),0===this.$el.closest("body").length&&this.attach(),this.builder.lockPageScroll(),this.$el.is(":visible"))return this;if(this.$el.show(),this.refreshPreview(this.builder.model.getPanelsData()),this.originalContainer=this.builder.$el.parent(),this.builder.$el.appendTo(this.$(".so-live-editor-builder")),this.builder.$(".so-tool-button.so-live-editor").hide(),this.builder.trigger("builder_resize"),"auto-draft"===s("#original_post_status").val()&&!this.autoSaved){var e=this;wp.autosave&&(""===s('#title[name="post_title"]').val()&&s('#title[name="post_title"]').val(panelsOptions.loc.draft).trigger("keydown"),s(document).one("heartbeat-tick.autosave",function(){e.autoSaved=!0,e.refreshPreview(e.builder.model.getPanelsData())}),wp.autosave.server.triggerSave())}},close:function(){return this.$el.is(":visible")?(this.$el.hide(),this.builder.unlockPageScroll(),this.builder.$el.appendTo(this.originalContainer),this.builder.$(".so-tool-button.so-live-editor").show(),void this.builder.trigger("builder_resize")):this},collapse:function(){this.$el.toggleClass("so-collapsed");var e=this.$(".live-editor-collapse span");e.html(e.data(this.$el.hasClass("so-collapsed")?"expand":"collapse"))},highlightElement:function(e){_.isUndefined(this.resetHighlightTimeout)||clearTimeout(this.resetHighlightTimeout);var t=this.previewIframe.contents().find("body");t.find(".panel-grid .panel-grid-cell .so-panel").filter(function(){return 0===s(this).parents(".widget_siteorigin-panels-builder").length}).not(e).addClass("so-panels-faded"),e.removeClass("so-panels-faded").addClass("so-panels-highlighted")},resetHighlights:function(){var e=this.previewIframe.contents().find("body");this.resetHighlightTimeout=setTimeout(function(){e.find(".panel-grid .panel-grid-cell .so-panel").removeClass("so-panels-faded so-panels-highlighted")},100)},scrollToElement:function(e){var t=this.$(".so-preview iframe")[0].contentWindow;t.liveEditorScrollTo(e)},handleRefreshData:function(e,t){return this.$el.is(":visible")?void this.refreshPreview(e):this},handleLoadData:function(){return this.$el.is(":visible")?void this.refreshPreview(this.builder.model.getPanelsData()):this},refreshPreview:function(e){var t=this.loadTimes.length?_.reduce(this.loadTimes,function(e,t){return e+t},0)/this.loadTimes.length:1e3;_.isNull(this.previewIframe)||this.$(".so-preview-overlay").is(":visible")||(this.previewScrollTop=this.previewIframe.contents().scrollTop()),this.$(".so-preview-overlay").show(),this.$(".so-preview-overlay .so-loading-bar").clearQueue().css("width","0%").animate({width:"100%"},parseInt(t)+100),this.postToIframe({live_editor_panels_data:JSON.stringify(e)},this.$el.data("preview-url"),this.$(".so-preview")),this.previewIframe.data("load-start",(new Date).getTime())},postToIframe:function(e,t,i){_.isNull(this.previewIframe)||this.previewIframe.remove();var l="siteorigin-panels-live-preview-"+this.previewFrameId;this.previewIframe=s('<iframe src="javascript:false;" />').attr({id:l,name:l}).appendTo(i),this.setupPreviewFrame(this.previewIframe);var o=s('<form id="soPostToPreviewFrame" method="post" />').attr({id:l,target:this.previewIframe.attr("id"),action:t}).appendTo("body");return s.each(e,function(e,t){s('<input type="hidden" />').attr({name:e,value:t}).appendTo(o)}),o.submit().remove(),this.previewFrameId++,this.previewIframe},setupPreviewFrame:function(e){var t=this;e.data("iframeready",!1).on("iframeready",function(){var e=s(this),i=e.contents();e.data("iframeready")||(e.data("iframeready",!0),void 0!==e.data("load-start")&&(t.loadTimes.unshift((new Date).getTime()-e.data("load-start")),_.isEmpty(t.loadTimes)||(t.loadTimes=t.loadTimes.slice(0,4))),setTimeout(function(){i.scrollTop(t.previewScrollTop),t.$(".so-preview-overlay").hide()},100),i.find(".panel-grid .panel-grid-cell .so-panel").filter(function(){return 0===s(this).parents(".widget_siteorigin-panels-builder").length}).each(function(e,i){var l=s(i),o=t.$(".so-live-editor-builder .so-widget-wrapper").eq(l.data("index"));o.data("live-editor-preview-widget",l),l.css({cursor:"pointer"}).mouseenter(function(){o.parent().addClass("so-hovered"),t.highlightElement(l)}).mouseleave(function(){o.parent().removeClass("so-hovered"),t.resetHighlights()}).click(function(e){e.preventDefault(),o.find(".title h4").click()})}),i.find("a").css({"pointer-events":"none"}).click(function(e){e.preventDefault()}))}).on("load",function(){var e=s(this);e.data("iframeready")||e.trigger("iframeready")})},hasPreviewUrl:function(){return""!==this.$("form.live-editor-form").attr("action")},mobileToggle:function(e){var t=s(e.currentTarget);this.$(".live-editor-mode").not(t).removeClass("so-active"),t.addClass("so-active"),this.$el.removeClass("live-editor-desktop-mode live-editor-tablet-mode live-editor-mobile-mode").addClass("live-editor-"+t.data("mode")+"-mode")}})},{}],23:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({template:_.template(l("#siteorigin-panels-builder-row").html().panelsProcessTemplate()),events:{"click .so-row-settings":"editSettingsHandler","click .so-row-duplicate":"duplicateHandler","click .so-row-delete":"confirmedDeleteHandler"},builder:null,dialog:null,initialize:function(){this.model.cells.on("add",this.handleCellAdd,this),this.model.cells.on("remove",this.handleCellRemove,this),this.model.on("reweight_cells",this.resize,this),this.model.on("destroy",this.onModelDestroy,this),this.model.on("visual_destroy",this.visualDestroyModel,this);var e=this;this.model.cells.each(function(t){e.listenTo(t.widgets,"add",e.resize)}),this.model.cells.on("add",function(t){e.listenTo(t.widgets,"add",e.resize)},this)},render:function(){this.setElement(this.template()),this.$el.data("view",this);var e=this;return this.model.cells.each(function(t){var i=new s.view.cell({model:t});i.row=e,i.render(),i.$el.appendTo(e.$(".so-cells"))}),this.builder.on("widget_sortable_move",this.resize,this),this.builder.on("builder_resize",this.resize,this),this.resize(),this},visualCreate:function(){this.$el.hide().fadeIn("fast")},resize:function(e){if(this.$el.is(":visible")){this.$(".so-cells .cell-wrapper").css("min-height",0);var t=0;this.$(".so-cells .cell").each(function(){t=Math.max(t,l(this).height()),l(this).css("width",100*l(this).data("view").model.get("weight")+"%")}),this.$(".so-cells .cell-wrapper").css("min-height",Math.max(t,64))}},onModelDestroy:function(){this.remove()},visualDestroyModel:function(){this.builder.addHistoryEntry("row_deleted");var e=this;this.$el.fadeOut("normal",function(){e.model.destroy(),e.builder.model.refreshPanelsData()})},duplicateHandler:function(){this.builder.addHistoryEntry("row_duplicated");var e=this.model.clone(this.builder.model);this.builder.model.rows.add(e,{at:this.builder.model.rows.indexOf(this.model)+1}),this.builder.model.refreshPanelsData()},confirmedDeleteHandler:function(e){var t=jQuery(e.target);if(t.hasClass("dashicons")&&(t=l.parent()),t.hasClass("so-confirmed"))this.visualDestroyModel();else{var i=t.html();t.addClass("so-confirmed").html('<span class="dashicons dashicons-yes"></span>'+panelsOptions.loc.dropdown_confirm),setTimeout(function(){t.removeClass("so-confirmed").html(i)},2500)}},editSettingsHandler:function(){null===this.dialog&&(this.dialog=new s.dialog.row,this.dialog.setBuilder(this.builder).setRowModel(this.model)),this.dialog.openDialog()},deleteHandler:function(){this.model.destroy()},handleCellAdd:function(e){var t=new s.view.cell({model:e});t.row=this,t.render(),t.$el.appendTo(this.$(".so-cells"))},handleCellRemove:function(e){this.$(".so-cells > .cell").each(function(){var t=l(this).data("view");_.isUndefined(t)||t.model.cid===e.cid&&t.remove()})},buildContextualMenu:function(e,t){for(var i=this,l=[],o=1;5>o;o++)l.push({title:o+" "+panelsOptions.loc.contextual.column});t.addSection({sectionTitle:panelsOptions.loc.contextual.add_row,search:!1},l,function(e){i.builder.addHistoryEntry("row_added");for(var t=Number(e)+1,l=[],o=0;t>o;o++)l.push(100/t);var n=new s.model.row({collection:i.collection});n.setCells(l),n.builder=i.builder,i.builder.model.rows.add(n,{at:i.builder.model.rows.indexOf(i.model)+1}),i.builder.model.refreshPanelsData()}),t.addSection({sectionTitle:panelsOptions.loc.contextual.row_actions,search:!1},{edit:{title:panelsOptions.loc.contextual.row_edit},duplicate:{title:panelsOptions.loc.contextual.row_duplicate},"delete":{title:panelsOptions.loc.contextual.row_delete,confirm:!0}},function(e){switch(e){case"edit":i.editSettingsHandler();break;case"duplicate":i.duplicateHandler();break;case"delete":i.visualDestroyModel()}})}})},{}],24:[function(e,t,i){var s=(window.panels,jQuery);t.exports=Backbone.View.extend({stylesLoaded:!1,initialize:function(){},render:function(e,t,i){if(!_.isUndefined(e)){i=_.extend({builderType:"",dialog:null},i),this.$el.addClass("so-visual-styles");var l=this;return s.post(panelsOptions.ajaxurl,{action:"so_panels_style_form",type:e,style:this.model.get("style"),args:JSON.stringify({builderType:i.builderType}),postId:t},function(e){l.$el.html(e),l.setupFields(),l.stylesLoaded=!0,l.trigger("styles_loaded",!_.isEmpty(e)),_.isNull(i.dialog)||i.dialog.trigger("styles_loaded",!_.isEmpty(e))}),this}},attach:function(e){e.append(this.$el)},detach:function(){this.$el.detach()},setupFields:function(){this.$(".style-section-wrapper").each(function(){var e=s(this);e.find(".style-section-head").click(function(t){t.preventDefault(),e.find(".style-section-fields").slideToggle("fast")})}),_.isUndefined(s.fn.wpColorPicker)||(_.isObject(panelsOptions.wpColorPickerOptions.palettes)&&!s.isArray(panelsOptions.wpColorPickerOptions.palettes)&&(panelsOptions.wpColorPickerOptions.palettes=s.map(panelsOptions.wpColorPickerOptions.palettes,function(e){return e})),this.$(".so-wp-color-field").wpColorPicker(panelsOptions.wpColorPickerOptions)),this.$(".style-field-image").each(function(){var e=null,t=s(this);t.find(".so-image-selector").click(function(i){i.preventDefault(),null===e&&(e=wp.media({title:"choose",library:{type:"image"},button:{text:"Done",close:!0}}),e.on("select",function(){var i=e.state().get("selection").first().attributes,s=i.url;if(!_.isUndefined(i.sizes))try{s=i.sizes.thumbnail.url}catch(l){s=i.sizes.full.url}t.find(".current-image").css("background-image","url("+s+")"),t.find("input").val(i.id)})),e.open()}),t.find(".remove-image").click(function(e){e.preventDefault(),t.find(".current-image").css("background-image","none"),t.find("input").val("")})}),this.$(".style-field-measurement").each(function(){var e=jQuery(this),t=e.find('input[type="text"]'),i=e.find("select"),s=e.find('input[type="hidden"]');if(""!==s.val()){var l=/(?:([0-9\.,]+)(.*))+/,o=s.val().split(" "),n=[];for(var a in o){var r=l.exec(o[a]);!_.isNull(r)||_.isUndefined(r[1])||_.isUndefined(r[2])||(n.push(r[1]),i.val(r[2]))}t.val(n.join(" "))}var d=function(){var e=t.val().split(" ").filter(function(e){return""!==e}).map(function(e){return e+i.val()}).join(" ");s.val(e)};t.keyup(d).change(d),i.change(d)})}})},{}],25:[function(e,t,i){var s=window.panels,l=jQuery;t.exports=Backbone.View.extend({template:_.template(l("#siteorigin-panels-builder-widget").html().panelsProcessTemplate()),cell:null,dialog:null,events:{"click .widget-edit":"editHandler","click .title h4":"editHandler","click .actions .widget-duplicate":"duplicateHandler","click .actions .widget-delete":"deleteHandler"},initialize:function(){this.model.on("user_edit",this.editHandler,this),this.model.on("user_duplicate",this.duplicateHandler,this),this.model.on("destroy",this.onModelDestroy,this),this.model.on("visual_destroy",this.visualDestroyModel,this),this.model.on("change:values",this.onModelChange,this)},render:function(e){if(e=_.extend({loadForm:!1},e),this.setElement(this.template({title:this.model.getWidgetField("title"),description:this.model.getTitle()})),this.$el.data("view",this),0===_.size(this.model.get("values"))||e.loadForm){var t=this.getEditDialog();t.once("form_loaded",t.saveWidget,t),t.setupDialog()}return this},visualCreate:function(){this.$el.hide().fadeIn("fast")},getEditDialog:function(){return null===this.dialog&&(this.dialog=new s.dialog.widget({model:this.model}),this.dialog.setBuilder(this.cell.row.builder),this.dialog.widgetView=this),this.dialog},editHandler:function(){this.getEditDialog().openDialog()},duplicateHandler:function(){this.cell.row.builder.addHistoryEntry("widget_duplicated");var e=this.model.clone(this.model.cell);this.cell.model.widgets.add(e,{at:this.model.collection.indexOf(this.model)+1}),this.cell.row.builder.model.refreshPanelsData()},deleteHandler:function(){this.model.trigger("visual_destroy")},onModelChange:function(){this.$(".description").html(this.model.getTitle())},onModelDestroy:function(){this.remove()},visualDestroyModel:function(){this.cell.row.builder.addHistoryEntry("widget_deleted");var e=this;this.$el.fadeOut("fast",function(){e.cell.row.resize(),e.model.destroy(),e.cell.row.builder.model.refreshPanelsData(),e.remove()})},buildContextualMenu:function(e,t){var i=this;t.addSection({sectionTitle:panelsOptions.loc.contextual.add_widget_below,searchPlaceholder:panelsOptions.loc.contextual.search_widgets,defaultDisplay:panelsOptions.contextual.default_widgets},panelsOptions.widgets,function(e){i.cell.row.builder.addHistoryEntry("widget_added");var t=new s.model.widget({"class":e});t.cell=i.cell.model,i.cell.model.widgets.add(t,{at:i.model.collection.indexOf(i.model)+1}),i.cell.row.builder.model.refreshPanelsData()}),t.addSection({sectionTitle:panelsOptions.loc.contextual.widget_actions,search:!1},{edit:{title:panelsOptions.loc.contextual.widget_edit},duplicate:{title:panelsOptions.loc.contextual.widget_duplicate},"delete":{title:panelsOptions.loc.contextual.widget_delete,confirm:!0}},function(e){switch(e){case"edit":i.editHandler();break;case"duplicate":i.duplicateHandler();break;case"delete":i.visualDestroyModel()}i.cell.row.builder.model.refreshPanelsData()}),this.cell.row.buildContextualMenu(e,t)}})},{}]},{},[12]);
js/styling-23.js DELETED
@@ -1,65 +0,0 @@
1
-
2
- /* global jQuery */
3
-
4
- jQuery(function($){
5
-
6
- var fullContainer = $( panelsStyles.fullContainer);
7
- if( fullContainer.length === 0 ) {
8
- fullContainer = $('body');
9
- }
10
-
11
- // Stretch all the full width rows
12
- var stretchFullWidthRows = function(){
13
-
14
- $('.siteorigin-panels-stretch.panel-row-style').each(function(){
15
- var $$ = $(this);
16
- $$.css({
17
- 'margin-left' : 0,
18
- 'margin-right' : 0,
19
- 'padding-left' : 0,
20
- 'padding-right' : 0
21
- });
22
-
23
- var leftSpace = $$.offset().left - fullContainer.offset().left;
24
- var rightSpace = fullContainer.outerWidth() - leftSpace - $$.parent().outerWidth();
25
-
26
- $$.css({
27
- 'margin-left' : -leftSpace,
28
- 'margin-right' : -rightSpace,
29
- 'padding-left' : $$.data('stretch-type') === 'full' ? leftSpace : 0,
30
- 'padding-right' : $$.data('stretch-type') === 'full' ? rightSpace : 0
31
- });
32
-
33
- var cells = $$.find('> .panel-grid-cell');
34
-
35
- if( $$.data('stretch-type') === 'full-stretched' && cells.length === 1 ) {
36
- cells.css({
37
- 'padding-left' : 0,
38
- 'padding-right' : 0
39
- });
40
- }
41
-
42
- $$.css({
43
- 'border-left' : 0,
44
- 'border-right' : 0
45
- });
46
- });
47
-
48
- if( $('.siteorigin-panels-stretch.panel-row-style').length ) {
49
- $(window).trigger('panelsStretchRows');
50
- }
51
- }
52
- $(window).resize( stretchFullWidthRows );
53
- stretchFullWidthRows();
54
-
55
- if( typeof $.stellar !== 'undefined' ) {
56
- // Setup parallax after a small timeout to allow full width to take effect
57
- setTimeout( function(){
58
- $.stellar( {
59
- horizontalScrolling: false,
60
- responsive: true
61
- } );
62
- }, 100 );
63
- }
64
-
65
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
js/styling-24.js ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* global _, jQuery */
2
+
3
+ jQuery( function ( $ ) {
4
+
5
+ var fullContainer = $( panelsStyles.fullContainer );
6
+ if ( fullContainer.length === 0 ) {
7
+ fullContainer = $( 'body' );
8
+ }
9
+
10
+ // Stretch all the full width rows
11
+ var stretchFullWidthRows = function () {
12
+
13
+ $( '.siteorigin-panels-stretch.panel-row-style' ).each( function () {
14
+ var $$ = $( this );
15
+ $$.css( {
16
+ 'margin-left': 0,
17
+ 'margin-right': 0,
18
+ 'padding-left': 0,
19
+ 'padding-right': 0
20
+ } );
21
+
22
+ var leftSpace = $$.offset().left - fullContainer.offset().left;
23
+ var rightSpace = fullContainer.outerWidth() - leftSpace - $$.parent().outerWidth();
24
+
25
+ $$.css( {
26
+ 'margin-left': - leftSpace,
27
+ 'margin-right': - rightSpace,
28
+ 'padding-left': $$.data( 'stretch-type' ) === 'full' ? leftSpace : 0,
29
+ 'padding-right': $$.data( 'stretch-type' ) === 'full' ? rightSpace : 0
30
+ } );
31
+
32
+ var cells = $$.find( '> .panel-grid-cell' );
33
+
34
+ if ( $$.data( 'stretch-type' ) === 'full-stretched' && cells.length === 1 ) {
35
+ cells.css( {
36
+ 'padding-left': 0,
37
+ 'padding-right': 0
38
+ } );
39
+ }
40
+
41
+ $$.css( {
42
+ 'border-left': 0,
43
+ 'border-right': 0
44
+ } );
45
+ } );
46
+
47
+ if ( $( '.siteorigin-panels-stretch.panel-row-style' ).length ) {
48
+ $( window ).trigger( 'panelsStretchRows' );
49
+ }
50
+ }
51
+ $( window ).resize( stretchFullWidthRows );
52
+ stretchFullWidthRows();
53
+
54
+ if ( typeof $.stellar !== 'undefined' ) {
55
+ // Setup parallax after a small timeout to allow full width to take effect
56
+ setTimeout( function () {
57
+ $.stellar( {
58
+ horizontalScrolling: false,
59
+ responsive: true
60
+ } );
61
+ }, 100 );
62
+ }
63
+
64
+ } );
js/{styling-23.min.js → styling-24.min.js} RENAMED
File without changes
readme.txt CHANGED
@@ -2,7 +2,8 @@
2
  Tags: page builder, responsive, widget, widgets, builder, page, admin, gallery, content, cms, pages, post, css, layout, grid
3
  Requires at least: 4.0
4
  Tested up to: 4.5
5
- Stable tag: 2.3.1
 
6
  License: GPLv3
7
  License URI: http://www.gnu.org/licenses/gpl.html
8
  Donate link: http://siteorigin.com/page-builder/#donate
@@ -95,6 +96,22 @@ We've tried to ensure that Page Builder is compatible with most plugin widgets.
95
 
96
  == Changelog ==
97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  = 2.3.2 - March 11 2016 =
99
  * Fixed compatibility with WordPress 4.5
100
 
2
  Tags: page builder, responsive, widget, widgets, builder, page, admin, gallery, content, cms, pages, post, css, layout, grid
3
  Requires at least: 4.0
4
  Tested up to: 4.5
5
+ Stable tag: 2.3.2
6
+ Build time: 2016-04-01T15:29:25+02:00
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl.html
9
  Donate link: http://siteorigin.com/page-builder/#donate
96
 
97
  == Changelog ==
98
 
99
+ = 2.4 - April 1 2016 =
100
+ * Created new Live Editor.
101
+ * Changes to Page Builder admin HTML structure for Live Editor.
102
+ * New layout for prebuilt dialog.
103
+ * Now possible to append, prepend and replace layouts in prebuilt dialog.
104
+ * Fixed contextual menu in Layout Builder widget.
105
+ * Added row/widget actions to contextual menu.
106
+ * Clarified functionality of "Switch to Editor" button by renaming to "Revert to Editor".
107
+ * refreshPanelsData function is called more consistently.
108
+ * Various background performance enhancements.
109
+ * Full JS code refactoring.
110
+ * Fixed cell bottom margins with reverse collapse order.
111
+ * Improved window scroll locking for dialogs.
112
+ * Added `in_widget_form` action when rendering widget forms
113
+ * Custom home page now saves revisions.
114
+
115
  = 2.3.2 - March 11 2016 =
116
  * Fixed compatibility with WordPress 4.5
117
 
settings/settings.php CHANGED
@@ -122,6 +122,7 @@ class SiteOrigin_Panels_Settings {
122
  $defaults['tablet-width'] = 1024;
123
  $defaults['mobile-width'] = 780;
124
  $defaults['margin-bottom'] = 30;
 
125
  $defaults['margin-sides'] = 30;
126
  $defaults['full-width-container'] = 'body';
127
 
@@ -270,6 +271,12 @@ class SiteOrigin_Panels_Settings {
270
  'description' => __('Default margin below rows.', 'siteorigin-panels'),
271
  );
272
 
 
 
 
 
 
 
273
  $fields['layout']['fields']['margin-sides'] = array(
274
  'type' => 'number',
275
  'unit' => 'px',
122
  $defaults['tablet-width'] = 1024;
123
  $defaults['mobile-width'] = 780;
124
  $defaults['margin-bottom'] = 30;
125
+ $defaults['margin-bottom-last-row'] = false;
126
  $defaults['margin-sides'] = 30;
127
  $defaults['full-width-container'] = 'body';
128
 
271
  'description' => __('Default margin below rows.', 'siteorigin-panels'),
272
  );
273
 
274
+ $fields['layout']['fields']['margin-bottom-last-row'] = array(
275
+ 'type' => 'checkbox',
276
+ 'label' => __('Last Row With Margin', 'siteorigin-panels'),
277
+ 'description' => __('Allow margin in last row.', 'siteorigin-panels'),
278
+ );
279
+
280
  $fields['layout']['fields']['margin-sides'] = array(
281
  'type' => 'number',
282
  'unit' => 'px',
siteorigin-panels.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Page Builder by SiteOrigin
4
  Plugin URI: https://siteorigin.com/page-builder/
5
  Description: A drag and drop, responsive page builder that simplifies building your website.
6
- Version: 2.3.2
7
  Author: SiteOrigin
8
  Author URI: https://siteorigin.com
9
  License: GPL3
@@ -11,11 +11,11 @@ License URI: http://www.gnu.org/licenses/gpl.html
11
  Donate link: http://siteorigin.com/page-builder/#donate
12
  */
13
 
14
- define('SITEORIGIN_PANELS_VERSION', '2.3.2');
15
  if ( ! defined('SITEORIGIN_PANELS_JS_SUFFIX' ) ) {
16
  define('SITEORIGIN_PANELS_JS_SUFFIX', '.min');
17
  }
18
- define('SITEORIGIN_PANELS_VERSION_SUFFIX', '-23');
19
  define('SITEORIGIN_PANELS_BASE_FILE', __FILE__);
20
 
21
  // All the basic settings
@@ -130,6 +130,8 @@ function siteorigin_panels_save_home_page(){
130
  $page_id = get_option( 'page_on_front' );
131
  if( empty($page_id) ) $page_id = get_option( 'siteorigin_panels_home_page_id' );
132
 
 
 
133
  if ( !$page_id || get_post_meta( $page_id, 'panels_data', true ) == '' ) {
134
  // Lets create a new page
135
  $page_id = wp_insert_post( array(
@@ -137,6 +139,7 @@ function siteorigin_panels_save_home_page(){
137
  'post_title' => __( 'Home Page', 'siteorigin-panels' ),
138
  'post_status' => !empty($_POST['siteorigin_panels_home_enabled']) ? 'publish' : 'draft',
139
  'post_type' => 'page',
 
140
  'comment_status' => 'closed',
141
  ) );
142
  update_option( 'page_on_front', $page_id );
@@ -144,6 +147,12 @@ function siteorigin_panels_save_home_page(){
144
 
145
  // Action triggered when creating a new home page through the custom home page interface
146
  do_action( 'siteorigin_panels_create_home_page', $page_id );
 
 
 
 
 
 
147
  }
148
 
149
  // Save the updated page data
@@ -187,7 +196,6 @@ function siteorigin_panels_save_home_page(){
187
  do_action( 'save_post', $post->ID, $post, true );
188
  do_action( 'wp_insert_post', $post->ID, $post, true );
189
  }
190
-
191
  }
192
  }
193
  add_action('admin_init', 'siteorigin_panels_save_home_page');
@@ -360,7 +368,6 @@ function siteorigin_panels_admin_enqueue_scripts( $prefix = '', $force = false )
360
  ),
361
 
362
  // general localization
363
- 'prebuilt_confirm' => __('Are you sure you want to overwrite your current content? This can be undone in the builder history.', 'siteorigin-panels'),
364
  'prebuilt_loading' => __('Loading prebuilt layout', 'siteorigin-panels'),
365
  'confirm_use_builder' => __("Would you like to copy this editor's existing content to Page Builder?", 'siteorigin-panels'),
366
  'confirm_stop_builder' => __("Would you like to clear your Page Builder content and revert to using the standard visual editor?", 'siteorigin-panels'),
@@ -368,7 +375,8 @@ function siteorigin_panels_admin_enqueue_scripts( $prefix = '', $force = false )
368
  'layout_widget' => __('Layout Builder Widget', 'siteorigin-panels'),
369
  // TRANSLATORS: A standard confirmation message
370
  'dropdown_confirm' => __('Are you sure?', 'siteorigin-panels'),
371
- 'search_results_header' => __('Search Results For: ', 'siteorigin-panels'),
 
372
 
373
  // Everything for the contextual menu
374
  'contextual' => array(
@@ -378,7 +386,18 @@ function siteorigin_panels_admin_enqueue_scripts( $prefix = '', $force = false )
378
 
379
  'add_row' => __('Add Row', 'siteorigin-panels'),
380
  'column' => __('Column', 'siteorigin-panels'),
381
- )
 
 
 
 
 
 
 
 
 
 
 
382
  ),
383
  'plupload' => array(
384
  'max_file_size' => wp_max_upload_size().'b',
@@ -389,6 +408,7 @@ function siteorigin_panels_admin_enqueue_scripts( $prefix = '', $force = false )
389
  'error_message' => __('Error uploading or importing file.', 'siteorigin-panels'),
390
  ),
391
  'wpColorPickerOptions' => apply_filters('siteorigin_panels_wpcolorpicker_options', array()),
 
392
  ));
393
 
394
  if( $screen->base != 'widgets' ) {
@@ -396,7 +416,8 @@ function siteorigin_panels_admin_enqueue_scripts( $prefix = '', $force = false )
396
  $original_post = isset($GLOBALS['post']) ? $GLOBALS['post'] : null; // Make sure widgets don't change the global post.
397
  foreach($GLOBALS['wp_widget_factory']->widgets as $class => $widget_obj){
398
  ob_start();
399
- $widget_obj->form( array() );
 
400
  ob_clean();
401
  }
402
  $GLOBALS['post'] = $original_post;
@@ -693,6 +714,7 @@ function siteorigin_panels_generate_css($post_id, $panels_data = false){
693
  $panels_tablet_width = $settings['tablet-width'];
694
  $panels_mobile_width = $settings['mobile-width'];
695
  $panels_margin_bottom = $settings['margin-bottom'];
 
696
 
697
  $panels_data = apply_filters( 'siteorigin_panels_data', $panels_data, $post_id );
698
 
@@ -720,14 +742,13 @@ function siteorigin_panels_generate_css($post_id, $panels_data = false){
720
  }
721
 
722
  // Add the bottom margin to any grids that aren't the last
723
- if($gi != count($panels_data['grids'])-1){
724
  // Filter the bottom margin for this row with the arguments
725
  $css->add_row_css($post_id, $grid_id, '', array(
726
  'margin-bottom' => apply_filters('siteorigin_panels_css_row_margin_bottom', $panels_margin_bottom.'px', $grid, $gi, $panels_data, $post_id)
727
  ));
728
  }
729
 
730
-
731
  $collapse_order = !empty( $grid['style']['collapse_order'] ) ? $grid['style']['collapse_order'] : ( !is_rtl() ? 'left-top' : 'right-top' );
732
 
733
  if ( $cell_count > 1 ) {
@@ -753,7 +774,7 @@ function siteorigin_panels_generate_css($post_id, $panels_data = false){
753
  ), $panels_mobile_width);
754
 
755
  for ( $i = 0; $i < $cell_count; $i++ ) {
756
- if ( $i != $cell_count - 1 ) {
757
  $css->add_cell_css($post_id, $grid_id, $i, '', array(
758
  'margin-bottom' => $panels_margin_bottom . 'px',
759
  ), $panels_mobile_width);
@@ -961,6 +982,8 @@ function siteorigin_panels_render( $post_id = false, $enqueue_css = true, $panel
961
  $panels_data['widgets'][$i]['panels_info'] = $panels_data['widgets'][$i]['info'];
962
  unset($panels_data['widgets'][$i]['info']);
963
  }
 
 
964
  }
965
  }
966
 
@@ -1201,7 +1224,7 @@ function siteorigin_panels_the_widget( $widget_info, $instance, $grid, $cell, $p
1201
  }
1202
 
1203
  $args = array(
1204
- 'before_widget' => '<div class="' . esc_attr( implode( ' ', $classes ) ) . '" id="' . $id . '">',
1205
  'after_widget' => '</div>',
1206
  'before_title' => $before_title,
1207
  'after_title' => $after_title,
@@ -1373,7 +1396,8 @@ function siteorigin_panels_render_form($widget, $instance = array(), $raw = fals
1373
  $the_widget->number = $widget_number;
1374
 
1375
  ob_start();
1376
- $the_widget->form($instance);
 
1377
  $form = ob_get_clean();
1378
 
1379
  // Convert the widget field naming into ones that Page Builder uses
@@ -1417,7 +1441,7 @@ function siteorigin_panels_process_panels_data( $panels_data ){
1417
  $last_wi = 0;
1418
 
1419
  foreach( $panels_data['widgets'] as &$widget ) {
1420
-
1421
  if( empty($widget['panels_info']) && !empty($widget['info']) ) {
1422
  $widget['panels_info'] = $widget['info'];
1423
  unset( $widget['info'] );
@@ -1435,6 +1459,14 @@ function siteorigin_panels_process_panels_data( $panels_data ){
1435
  }
1436
  $widget['panels_info']['cell_index'] = $last_wi++;
1437
  }
 
 
 
 
 
 
 
 
1438
  }
1439
 
1440
  // Process the IDs of the grids. Make sure that each is unique.
3
  Plugin Name: Page Builder by SiteOrigin
4
  Plugin URI: https://siteorigin.com/page-builder/
5
  Description: A drag and drop, responsive page builder that simplifies building your website.
6
+ Version: 2.4
7
  Author: SiteOrigin
8
  Author URI: https://siteorigin.com
9
  License: GPL3
11
  Donate link: http://siteorigin.com/page-builder/#donate
12
  */
13
 
14
+ define('SITEORIGIN_PANELS_VERSION', '2.4');
15
  if ( ! defined('SITEORIGIN_PANELS_JS_SUFFIX' ) ) {
16
  define('SITEORIGIN_PANELS_JS_SUFFIX', '.min');
17
  }
18
+ define('SITEORIGIN_PANELS_VERSION_SUFFIX', '-24');
19
  define('SITEORIGIN_PANELS_BASE_FILE', __FILE__);
20
 
21
  // All the basic settings
130
  $page_id = get_option( 'page_on_front' );
131
  if( empty($page_id) ) $page_id = get_option( 'siteorigin_panels_home_page_id' );
132
 
133
+ $post_content = wp_unslash( $_POST['post_content'] );
134
+
135
  if ( !$page_id || get_post_meta( $page_id, 'panels_data', true ) == '' ) {
136
  // Lets create a new page
137
  $page_id = wp_insert_post( array(
139
  'post_title' => __( 'Home Page', 'siteorigin-panels' ),
140
  'post_status' => !empty($_POST['siteorigin_panels_home_enabled']) ? 'publish' : 'draft',
141
  'post_type' => 'page',
142
+ 'post_content' => $post_content,
143
  'comment_status' => 'closed',
144
  ) );
145
  update_option( 'page_on_front', $page_id );
147
 
148
  // Action triggered when creating a new home page through the custom home page interface
149
  do_action( 'siteorigin_panels_create_home_page', $page_id );
150
+ } else {
151
+ // `wp_insert_post` does it's own sanitization, but it seems `wp_update_post` doesn't.
152
+ $post_content = sanitize_post_field( 'post_content', $post_content, $page_id, 'db' );
153
+
154
+ // Update the post with changed content to save revision if necessary.
155
+ wp_update_post( array( 'ID' => $page_id, 'post_content' => $post_content ) );
156
  }
157
 
158
  // Save the updated page data
196
  do_action( 'save_post', $post->ID, $post, true );
197
  do_action( 'wp_insert_post', $post->ID, $post, true );
198
  }
 
199
  }
200
  }
201
  add_action('admin_init', 'siteorigin_panels_save_home_page');
368
  ),
369
 
370
  // general localization
 
371
  'prebuilt_loading' => __('Loading prebuilt layout', 'siteorigin-panels'),
372
  'confirm_use_builder' => __("Would you like to copy this editor's existing content to Page Builder?", 'siteorigin-panels'),
373
  'confirm_stop_builder' => __("Would you like to clear your Page Builder content and revert to using the standard visual editor?", 'siteorigin-panels'),
375
  'layout_widget' => __('Layout Builder Widget', 'siteorigin-panels'),
376
  // TRANSLATORS: A standard confirmation message
377
  'dropdown_confirm' => __('Are you sure?', 'siteorigin-panels'),
378
+ // TRANSLATORS: When a layout file is ready to be inserted. %s is the filename.
379
+ 'ready_to_insert' => __('%s is ready to insert.', 'siteorigin-panels'),
380
 
381
  // Everything for the contextual menu
382
  'contextual' => array(
386
 
387
  'add_row' => __('Add Row', 'siteorigin-panels'),
388
  'column' => __('Column', 'siteorigin-panels'),
389
+
390
+ 'widget_actions' => __( 'Widget Actions', 'siteorigin-panels' ),
391
+ 'widget_edit' => __( 'Edit Widget', 'siteorigin-panels' ),
392
+ 'widget_duplicate' => __( 'Duplicate Widget', 'siteorigin-panels' ),
393
+ 'widget_delete' => __( 'Delete Widget', 'siteorigin-panels' ),
394
+
395
+ 'row_actions' => __( 'Row Actions', 'siteorigin-panels' ),
396
+ 'row_edit' => __( 'Edit Row', 'siteorigin-panels' ),
397
+ 'row_duplicate' => __( 'Duplicate Row', 'siteorigin-panels' ),
398
+ 'row_delete' => __( 'Delete Row', 'siteorigin-panels' ),
399
+ ),
400
+ 'draft' => __( 'Draft', 'siteorigin-panels' ),
401
  ),
402
  'plupload' => array(
403
  'max_file_size' => wp_max_upload_size().'b',
408
  'error_message' => __('Error uploading or importing file.', 'siteorigin-panels'),
409
  ),
410
  'wpColorPickerOptions' => apply_filters('siteorigin_panels_wpcolorpicker_options', array()),
411
+ 'prebuiltDefaultScreenshot' => plugin_dir_url( __FILE__ ) . 'css/images/prebuilt-default.png',
412
  ));
413
 
414
  if( $screen->base != 'widgets' ) {
416
  $original_post = isset($GLOBALS['post']) ? $GLOBALS['post'] : null; // Make sure widgets don't change the global post.
417
  foreach($GLOBALS['wp_widget_factory']->widgets as $class => $widget_obj){
418
  ob_start();
419
+ $return = $widget_obj->form( array() );
420
+ do_action_ref_array( 'in_widget_form', array( &$widget_obj, &$return, array() ) );
421
  ob_clean();
422
  }
423
  $GLOBALS['post'] = $original_post;
714
  $panels_tablet_width = $settings['tablet-width'];
715
  $panels_mobile_width = $settings['mobile-width'];
716
  $panels_margin_bottom = $settings['margin-bottom'];
717
+ $panels_margin_bottom_last_row = $settings['margin-bottom-last-row'];
718
 
719
  $panels_data = apply_filters( 'siteorigin_panels_data', $panels_data, $post_id );
720
 
742
  }
743
 
744
  // Add the bottom margin to any grids that aren't the last
745
+ if($gi != count($panels_data['grids'])-1 || !empty($grid['style']['bottom_margin']) || !empty($panels_margin_bottom_last_row)){
746
  // Filter the bottom margin for this row with the arguments
747
  $css->add_row_css($post_id, $grid_id, '', array(
748
  'margin-bottom' => apply_filters('siteorigin_panels_css_row_margin_bottom', $panels_margin_bottom.'px', $grid, $gi, $panels_data, $post_id)
749
  ));
750
  }
751
 
 
752
  $collapse_order = !empty( $grid['style']['collapse_order'] ) ? $grid['style']['collapse_order'] : ( !is_rtl() ? 'left-top' : 'right-top' );
753
 
754
  if ( $cell_count > 1 ) {
774
  ), $panels_mobile_width);
775
 
776
  for ( $i = 0; $i < $cell_count; $i++ ) {
777
+ if ( ( $collapse_order == 'left-top' && $i != $cell_count - 1 ) || ( $collapse_order == 'right-top' && $i !== 0 ) ) {
778
  $css->add_cell_css($post_id, $grid_id, $i, '', array(
779
  'margin-bottom' => $panels_margin_bottom . 'px',
780
  ), $panels_mobile_width);
982
  $panels_data['widgets'][$i]['panels_info'] = $panels_data['widgets'][$i]['info'];
983
  unset($panels_data['widgets'][$i]['info']);
984
  }
985
+
986
+ $panels_data['widgets'][$i]['panels_info']['widget_index'] = $i;
987
  }
988
  }
989
 
1224
  }
1225
 
1226
  $args = array(
1227
+ 'before_widget' => '<div class="' . esc_attr( implode( ' ', $classes ) ) . '" id="' . $id . '" data-index="' . $widget_info['widget_index'] . '">',
1228
  'after_widget' => '</div>',
1229
  'before_title' => $before_title,
1230
  'after_title' => $after_title,
1396
  $the_widget->number = $widget_number;
1397
 
1398
  ob_start();
1399
+ $return = $the_widget->form($instance);
1400
+ do_action_ref_array( 'in_widget_form', array( &$the_widget, &$return, $instance ) );
1401
  $form = ob_get_clean();
1402
 
1403
  // Convert the widget field naming into ones that Page Builder uses
1441
  $last_wi = 0;
1442
 
1443
  foreach( $panels_data['widgets'] as &$widget ) {
1444
+ // Transfer legacy content
1445
  if( empty($widget['panels_info']) && !empty($widget['info']) ) {
1446
  $widget['panels_info'] = $widget['info'];
1447
  unset( $widget['info'] );
1459
  }
1460
  $widget['panels_info']['cell_index'] = $last_wi++;
1461
  }
1462
+
1463
+ foreach( $panels_data['grids'] as &$grid ) {
1464
+ if( !empty( $grid['style'] ) && is_string( $grid['style'] ) ) {
1465
+ $grid['style'] = array(
1466
+
1467
+ );
1468
+ }
1469
+ }
1470
  }
1471
 
1472
  // Process the IDs of the grids. Make sure that each is unique.
tpl/admin-home-page.php CHANGED
@@ -33,19 +33,21 @@
33
  </div>
34
  <?php endif; ?>
35
 
36
- <div class="siteorigin-panels-builder so-panels-loading">
37
 
38
  </div>
39
 
40
  <script type="text/javascript">
41
- // Create the panels_data input
42
- document.write( '<input name="panels_data" type="hidden" class="siteorigin-panels-data-field" id="panels-data-field-home" />' );
43
- document.getElementById('panels-data-field-home').value = decodeURIComponent("<?php echo rawurlencode( json_encode($panels_data) ); ?>");
 
 
44
  </script>
45
 
46
  <p><input type="submit" class="button button-primary" id="panels-save-home-page" value="<?php esc_attr_e('Save Home Page', 'siteorigin-panels') ?>" /></p>
47
-
48
  <?php wp_nonce_field('save', '_sopanels_home_nonce') ?>
49
  </form>
50
  <noscript><p><?php _e('This interface requires Javascript', 'siteorigin-panels') ?></p></noscript>
51
- </div>
33
  </div>
34
  <?php endif; ?>
35
 
36
+ <div class="siteorigin-panels-builder-container so-panels-loading">
37
 
38
  </div>
39
 
40
  <script type="text/javascript">
41
+ ( function( builderId, panelsData ){
42
+ // Create the panels_data input
43
+ document.write( '<input name="panels_data" type="hidden" class="siteorigin-panels-data-field" id="panels-data-field-' + builderId + '" />' );
44
+ document.getElementById( 'panels-data-field-' + builderId ).value = JSON.stringify( panelsData );
45
+ } )( "home-page", <?php echo json_encode( $panels_data ); ?> );
46
  </script>
47
 
48
  <p><input type="submit" class="button button-primary" id="panels-save-home-page" value="<?php esc_attr_e('Save Home Page', 'siteorigin-panels') ?>" /></p>
49
+ <input type="hidden" id="post_content" name="post_content"/>
50
  <?php wp_nonce_field('save', '_sopanels_home_nonce') ?>
51
  </form>
52
  <noscript><p><?php _e('This interface requires Javascript', 'siteorigin-panels') ?></p></noscript>
53
+ </div>
tpl/js-templates.php CHANGED
@@ -5,66 +5,70 @@ $layouts = apply_filters( 'siteorigin_panels_prebuilt_layouts', array() );
5
 
6
  <script type="text/template" id="siteorigin-panels-builder">
7
 
8
- <div class="so-builder-toolbar">
9
 
10
- <a href="#" class="so-tool-button so-widget-add">
11
- <span class="so-panels-icon so-panels-icon-plus"></span>
12
- <span class="so-button-text"><?php esc_attr_e('Add Widget', 'siteorigin-panels') ?></span>
13
- </a>
14
 
15
- <a href="#" class="so-tool-button so-row-add">
16
- <span class="so-panels-icon so-panels-icon-columns"></span>
17
- <span class="so-button-text"><?php esc_attr_e('Add Row', 'siteorigin-panels') ?></span>
18
- </a>
19
-
20
- <a href="#" class="so-tool-button so-prebuilt-add">
21
- <span class="so-panels-icon so-panels-icon-cubes"></span>
22
- <span class="so-button-text"><?php esc_attr_e('Prebuilt', 'siteorigin-panels') ?></span>
23
- </a>
24
-
25
- <?php if( !empty($post) ) : ?>
26
 
27
- <a href="#" class="so-tool-button so-history" style="display: none">
28
- <span class="so-panels-icon so-panels-icon-rotate-left"></span>
29
- <span class="so-button-text"><?php _e('History', 'siteorigin-panels') ?></span>
30
  </a>
31
 
32
- <a href="#" class="so-tool-button so-live-editor" style="display: none">
33
- <span class="so-panels-icon so-panels-icon-eye"></span>
34
- <span class="so-button-text"><?php _e('Live Editor', 'siteorigin-panels') ?></span>
35
  </a>
36
 
37
- <?php endif; ?>
38
 
39
- <a href="#" class="so-switch-to-standard"><?php _e('Switch to Editor', 'siteorigin-panels') ?></a>
 
 
 
40
 
41
- </div>
 
 
 
42
 
43
- <div class="so-rows-container">
44
 
45
- </div>
 
 
 
 
46
 
47
- <div class="so-panels-welcome-message">
48
- <div class="so-message-wrapper">
49
- <?php
50
- echo preg_replace(
51
- array(
52
- '/1\{ *(.*?) *\}/',
53
- '/2\{ *(.*?) *\}/',
54
- '/3\{ *(.*?) *\}/',
55
- '/4\{ *(.*?) *\}/',
56
- ),
57
- array(
58
- "<a href='#' class='so-tool-button so-widget-add'><span class='so-panels-icon so-panels-icon-plus'></span> $1</a>",
59
- "<a href='#' class='so-tool-button so-row-add'><span class='so-panels-icon so-panels-icon-columns'></span> $1</a>",
60
- "<a href='#' class='so-tool-button so-prebuilt-add'><span class='so-panels-icon so-panels-icon-cubes'></span> $1</a>",
61
- "<a href='https://siteorigin.com/page-builder/documentation/' target='_blank'>$1</a>"
62
- ),
63
- // TRANSLATORS: This message gives suggestions of next steps for the user x{...} is used to insert links
64
- __("Add a 1{widget}, 2{row} or 3{prebuilt layout} to get started. Read our 4{documentation} if you need help.", 'siteorigin-panels')
65
- );
66
- ?>
67
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  </div>
69
 
70
  </script>
@@ -76,13 +80,13 @@ $layouts = apply_filters( 'siteorigin_panels_prebuilt_layouts', array() );
76
  <span class="so-row-move so-tool-button"><span class="so-panels-icon so-panels-icon-arrows-v"></span></span>
77
 
78
  <span class="so-dropdown-wrapper">
79
- <a href="#" class="so-row-settings so-tool-button"><span class="so-panels-icon so-panels-icon-wrench"></span></a>
80
 
81
  <div class="so-dropdown-links-wrapper">
82
  <ul>
83
- <li><a href="#" class="so-row-settings"><?php _e('Edit Row', 'siteorigin-panels') ?></a></li>
84
- <li><a href="#" class="so-row-duplicate"><?php _e('Duplicate Row', 'siteorigin-panels') ?></a></li>
85
- <li><a href="#" class="so-row-delete so-needs-confirm" data-confirm="<?php esc_attr_e('Are you sure?', 'siteorigin-panels') ?>"><?php _e('Delete Row', 'siteorigin-panels') ?></a></li>
86
  <div class="so-pointer"></div>
87
  </ul>
88
  </div>
@@ -110,9 +114,9 @@ $layouts = apply_filters( 'siteorigin_panels_prebuilt_layouts', array() );
110
  <div class="title">
111
  <h4>{{%= title %}}</h4>
112
  <span class="actions">
113
- <a href="#" class="widget-edit"><?php _e('Edit', 'siteorigin-panels') ?></a>
114
- <a href="#" class="widget-duplicate"><?php _e('Duplicate', 'siteorigin-panels') ?></a>
115
- <a href="#" class="widget-delete"><?php _e('Delete', 'siteorigin-panels') ?></a>
116
  </span>
117
  </div>
118
  <small class="description">{{%= description %}}</small>
@@ -227,8 +231,8 @@ $layouts = apply_filters( 'siteorigin_panels_prebuilt_layouts', array() );
227
 
228
  <div class="buttons">
229
  <div class="action-buttons">
230
- <a href="#" class="so-delete"><?php _e('Delete', 'siteorigin-panels') ?></a>
231
- <a href="#" class="so-duplicate"><?php _e('Duplicate', 'siteorigin-panels') ?></a>
232
  </div>
233
 
234
  <input type="button" class="button-primary so-close" value="<?php esc_attr_e('Done', 'siteorigin-panels') ?>" />
@@ -318,8 +322,8 @@ $layouts = apply_filters( 'siteorigin_panels_prebuilt_layouts', array() );
318
  <div class="buttons">
319
  {{% if( dialogType == 'edit' ) { %}}
320
  <div class="action-buttons">
321
- <a href="#" class="so-delete"><?php _e('Delete', 'siteorigin-panels') ?></a>
322
- <a href="#" class="so-duplicate"><?php _e('Duplicate', 'siteorigin-panels') ?></a>
323
  </div>
324
  {{% } %}}
325
 
@@ -373,6 +377,17 @@ $layouts = apply_filters( 'siteorigin_panels_prebuilt_layouts', array() );
373
  </div>
374
 
375
  <div class="buttons">
 
 
 
 
 
 
 
 
 
 
 
376
  </div>
377
 
378
  </div>
@@ -389,7 +404,6 @@ $layouts = apply_filters( 'siteorigin_panels_prebuilt_layouts', array() );
389
  <div class="so-directory-items">
390
 
391
  <div class="so-directory-browse">
392
- <?php _e('Newest Layouts', 'siteorigin-panels') ?>
393
  </div>
394
 
395
  <div class="so-directory-items-wrapper">
@@ -399,19 +413,20 @@ $layouts = apply_filters( 'siteorigin_panels_prebuilt_layouts', array() );
399
  </div>
400
  {{% } else { %}}
401
  {{% _.each(items, function(item) { %}}
402
- <div class="so-directory-item">
403
  <div class="so-directory-item-wrapper">
404
- <div class="so-screenshot" data-src="http://s.wordpress.com/mshots/v1/{{% print( encodeURIComponent(item.preview) ) %}}?w=400">
405
- <a href="{{%- item.preview %}}" target="_blank" class="so-panels-loading"></a>
406
  </div>
407
  <div class="so-description">{{%- item.description %}}</div>
408
 
409
  <div class="so-bottom">
410
  <h4 class="so-title">{{%= item.title %}}</h4>
411
- <div class="so-buttons">
412
- <a href="{{%- item.preview %}}" class="button-secondary so-button-preview" target="_blank">Preview</a>
413
- <a href="#" class="button-primary so-button-use" data-layout-slug="{{%- item.slug %}}">Use</a>
414
- </div>
 
415
  </div>
416
  </div>
417
  </div>
@@ -422,8 +437,8 @@ $layouts = apply_filters( 'siteorigin_panels_prebuilt_layouts', array() );
422
  <div class="clear"></div>
423
 
424
  <div class="so-directory-pages">
425
- <a href="#" class="so-previous button-secondary" data-direction="prev"><?php _e('Previous', 'siteorigin-panels') ?></a>
426
- <a href="#" class="so-next button-secondary" data-direction="next"><?php _e('Next', 'siteorigin-panels') ?></a>
427
  </div>
428
  </div>
429
  </script>
@@ -440,6 +455,8 @@ $layouts = apply_filters( 'siteorigin_panels_prebuilt_layouts', array() );
440
  <input type="button" value="<?php esc_attr_e('Select Import File', 'siteorigin-panels'); ?>" class="file-browse-button button" />
441
  </p>
442
 
 
 
443
  <div class="progress-bar">
444
  <div class="progress-percent"></div>
445
  </div>
@@ -457,16 +474,6 @@ $layouts = apply_filters( 'siteorigin_panels_prebuilt_layouts', array() );
457
  </div>
458
  </script>
459
 
460
- <script type="text/template" id="siteorigin-panels-dialog-prebuilt-entry">
461
- <div class="layout">
462
- <div class="layout-inside">
463
- <div class="dashicons dashicons-migrate"></div>
464
- <h4>{{%= name %}}</h4>
465
- <div class="description">{{%= description %}}</div>
466
- </div>
467
- </div>
468
- </script>
469
-
470
  <script type="text/template" id="siteorigin-panels-dialog-history">
471
  <div class="dialog-data">
472
 
@@ -478,7 +485,7 @@ $layouts = apply_filters( 'siteorigin_panels_prebuilt_layouts', array() );
478
 
479
  <div class="content">
480
  <form method="post" action="<?php echo add_query_arg( 'siteorigin_panels_live_editor', 'true', get_the_permalink() ) ?>" target="siteorigin-panels-history-iframe-{{%= cid %}}" class="history-form">
481
- <input type="hidden" name="siteorigin_panels_data" value="">
482
  </form>
483
  <iframe class="siteorigin-panels-history-iframe" name="siteorigin-panels-history-iframe-{{%= cid %}}" src=""></iframe>
484
  </div>
@@ -498,47 +505,45 @@ $layouts = apply_filters( 'siteorigin_panels_prebuilt_layouts', array() );
498
  </script>
499
 
500
  <script type="text/template" id="siteorigin-panels-live-editor">
501
- <div class="so-panels-live-editor">
502
-
503
- <div class="so-overlay"></div>
504
 
505
- <form method="post" action="<?php echo add_query_arg( 'siteorigin_panels_live_editor', 'true', set_url_scheme( get_the_permalink() ) ) ?>" target="siteorigin-panels-live-editor-iframe" class="live-editor-form">
506
- <input type="hidden" name="siteorigin_panels_data" value="">
507
- </form>
508
-
509
- <div class="so-sidebar">
510
-
511
- <div class="so-sidebar-tools">
512
- <a href="#" class="live-editor-close" title="<?php esc_attr_e('Close Live Editor', 'siteorigin-panels') ?>"></a>
513
- </div>
514
 
515
- <div class="page-widgets">
 
516
 
517
- </div>
 
 
 
 
 
 
 
 
518
 
519
  </div>
520
 
521
- <div class="so-preview">
522
- <iframe id="siteorigin-panels-live-editor-iframe" name="siteorigin-panels-live-editor-iframe" src=""></iframe>
523
  </div>
524
 
525
- </div>
526
- </script>
527
 
528
- <script type="text/template" id="siteorigin-panels-live-editor-sidebar-section">
529
- <div class="page-widgets-section">
530
- <div class="section-header">
531
- <h4>{{%= title %}}</h4>
532
- </div>
533
- <div class="section-widgets">
534
  </div>
 
535
  </div>
536
  </script>
537
 
538
  <script type="text/template" id="siteorigin-panels-context-menu">
539
- <div class="so-panels-contextual-menu">
540
-
541
- </div>
542
  </script>
543
 
544
  <script type="text/template" id="siteorigin-panels-context-menu-section">
@@ -552,7 +557,7 @@ $layouts = apply_filters( 'siteorigin_panels_prebuilt_layouts', array() );
552
  {{% } %}}
553
  <ul class="so-items">
554
  {{% for( var k in items ) { %}}
555
- <li data-key="{{%- k %}}" class="so-item">{{%= items[k][settings.titleKey] %}}</li>
556
  {{% } %}}
557
  </ul>
558
  {{% if( settings.search ) { %}}
5
 
6
  <script type="text/template" id="siteorigin-panels-builder">
7
 
8
+ <div class="siteorigin-panels-builder">
9
 
10
+ <div class="so-builder-toolbar">
 
 
 
11
 
12
+ <a class="so-tool-button so-widget-add" title="<?php esc_attr_e( 'Add Widget', 'siteorigin-panels' ) ?>">
13
+ <span class="so-panels-icon so-panels-icon-plus"></span>
14
+ <span class="so-button-text"><?php esc_html_e('Add Widget', 'siteorigin-panels') ?></span>
15
+ </a>
 
 
 
 
 
 
 
16
 
17
+ <a class="so-tool-button so-row-add" title="<?php esc_attr_e( 'Add Row', 'siteorigin-panels' ) ?>">
18
+ <span class="so-panels-icon so-panels-icon-columns"></span>
19
+ <span class="so-button-text"><?php esc_html_e('Add Row', 'siteorigin-panels') ?></span>
20
  </a>
21
 
22
+ <a class="so-tool-button so-prebuilt-add" title="<?php esc_attr_e( 'Prebuilt Layouts', 'siteorigin-panels' ) ?>">
23
+ <span class="so-panels-icon so-panels-icon-cubes"></span>
24
+ <span class="so-button-text"><?php esc_html_e('Prebuilt', 'siteorigin-panels') ?></span>
25
  </a>
26
 
27
+ <?php if( !empty($post) ) : ?>
28
 
29
+ <a class="so-tool-button so-history" style="display: none" title="<?php esc_attr_e( 'Edit History', 'siteorigin-panels' ) ?>">
30
+ <span class="so-panels-icon so-panels-icon-rotate-left"></span>
31
+ <span class="so-button-text"><?php _e('History', 'siteorigin-panels') ?></span>
32
+ </a>
33
 
34
+ <a class="so-tool-button so-live-editor" style="display: none" title="<?php esc_html_e( 'Live Editor', 'siteorigin-panels' ) ?>">
35
+ <span class="so-panels-icon so-panels-icon-eye"></span>
36
+ <span class="so-button-text"><?php _e('Live Editor', 'siteorigin-panels') ?></span>
37
+ </a>
38
 
39
+ <?php endif; ?>
40
 
41
+ <a class="so-switch-to-standard"><?php _e('Revert to Editor', 'siteorigin-panels') ?></a>
42
+
43
+ </div>
44
+
45
+ <div class="so-rows-container">
46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  </div>
48
+
49
+ <div class="so-panels-welcome-message">
50
+ <div class="so-message-wrapper">
51
+ <?php
52
+ echo preg_replace(
53
+ array(
54
+ '/1\{ *(.*?) *\}/',
55
+ '/2\{ *(.*?) *\}/',
56
+ '/3\{ *(.*?) *\}/',
57
+ '/4\{ *(.*?) *\}/',
58
+ ),
59
+ array(
60
+ "<a href='#' class='so-tool-button so-widget-add'><span class='so-panels-icon so-panels-icon-plus'></span> $1</a>",
61
+ "<a href='#' class='so-tool-button so-row-add'><span class='so-panels-icon so-panels-icon-columns'></span> $1</a>",
62
+ "<a href='#' class='so-tool-button so-prebuilt-add'><span class='so-panels-icon so-panels-icon-cubes'></span> $1</a>",
63
+ "<a href='https://siteorigin.com/page-builder/documentation/' target='_blank'>$1</a>"
64
+ ),
65
+ // TRANSLATORS: This message gives suggestions of next steps for the user x{...} is used to insert links
66
+ __("Add a 1{widget}, 2{row} or 3{prebuilt layout} to get started. Read our 4{documentation} if you need help.", 'siteorigin-panels')
67
+ );
68
+ ?>
69
+ </div>
70
+ </div>
71
+
72
  </div>
73
 
74
  </script>
80
  <span class="so-row-move so-tool-button"><span class="so-panels-icon so-panels-icon-arrows-v"></span></span>
81
 
82
  <span class="so-dropdown-wrapper">
83
+ <a class="so-row-settings so-tool-button"><span class="so-panels-icon so-panels-icon-wrench"></span></a>
84
 
85
  <div class="so-dropdown-links-wrapper">
86
  <ul>
87
+ <li><a class="so-row-settings"><?php _e('Edit Row', 'siteorigin-panels') ?></a></li>
88
+ <li><a class="so-row-duplicate"><?php _e('Duplicate Row', 'siteorigin-panels') ?></a></li>
89
+ <li><a class="so-row-delete so-needs-confirm" data-confirm="<?php esc_attr_e('Are you sure?', 'siteorigin-panels') ?>"><?php _e('Delete Row', 'siteorigin-panels') ?></a></li>
90
  <div class="so-pointer"></div>
91
  </ul>
92
  </div>
114
  <div class="title">
115
  <h4>{{%= title %}}</h4>
116
  <span class="actions">
117
+ <a class="widget-edit"><?php _e('Edit', 'siteorigin-panels') ?></a>
118
+ <a class="widget-duplicate"><?php _e('Duplicate', 'siteorigin-panels') ?></a>
119
+ <a class="widget-delete"><?php _e('Delete', 'siteorigin-panels') ?></a>
120
  </span>
121
  </div>
122
  <small class="description">{{%= description %}}</small>
231
 
232
  <div class="buttons">
233
  <div class="action-buttons">
234
+ <a class="so-delete"><?php _e('Delete', 'siteorigin-panels') ?></a>
235
+ <a class="so-duplicate"><?php _e('Duplicate', 'siteorigin-panels') ?></a>
236
  </div>
237
 
238
  <input type="button" class="button-primary so-close" value="<?php esc_attr_e('Done', 'siteorigin-panels') ?>" />
322
  <div class="buttons">
323
  {{% if( dialogType == 'edit' ) { %}}
324
  <div class="action-buttons">
325
+ <a class="so-delete"><?php _e('Delete', 'siteorigin-panels') ?></a>
326
+ <a class="so-duplicate"><?php _e('Duplicate', 'siteorigin-panels') ?></a>
327
  </div>
328
  {{% } %}}
329
 
377
  </div>
378
 
379
  <div class="buttons">
380
+ <span class="so-dropdown-wrapper">
381
+ <input type="button" class="button-primary so-dropdown-button so-import-layout disabled" value="<?php esc_attr_e('Insert', 'siteorigin-panels') ?>" disabled="disabled"/>
382
+
383
+ <div class="so-dropdown-links-wrapper hidden">
384
+ <ul class="so-layout-position">
385
+ <li><a class="so-toolbar-button" data-value="after"><?php esc_html_e('Insert after', 'siteorigin-panels') ?></a></li>
386
+ <li><a class="so-toolbar-button" data-value="before"><?php esc_html_e('Insert before', 'siteorigin-panels') ?></a></li>
387
+ <li><a class="so-toolbar-button so-needs-confirm" data-value="replace" data-confirm="<?php esc_attr_e('Are you sure?', 'siteorigin-panels') ?>"><?php esc_html_e('Replace current', 'siteorigin-panels') ?></a></li>
388
+ </ul>
389
+ </div>
390
+ </span>
391
  </div>
392
 
393
  </div>
404
  <div class="so-directory-items">
405
 
406
  <div class="so-directory-browse">
 
407
  </div>
408
 
409
  <div class="so-directory-items-wrapper">
413
  </div>
414
  {{% } else { %}}
415
  {{% _.each(items, function(item) { %}}
416
+ <div class="so-directory-item" data-layout-id="{{%- item.id %}}" data-layout-type="{{%- item.type %}}">
417
  <div class="so-directory-item-wrapper">
418
+ <div class="so-screenshot" data-src="{{%- item.screenshot %}}">
419
+ <div class="so-panels-loading so-screenshot-wrapper"></div>
420
  </div>
421
  <div class="so-description">{{%- item.description %}}</div>
422
 
423
  <div class="so-bottom">
424
  <h4 class="so-title">{{%= item.title %}}</h4>
425
+ {{% if( item.preview ) { %}}
426
+ <div class="so-buttons">
427
+ <a href="{{%- item.preview %}}" class="button-secondary so-button-preview" target="_blank">Preview</a>
428
+ </div>
429
+ {{% } %}}
430
  </div>
431
  </div>
432
  </div>
437
  <div class="clear"></div>
438
 
439
  <div class="so-directory-pages">
440
+ <a class="so-previous button-secondary" data-direction="prev"><?php _e('Previous', 'siteorigin-panels') ?></a>
441
+ <a class="so-next button-secondary" data-direction="next"><?php _e('Next', 'siteorigin-panels') ?></a>
442
  </div>
443
  </div>
444
  </script>
455
  <input type="button" value="<?php esc_attr_e('Select Import File', 'siteorigin-panels'); ?>" class="file-browse-button button" />
456
  </p>
457
 
458
+ <p class="drag-drop-message js-so-selected-file"></p>
459
+
460
  <div class="progress-bar">
461
  <div class="progress-percent"></div>
462
  </div>
474
  </div>
475
  </script>
476
 
 
 
 
 
 
 
 
 
 
 
477
  <script type="text/template" id="siteorigin-panels-dialog-history">
478
  <div class="dialog-data">
479
 
485
 
486
  <div class="content">
487
  <form method="post" action="<?php echo add_query_arg( 'siteorigin_panels_live_editor', 'true', get_the_permalink() ) ?>" target="siteorigin-panels-history-iframe-{{%= cid %}}" class="history-form">
488
+ <input type="hidden" name="live_editor_panels_data" value="">
489
  </form>
490
  <iframe class="siteorigin-panels-history-iframe" name="siteorigin-panels-history-iframe-{{%= cid %}}" src=""></iframe>
491
  </div>
505
  </script>
506
 
507
  <script type="text/template" id="siteorigin-panels-live-editor">
508
+ <div class="so-panels-live-editor" data-preview-url="<?php echo add_query_arg( 'siteorigin_panels_live_editor', 'true', set_url_scheme( get_permalink() ) ) ?>">
 
 
509
 
510
+ <div class="live-editor-collapse">
511
+ <div class="collapse-icon"></div>
512
+ <span data-collapse="<?php esc_attr_e( 'Collapse', 'siteorigin-panels' ) ?>" data-expand="<?php esc_attr_e( 'Expand', 'siteorigin-panels' ) ?>">
513
+ <?php _e( 'Collapse', 'siteorigin-panels' ) ?>
514
+ </span>
515
+ </div>
 
 
 
516
 
517
+ <div class="so-sidebar-tools">
518
+ <button class="live-editor-close button-primary"><?php esc_html_e('Done', 'siteorigin-panels') ?></button>
519
 
520
+ <a class="live-editor-mode live-editor-desktop so-active" title="<?php esc_attr_e( 'Toggle desktop mode', 'siteorigin-panels' ) ?>" data-mode="desktop">
521
+ <span class="dashicons dashicons-desktop"></span>
522
+ </a>
523
+ <a class="live-editor-mode live-editor-tablet" title="<?php esc_attr_e( 'Toggle tablet mode', 'siteorigin-panels' ) ?>" data-mode="tablet">
524
+ <span class="dashicons dashicons-tablet"></span>
525
+ </a>
526
+ <a class="live-editor-mode live-editor-mobile" title="<?php esc_attr_e( 'Toggle mobile mode', 'siteorigin-panels' ) ?>" data-mode="mobile">
527
+ <span class="dashicons dashicons-smartphone"></span>
528
+ </a>
529
 
530
  </div>
531
 
532
+ <div class="so-sidebar">
533
+ <div class="so-live-editor-builder"></div>
534
  </div>
535
 
536
+ <div class="so-preview"></div>
 
537
 
538
+ <div class="so-preview-overlay">
539
+ <div class="so-loading-container"><div class="so-loading-bar"></div></div>
 
 
 
 
540
  </div>
541
+
542
  </div>
543
  </script>
544
 
545
  <script type="text/template" id="siteorigin-panels-context-menu">
546
+ <div class="so-panels-contextual-menu"></div>
 
 
547
  </script>
548
 
549
  <script type="text/template" id="siteorigin-panels-context-menu-section">
557
  {{% } %}}
558
  <ul class="so-items">
559
  {{% for( var k in items ) { %}}
560
+ <li data-key="{{%- k %}}" class="so-item {{% if( !_.isUndefined( items[k].confirm ) && items[k].confirm ) { print( 'so-confirm' ); } %}}">{{%= items[k][settings.titleKey] %}}</li>
561
  {{% } %}}
562
  </ul>
563
  {{% if( settings.search ) { %}}
tpl/metabox-panels.php CHANGED
@@ -2,16 +2,17 @@
2
  $builder_id = uniqid();
3
  ?>
4
 
5
- <div id="siteorigin-panels-metabox" class="siteorigin-panels-builder">
6
  <?php do_action('siteorigin_panels_before_interface') ?>
7
  <?php wp_nonce_field('save', '_sopanels_nonce') ?>
8
 
9
  <script type="text/javascript">
10
- // Create the panels_data input
11
- var builderId = "<?php echo esc_attr($builder_id) ?>";
12
- document.write( '<input name="panels_data" type="hidden" class="siteorigin-panels-data-field" id="panels-data-field-' + builderId + '" />' );
13
- document.getElementById('panels-data-field-<?php echo esc_attr($builder_id) ?>').value = decodeURIComponent("<?php echo rawurlencode( json_encode($panels_data) ); ?>");
 
14
  </script>
15
 
16
  <?php do_action('siteorigin_panels_metabox_end'); ?>
17
- </div>
2
  $builder_id = uniqid();
3
  ?>
4
 
5
+ <div id="siteorigin-panels-metabox">
6
  <?php do_action('siteorigin_panels_before_interface') ?>
7
  <?php wp_nonce_field('save', '_sopanels_nonce') ?>
8
 
9
  <script type="text/javascript">
10
+ ( function( builderId, panelsData ){
11
+ // Create the panels_data input
12
+ document.write( '<input name="panels_data" type="hidden" class="siteorigin-panels-data-field" id="panels-data-field-' + builderId + '" />' );
13
+ document.getElementById('panels-data-field-<?php echo esc_attr($builder_id) ?>').value = JSON.stringify( panelsData );
14
+ } )( "<?php echo esc_attr($builder_id) ?>", <?php echo json_encode( $panels_data ); ?> );
15
  </script>
16
 
17
  <?php do_action('siteorigin_panels_metabox_end'); ?>
18
+ </div>
widgets/basic.php CHANGED
@@ -36,6 +36,9 @@ class SiteOrigin_Panels_Widgets_Layout extends WP_Widget {
36
 
37
  function update($new, $old) {
38
  $new['builder_id'] = uniqid();
 
 
 
39
  return $new;
40
  }
41
 
@@ -48,14 +51,22 @@ class SiteOrigin_Panels_Widgets_Layout extends WP_Widget {
48
  if( !is_string( $instance['panels_data'] ) ) $instance['panels_data'] = json_encode( $instance['panels_data'] );
49
 
50
  ?>
51
- <div class="siteorigin-page-builder-widget siteorigin-panels-builder" id="siteorigin-page-builder-widget-<?php echo esc_attr( $instance['builder_id'] ) ?>" data-builder-id="<?php echo esc_attr( $instance['builder_id'] ) ?>" data-type="layout_widget">
52
  <p>
53
  <a href="#" class="button-secondary siteorigin-panels-display-builder" ><?php _e('Open Builder', 'siteorigin-panels') ?></a>
54
  </p>
55
 
56
  <input type="hidden" data-panels-filter="json_parse" value="" class="panels-data" name="<?php echo $this->get_field_name('panels_data') ?>" id="<?php echo $this->get_field_id('panels_data') ?>" />
 
 
 
 
 
 
 
 
57
  <script type="text/javascript">
58
- document.getElementById('<?php echo $this->get_field_id('panels_data') ?>').value = decodeURIComponent("<?php echo rawurlencode( $instance['panels_data'] ); ?>");
59
  </script>
60
 
61
  <input type="hidden" value="<?php echo esc_attr( $instance['builder_id'] ) ?>" name="<?php echo $this->get_field_name('builder_id') ?>" />
36
 
37
  function update($new, $old) {
38
  $new['builder_id'] = uniqid();
39
+ if ( ! empty( $new['panels_data'] ) && ! empty( $new['panels_data']['widgets'] ) ) {
40
+ $new['panels_data']['widgets'] = siteorigin_panels_process_raw_widgets( $new['panels_data']['widgets'] );
41
+ }
42
  return $new;
43
  }
44
 
51
  if( !is_string( $instance['panels_data'] ) ) $instance['panels_data'] = json_encode( $instance['panels_data'] );
52
 
53
  ?>
54
+ <div class="siteorigin-page-builder-widget" id="siteorigin-page-builder-widget-<?php echo esc_attr( $instance['builder_id'] ) ?>" data-builder-id="<?php echo esc_attr( $instance['builder_id'] ) ?>" data-type="layout_widget">
55
  <p>
56
  <a href="#" class="button-secondary siteorigin-panels-display-builder" ><?php _e('Open Builder', 'siteorigin-panels') ?></a>
57
  </p>
58
 
59
  <input type="hidden" data-panels-filter="json_parse" value="" class="panels-data" name="<?php echo $this->get_field_name('panels_data') ?>" id="<?php echo $this->get_field_id('panels_data') ?>" />
60
+
61
+ <script type="text/javascript">
62
+ ( function( panelsData ){
63
+ // Create the panels_data input
64
+ document.getElementById('<?php echo $this->get_field_id('panels_data') ?>').value = JSON.stringify( panelsData );
65
+ } )( <?php echo $instance['panels_data']; ?> );
66
+ </script>
67
+
68
  <script type="text/javascript">
69
+ // document.getElementById('<?php echo $this->get_field_id('panels_data') ?>').value = decodeURIComponent("<?php echo rawurlencode( $instance['panels_data'] ); ?>");
70
  </script>
71
 
72
  <input type="hidden" value="<?php echo esc_attr( $instance['builder_id'] ) ?>" name="<?php echo $this->get_field_name('builder_id') ?>" />
widgets/migration.php CHANGED
@@ -26,7 +26,7 @@ function siteorigin_panels_legacy_widget_migration($panels_data){
26
  'text' => $shortcode,
27
  'panels_info' => $widget['panels_info']
28
  );
29
- $widget['panels_info']['class'] = 'WP_Widget_Black_Studio_TinyMCE';
30
 
31
  break;
32
 
@@ -49,7 +49,7 @@ function siteorigin_panels_legacy_widget_migration($panels_data){
49
  'panels_info' => $widget['panels_info']
50
  );
51
 
52
- $widget['panels_info']['class'] = 'WP_Widget_Black_Studio_TinyMCE';
53
  }
54
 
55
  break;
26
  'text' => $shortcode,
27
  'panels_info' => $widget['panels_info']
28
  );
29
+ $widget['panels_info']['class'] = 'SiteOrigin_Widget_Editor_Widget';
30
 
31
  break;
32
 
49
  'panels_info' => $widget['panels_info']
50
  );
51
 
52
+ $widget['panels_info']['class'] = 'SiteOrigin_Widget_Editor_Widget';
53
  }
54
 
55
  break;